/*++ Copyright (c) 1996 Microsoft Corporation Module Name : comobj.cxx Abstract: This module defines DCOM Admin APIs. Author: Sophia Chung (sophiac) 23-Nov-1996 --*/ extern "C" { #include #include #include } #include #include #include #include #include #include #include #include #include #include #include #include #include // // Globals // DECLARE_DEBUG_PRINTS_OBJECT(); ULONG g_dwRefCount = 0; COpenHandle g_ohMasterRootHandle; HANDLE_TABLE g_MasterRoot = { NULL, 0, METADATA_MASTER_ROOT_HANDLE, ALL_HANDLE, &g_ohMasterRootHandle }; // // Private prototypes // #define MAX_SINK_CALLS_TOBE_REMOVED 10 // // Used by RestoreHelper // #define RESTORE_HISTORY 0x1 #define RESTORE_BACKUP 0x2 BOOL MakeParentPath( LPWSTR pszPath ); BOOL IsValidNsepmPath( LPCWSTR pszMDPath ); //------------------------------ CADMCOMW::CADMCOMW(): m_ImpIConnectionPointContainer(), m_pMdObject(NULL), m_dwRefCount(1), m_dwHandleValue(1), m_pEventSink(NULL), m_pConnPoint(NULL), m_bSinkConnected(FALSE), m_bCallSinks(TRUE), m_piuFTM(NULL), m_pNseObject(NULL), m_bTerminated(FALSE), m_bIsTerminateRoutineComplete(FALSE) { HRESULT hRes; UINT i; memset((PVOID)m_hashtab, 0, sizeof(m_hashtab) ); // Null all entries in the connection point array. for (i=0; iComMDInitialize(); if (FAILED(hRes)) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::CADMCOMW] ComMDInitialize(MDCOM) failed, error %lx\n", hRes )); m_pMdObject->Release(); m_pMdObject = NULL; } } if (SUCCEEDED(hRes)) { if ( IISGetPlatformType() != PtWindows95 ) { hRes = CoCreateInstance(CLSID_NSEPMCOM, NULL, CLSCTX_INPROC_SERVER, IID_NSECOM, (void**) &m_pNseObject); if (FAILED(hRes)) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOM::CADMCOM] CoCreateInstance(NSEPMCOM) failed, error %lx\n", GetLastError() )); } else { hRes = m_pNseObject->ComMDInitialize(); if (FAILED(hRes)) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOM::CADMCOM] ComMDInitialize(NSEPMCOM) failed, error %lx\n", hRes )); m_pNseObject->Release(); m_pNseObject = NULL; } } } m_pEventSink = new CImpIMDCOMSINKW((IMSAdminBaseW*)this); if( m_pEventSink == NULL ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::CADMCOMW] CImpIMDCOMSINKW failed, error %lx\n", ERROR_NOT_ENOUGH_MEMORY )); hRes = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY); } else { m_pEventSink->AddRef(); COConnectionPoint* pCOConnPt; m_ImpIConnectionPointContainer.Init(this); // Rig this COPaper COM object to be connectable. Assign the connection // point array. This object's connection points are determined at // compile time--it currently has only one connection point: // the CONNPOINT_PAPERSINK connection point. Create a connection // point object for this and assign it into the array. This array could // easily grow to support additional connection points in the future. // First try creating a new connection point object. Pass 'this' as the // pHostObj pointer used by the connection point to pass its AddRef and // Release calls back to the host connectable object. pCOConnPt = new COConnectionPoint((IUnknown*)this); if (NULL != pCOConnPt) { // If creation succeeded then initialize it (including creating // its initial dynamic connection array). hRes = pCOConnPt->Init(IID_IMSAdminBaseSink_W); // If the init succeeded then use QueryInterface to obtain the // IConnectionPoint interface on the new connection point object. // The interface pointer is assigned directly into the // connection point array. The QI also does the needed AddRef. if (SUCCEEDED(hRes)) { hRes = pCOConnPt->QueryInterface(IID_IConnectionPoint, (PPVOID)&m_aConnectionPoints[ADM_CONNPOINT_WRITESINK]); } if (FAILED(hRes)) { delete (pCOConnPt); } } if (SUCCEEDED(hRes)) { // // Admin's sink // IConnectionPointContainer* pConnPointContainer = NULL; // First query the object for its Connection Point Container. This // essentially asks the object in the server if it is connectable. hRes = m_pMdObject->QueryInterface( IID_IConnectionPointContainer, (PVOID *)&pConnPointContainer); if SUCCEEDED(hRes) { // Find the requested Connection Point. This AddRef's the // returned pointer. hRes = pConnPointContainer->FindConnectionPoint(IID_IMDCOMSINK_W, &m_pConnPoint); if (SUCCEEDED(hRes)) { hRes = m_pConnPoint->Advise((IUnknown *)m_pEventSink, &m_dwCookie); if (SUCCEEDED(hRes)) { m_bSinkConnected = TRUE; } } RELEASE_INTERFACE(pConnPointContainer); if (SUCCEEDED(hRes)) { hRes = CoCreateFreeThreadedMarshaler((IUnknown *)this, &m_piuFTM); } } } } } SetStatus(hRes); // // Insert our object into the global list only if it is valid. // if( SUCCEEDED(hRes) ) { AddObjectToList(); } } CADMCOMW::~CADMCOMW() { Terminate(); } VOID CADMCOMW::Terminate() { HANDLE_TABLE *node; HANDLE_TABLE *nextnode; DWORD i; // // Terminate must only be called from two locations. And they // should synchronize correctly. // // 1. From ~CADMCOMW. Obviously this should only be called once. // // 2. From ForceTerminate. That routine should only be called in // shutdown. With a reference held on this object. So the final // release should call the dtor and this routine should noop. // if( !m_bTerminated ) { m_bTerminated = TRUE; if (m_bSinkConnected) { m_pConnPoint->Unadvise(m_dwCookie); m_rSinkResource.Lock(TSRES_LOCK_WRITE); m_bCallSinks = FALSE; m_rSinkResource.Unlock(); } // // Tell ADMWPROX.DLL to release this object's associated security // context. // ReleaseObjectSecurityContextW( ( IUnknown* )this ); // // Do final release of the connection point objects. // If this isn't the final release, then the client has an outstanding // unbalanced reference to a connection point and a memory leak may // likely result because the host COPaper object is now going away yet // a connection point for this host object will not end up deleting // itself (and its connections array). // for (i=0; ihAdminHandle != INVALID_ADMINHANDLE_VALUE ) { AdminAclNotifyClose( (LPVOID)this, node->hAdminHandle ); if( node->HandleType == NSEPM_HANDLE ) { // // call nse com api // m_pNseObject->ComMDCloseMetaObject( node->hActualHandle ); } else { // // call metadata com api // m_pMdObject->ComMDCloseMetaObject( node->hActualHandle ); } } nextnode = node->next; delete node->pohHandle; LocalFree(node); } m_hashtab[i] = NULL; } // // Issue TaylorW 3/20/2001 // QFE tree contains this call: // // AdminAclNotifyClose( (LPVOID)this, METADATA_MASTER_ROOT_HANDLE ); // // I have no idea when this may have entered their tree or been lost // from ours. I don't see any record in source depot of it being // removed or added. Need to investigate why it would be needed. // m_rHandleResource.Unlock(); } if ( m_pEventSink != NULL ) { m_pEventSink->Release(); m_pEventSink = NULL; } if ( m_pMdObject != NULL ) { m_pMdObject->ComMDTerminate(TRUE); m_pMdObject->Release(); m_pMdObject = NULL; } if ( m_piuFTM != NULL ) { m_piuFTM->Release(); m_piuFTM = NULL; } if ( m_pNseObject != NULL ) { m_pNseObject->ComMDTerminate(TRUE); m_pNseObject->Release(); m_pNseObject = NULL; } m_bIsTerminateRoutineComplete = TRUE; } DBG_ASSERT( m_bIsTerminateRoutineComplete ); } VOID CADMCOMW::ForceTerminate() { DBG_ASSERT( !m_bIsTerminateRoutineComplete ); DBG_ASSERT( !m_bTerminated ); // // Wait on the reference count of this object. But bound // the wait so a leaked in process object does not prevent // us from shutting down the service. // // Wait on a ref count of 1, because the caller better be // holding our last reference. This assumes all external // references are killed through CoDisconnect() and all // internal references are released because of dependent // services shutting down. // // Issue TaylorW 3/20/2001 // // In iis 5.1 the web service will shutdown filters after // it has already reported that it is done shutting down. // This is bad, but changing the shutdown logic of the // web service is not worth doing at this time. Hopefully // the shutdown timeout will be sufficient to allow this // operation to complete. // // Windows Bugs 318006 // const INT MAX_WAIT_TRIES = 5; INT WaitTries; for( WaitTries = 0; m_dwRefCount > 1 && WaitTries < MAX_WAIT_TRIES; WaitTries++ ) { Sleep( 1000 ); } // // If we timed out. Something is wrong. Most likely someone in // process has leaked this object. These asserts are actually // overactive unless ref tracing is enabled on this object. // // // Issue TaylorW 4/9/2001 // // It looks like front page leaks a base object from in process. // So these assertions need to be turned off. // #define DEBUG_BASE_OBJ_LEAK 0x80000000L IF_DEBUG( BASE_OBJ_LEAK ) { DBG_ASSERT( m_dwRefCount == 1 ); DBG_ASSERT( WaitTries < MAX_WAIT_TRIES ); } // // Go ahead and try to clean up. // Terminate(); } HRESULT CADMCOMW::QueryInterface( REFIID riid, void **ppObject) { if (riid==IID_IUnknown || riid==IID_IMSAdminBase_W) { *ppObject = (IMSAdminBase *) this; AddRef(); } else if (IID_IMSAdminBase2_W == riid) { *ppObject = (IMSAdminBase2 *) this; AddRef(); } else if (IID_IConnectionPointContainer == riid) { *ppObject = &m_ImpIConnectionPointContainer; AddRef(); } else if (IID_IMarshal == riid) { return m_piuFTM->QueryInterface(riid, ppObject); } else { return E_NOINTERFACE; } return S_OK; } ULONG CADMCOMW::AddRef( ) { DWORD dwRefCount; dwRefCount = InterlockedIncrement((long *)&m_dwRefCount); #if DBG if( sm_pDbgRefTraceLog ) { WriteRefTraceLog( sm_pDbgRefTraceLog, dwRefCount, this ); } #endif return dwRefCount; } ULONG CADMCOMW::Release( ) { DWORD dwRefCount; dwRefCount = InterlockedDecrement((long *)&m_dwRefCount); #if DBG if( sm_pDbgRefTraceLog ) { WriteRefTraceLog( sm_pDbgRefTraceLog, -(LONG)dwRefCount, this ); } #endif if( dwRefCount == 1 ) { // // We keep a list of objects around so that we can clean up and // shutdown successfully. The list holds a reference to this object // when we hit a reference of 1, we know it is time to remove // ourselves from the list. If we are in shutdown we may already // have been removed from the list. But normally, this call to // RemoveObjectFromList removes our last reference and thus sends // us back through Release and ultimately to our destructor. // RemoveObjectFromList(); } else if( dwRefCount == 0 ) { delete this; } return dwRefCount; } HRESULT CADMCOMW::AddKey( IN METADATA_HANDLE hMDHandle, IN LPCWSTR pszMDPath ) /*++ Routine Description: Add meta object and adds it to the list of child objects for the object specified by Path. Arguments: hMDHandle - open handle pszMDPath - path of the object to be added Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; hresReturn = AddKeyHelper(hMDHandle, pszMDPath); return hresReturn; } HRESULT CADMCOMW::DeleteKey( IN METADATA_HANDLE hMDHandle, IN LPCWSTR pszMDPath ) /*++ Routine Description: Deletes a meta object and all of its data. Arguments: hMDHandle - open handle pszMDPath - path of object to be deleted, relative to the path of Handle. Must not be NULL. Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (pszMDPath == NULL) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, AAC_DELETEKEY, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDDeleteMetaObjectW( hActualHandle, pszMDPath ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDDeleteMetaObjectW( hActualHandle, pszMDPath ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::DeleteChildKeys( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath ) /*++ Routine Description: Deletes all child meta objects of the specified object, with all of their data. Arguments: hMDHandle - open handle pszMDPath - path of the parent of the objects to be deleted, relative to the path of Handle. Return Value: Status. --*/ { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDDeleteChildMetaObjectsW( hActualHandle, pszMDPath ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDDeleteChildMetaObjectsW( hActualHandle, pszMDPath ); } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::EnumKeys( /* [in] */ METADATA_HANDLE hMDHandle, /* [size_is][in] */ LPCWSTR pszMDPath, /* [size_is][out] */ LPWSTR pszMDName, /* [in] */ DWORD dwMDEnumObjectIndex ) /*++ Routine Description: Enumerate objects in path. Arguments: hMDHandle - open handle pszMDPath - path of parent object, relative to the path of Handle eg. "Root Object/Child/GrandChild" pszMDName - buffer where the Name of the object is returned dwEnumObjectIndex - index of the value to be retrieved Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (pszMDName == NULL) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, AAC_ENUM_KEYS, METADATA_PERMISSION_READ); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDEnumMetaObjectsW( hActualHandle, pszMDPath, pszMDName, dwMDEnumObjectIndex ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDEnumMetaObjectsW( hActualHandle, pszMDPath, pszMDName, dwMDEnumObjectIndex ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::CopyKey( /* [in] */ METADATA_HANDLE hMDSourceHandle, /* [string][in][unique] */ LPCWSTR pszMDSourcePath, /* [in] */ METADATA_HANDLE hMDDestHandle, /* [string][in][unique] */ LPCWSTR pszMDDestPath, /* [in] */ BOOL bMDOverwriteFlag, /* [in] */ BOOL bMDCopyFlag ) /*++ Routine Description: Copy or move source meta object and its data and descendants to Dest. Arguments: hMDSourceHandle - open handle pszMDSourcePath - path of the object to be copied hMDDestHandle - handle of the new location for the object pszMDDestPath - path of the new location for the object, relative to the path of hMDDestHandle bMDOverwriteFlag - determine the behavior if a meta object with the same name as source is already a child of pszMDDestPath. bMDCopyFlag - determine whether Source is deleted from its original location Return Value: Status --*/ { METADATA_HANDLE hSActualHandle; HANDLE_TYPE SHandleType; METADATA_HANDLE hDActualHandle; HANDLE_TYPE DHandleType; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; // // lookup and access check source // if (bMDCopyFlag) { hresReturn = LookupAndAccessCheck(hMDSourceHandle, &hSActualHandle, &SHandleType, pszMDSourcePath, 0, METADATA_PERMISSION_READ); } else { // // Deleting source path, so need delete permission // hresReturn = LookupAndAccessCheck(hMDSourceHandle, &hSActualHandle, &SHandleType, pszMDSourcePath, AAC_DELETEKEY, METADATA_PERMISSION_WRITE); } if (SUCCEEDED(hresReturn)) { // // lookup and access check dest // hresReturn = LookupAndAccessCheck(hMDDestHandle, &hDActualHandle, &DHandleType, pszMDDestPath, AAC_COPYKEY, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if( SHandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDCopyMetaObjectW( hSActualHandle, pszMDSourcePath, hDActualHandle, pszMDDestPath, bMDOverwriteFlag, bMDCopyFlag ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDCopyMetaObjectW( hSActualHandle, pszMDSourcePath, hDActualHandle, pszMDDestPath, bMDOverwriteFlag, bMDCopyFlag ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::RenameKey( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [string][in][unique] */ LPCWSTR pszMDNewName) { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ((LPSTR)pszMDNewName == NULL) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDRenameMetaObjectW(hActualHandle, pszMDPath, pszMDNewName ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDRenameMetaObjectW(hActualHandle, pszMDPath, pszMDNewName ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::SetData( /* [in] */ METADATA_HANDLE hMDHandle, /* [size_is][in] */ LPCWSTR pszMDPath, /* [in] */ PMETADATA_RECORD pmdrMDData ) /*++ Routine Description: Set a data object. Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data to set Return Value: Status. --*/ { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, pmdrMDData->dwMDIdentifier, METADATA_PERMISSION_WRITE ); if (SUCCEEDED(hresReturn)) { if ( !AdminAclNotifySetOrDeleteProp( hMDHandle, pmdrMDData->dwMDIdentifier ) ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::SetData] AdminAclNotifySetOrDel failed, error %lx\n", GetLastError() )); hresReturn = RETURNCODETOHRESULT( GetLastError() ); } else { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDSetMetaDataW( hActualHandle, pszMDPath, pmdrMDData ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDSetMetaDataW( hActualHandle, pszMDPath, pmdrMDData ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::GetData( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in] */ LPCWSTR pszMDPath, /* [out][in] */ PMETADATA_RECORD pmdrMDData, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen ) /*++ Routine Description: Get one metadata value Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data structure pdwMDRequiredDataLen - updated with required length Return Value: Status. --*/ { BOOL fEnableSecureAccess; BOOL fRequestedInheritedStatus; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ((pmdrMDData == NULL) || ((pmdrMDData->dwMDDataLen != 0) && (pmdrMDData->pbMDData == NULL)) || !CheckGetAttributes(pmdrMDData->dwMDAttributes) || (pmdrMDData->dwMDDataType >= INVALID_END_METADATA)) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, pmdrMDData->dwMDIdentifier, METADATA_PERMISSION_READ, &fEnableSecureAccess ); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDGetMetaDataW( hActualHandle, pszMDPath, pmdrMDData, pdwMDRequiredDataLen ); } else { DWORD RetCode; fRequestedInheritedStatus = pmdrMDData->dwMDAttributes & METADATA_ISINHERITED; pmdrMDData->dwMDAttributes |= METADATA_ISINHERITED; // // call metadata com api // hresReturn = m_pMdObject->ComMDGetMetaDataW( hActualHandle, pszMDPath, pmdrMDData, pdwMDRequiredDataLen ); // // if metadata is secure, check if can access this property from // where it is defined, i.e using the ACL visible at the definition // point in tree. // if ( SUCCEEDED( hresReturn ) && (pmdrMDData->dwMDAttributes & METADATA_SECURE) && (RetCode = IsReadAccessGranted( hMDHandle, (LPWSTR)pszMDPath, pmdrMDData )) != ERROR_SUCCESS ) { hresReturn = RETURNCODETOHRESULT( RetCode ); } if ( !fRequestedInheritedStatus ) { pmdrMDData->dwMDAttributes &= ~METADATA_ISINHERITED; } } // // if metadata secure, check access allowed to secure properties // if ( SUCCEEDED( hresReturn ) && (pmdrMDData->dwMDAttributes & METADATA_SECURE) && !fEnableSecureAccess) { *pdwMDRequiredDataLen = 0; pmdrMDData->dwMDDataLen = 0; hresReturn = RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::DeleteData( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in] */ LPCWSTR pszMDPath, /* [in] */ DWORD dwMDIdentifier, /* [in] */ DWORD dwMDDataType ) /*++ Routine Description: Deletes a data object. Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated dwMDIdentifier - identifier of the data to remove dwMDDataType - optional type of the data to remove Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (dwMDDataType >= INVALID_END_METADATA) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, dwMDIdentifier, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if ( !AdminAclNotifySetOrDeleteProp( hMDHandle, dwMDIdentifier ) ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::DeleteData] AdminAclNotifySetOrDel failed, error %lx\n", GetLastError() )); hresReturn = RETURNCODETOHRESULT( GetLastError() ); } else { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDDeleteMetaDataW( hActualHandle, pszMDPath, dwMDIdentifier, dwMDDataType ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDDeleteMetaDataW( hActualHandle, pszMDPath, dwMDIdentifier, dwMDDataType ); } } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::EnumData( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in] */ LPCWSTR pszMDPath, /* [out][in] */ PMETADATA_RECORD pmdrMDData, /* [in] */ DWORD dwMDEnumDataIndex, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredDataLen ) /*++ Routine Description: Enumerate properties of object. Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pmdrMDData - data structure pdwMDRequiredDataLen - updated with required length Return Value: Status. --*/ { BOOL fSecure; BOOL fRequestedInheritedStatus; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ((pmdrMDData == NULL) || ((pmdrMDData->dwMDDataLen != 0) && (pmdrMDData->pbMDData == NULL)) || !CheckGetAttributes(pmdrMDData->dwMDAttributes) || (pmdrMDData->dwMDDataType >= INVALID_END_METADATA)) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_READ, &fSecure); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDEnumMetaDataW( hActualHandle, pszMDPath, pmdrMDData, dwMDEnumDataIndex, pdwMDRequiredDataLen ); if ( !fSecure && SUCCEEDED(hresReturn) ) { hresReturn = RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ); memset( pmdrMDData->pbMDData, 0x0, pmdrMDData->dwMDDataLen ); } } else { fRequestedInheritedStatus = pmdrMDData->dwMDAttributes & METADATA_ISINHERITED; pmdrMDData->dwMDAttributes |= METADATA_ISINHERITED; // // call metadata com api // hresReturn = m_pMdObject->ComMDEnumMetaDataW( hActualHandle, pszMDPath, pmdrMDData, dwMDEnumDataIndex, pdwMDRequiredDataLen ); // // if metadata is secure, check if can access this property from // where it is defined, i.e using the ACL visible at the definition // point in tree. // DWORD RetCode; if ( SUCCEEDED( hresReturn ) && (pmdrMDData->dwMDAttributes & METADATA_SECURE) && (RetCode = IsReadAccessGranted( hMDHandle, (LPWSTR)pszMDPath, pmdrMDData )) != ERROR_SUCCESS ) { hresReturn = RETURNCODETOHRESULT( RetCode ); if ( !pmdrMDData->dwMDDataTag ) { memset( pmdrMDData->pbMDData, 0x0, pmdrMDData->dwMDDataLen ); } } if ( !fRequestedInheritedStatus ) { pmdrMDData->dwMDAttributes &= ~METADATA_ISINHERITED; } if ( !fSecure && SUCCEEDED(hresReturn) ) { if ( pmdrMDData->dwMDAttributes & METADATA_SECURE ) { hresReturn = RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ); if ( !pmdrMDData->dwMDDataTag ) { memset( pmdrMDData->pbMDData, 0x0, pmdrMDData->dwMDDataLen ); } } } } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::GetAllData( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in] */ LPCWSTR pszMDPath, /* [in] */ DWORD dwMDAttributes, /* [in] */ DWORD dwMDUserType, /* [in] */ DWORD dwMDDataType, /* [out] */ DWORD __RPC_FAR *pdwMDNumDataEntries, /* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber, /* [in] */ DWORD dwMDBufferSize, /* [size_is][out] */ unsigned char __RPC_FAR *pbMDBuffer, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize ) /*++ Routine Description: Gets all data associated with a Meta Object Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated dwMDAttributes - flags for the data dwMDUserType - user Type for the data dwMDDataType - type of the data pdwMDNumDataEntries - number of entries copied to Buffer pdwMDDataSetNumber - number associated with this data set dwMDBufferSize - size in bytes of buffer pbMDBuffer - buffer to store the data pdwMDRequiredBufferSize - updated with required length of buffer Return Value: Status. --*/ { BOOL fSecure; BOOL fRequestedInheritedStatus; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ((pdwMDNumDataEntries == NULL) || ((dwMDBufferSize != 0) && (pbMDBuffer == NULL)) || !CheckGetAttributes(dwMDAttributes) || (dwMDDataType >= INVALID_END_METADATA)) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, AAC_GETALL, METADATA_PERMISSION_READ, &fSecure ); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDGetAllMetaDataW( hActualHandle, pszMDPath, dwMDAttributes, dwMDUserType, dwMDDataType, pdwMDNumDataEntries, pdwMDDataSetNumber, dwMDBufferSize, pbMDBuffer, pdwMDRequiredBufferSize ); if ( !fSecure && SUCCEEDED(hresReturn) ) { hresReturn = RETURNCODETOHRESULT( ERROR_ACCESS_DENIED ); } } else { fRequestedInheritedStatus = dwMDAttributes & METADATA_ISINHERITED; dwMDAttributes |= METADATA_ISINHERITED; // // call metadata com api // hresReturn = m_pMdObject->ComMDGetAllMetaDataW( hActualHandle, pszMDPath, dwMDAttributes, dwMDUserType, dwMDDataType, pdwMDNumDataEntries, pdwMDDataSetNumber, dwMDBufferSize, pbMDBuffer, pdwMDRequiredBufferSize ); if ( SUCCEEDED(hresReturn) ) { PMETADATA_GETALL_RECORD pMDRecord; DWORD iP; // // Scan for secure properties // For such properties, check if user has access to it using following rules: // - must have right to access secure properties in ACE // - must have access to property using ACL visible where property is defined // if no access to property then remove it from list of returned properties pMDRecord = (PMETADATA_GETALL_RECORD)pbMDBuffer; for ( iP = 0 ; iP < *pdwMDNumDataEntries ; ) { if ( pMDRecord->dwMDAttributes & METADATA_SECURE ) { if ( !fSecure || IsReadAccessGranted( hMDHandle, (LPWSTR)pszMDPath, (PMETADATA_RECORD)pMDRecord ) != ERROR_SUCCESS ) { // // remove this property from METADATA_RECORD list, // zero out content // memset( pbMDBuffer + pMDRecord->dwMDDataOffset, 0x0, pMDRecord->dwMDDataLen ); --*pdwMDNumDataEntries; memmove( pMDRecord, pMDRecord + 1, sizeof(METADATA_GETALL_RECORD) * (*pdwMDNumDataEntries-iP) ); continue; } } if ( !fRequestedInheritedStatus ) { pMDRecord->dwMDAttributes &= ~METADATA_ISINHERITED; } ++iP; ++pMDRecord; } } } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::DeleteAllData( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [in] */ DWORD dwMDUserType, /* [in] */ DWORD dwMDDataType ) { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (dwMDDataType >= INVALID_END_METADATA) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDDeleteAllMetaDataW( hActualHandle, pszMDPath, dwMDUserType, dwMDDataType ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDDeleteAllMetaDataW( hActualHandle, pszMDPath, dwMDUserType, dwMDDataType ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::CopyData( /* [in] */ METADATA_HANDLE hMDSourceHandle, /* [string][in] */ LPCWSTR pszMDSourcePath, /* [in] */ METADATA_HANDLE hMDDestHandle, /* [string][in] */ LPCWSTR pszMDDestPath, /* [in] */ DWORD dwMDAttributes, /* [in] */ DWORD dwMDUserType, /* [in] */ DWORD dwMDDataType, /* [in] */ BOOL bMDCopyFlag ) /*++ Routine Description: Copies or moves data associated with the source object to the destination object. Arguments: hMDSourceHandle - open handle pszMDSourcePath - path of the meta object with which then source data is associated hMDDestHandle - handle returned by MDOpenKey with write permission pszMDDestPath - path of the meta object for data to be copied to dwMDAttributes - flags for the data dwMDUserType - user Type for the data dwMDDataType - optional type of the data to copy bMDCopyFlag - if true, data will be copied; if false, data will be moved. Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (((!bMDCopyFlag) && (dwMDAttributes & METADATA_INHERIT)) || ((dwMDAttributes & METADATA_PARTIAL_PATH) && !(dwMDAttributes & METADATA_INHERIT))){ hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hSActualHandle; HANDLE_TYPE SHandleType; METADATA_HANDLE hDActualHandle; HANDLE_TYPE DHandleType; // // lookup and access check source // if (bMDCopyFlag) { hresReturn = LookupAndAccessCheck(hMDSourceHandle, &hSActualHandle, &SHandleType, pszMDSourcePath, 0, METADATA_PERMISSION_READ); } else { // // Deleting source data, so need delete permission // hresReturn = LookupAndAccessCheck(hMDSourceHandle, &hSActualHandle, &SHandleType, pszMDSourcePath, 0, METADATA_PERMISSION_WRITE); } if (SUCCEEDED(hresReturn)) { // // lookup and access check dest // hresReturn = LookupAndAccessCheck(hMDDestHandle, &hDActualHandle, &DHandleType, pszMDDestPath, 0, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if( SHandleType != DHandleType ) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_HANDLE); } else { if( SHandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDCopyMetaDataW(hSActualHandle, pszMDSourcePath, hDActualHandle, pszMDDestPath, dwMDAttributes, dwMDUserType, dwMDDataType, bMDCopyFlag ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDCopyMetaDataW(hSActualHandle, pszMDSourcePath, hDActualHandle, pszMDDestPath, dwMDAttributes, dwMDUserType, dwMDDataType, bMDCopyFlag ); } } } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::GetDataPaths( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [in] */ DWORD dwMDIdentifier, /* [in] */ DWORD dwMDDataType, /* [in] */ DWORD dwMDBufferSize, /* [size_is][out] */ LPWSTR pszMDBuffer, /* [out] */ DWORD __RPC_FAR *pdwMDRequiredBufferSize) { DWORD RetCode; BOOL fSecure; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (((pszMDBuffer == NULL) && (dwMDBufferSize != 0)) || (dwMDDataType >= INVALID_END_METADATA) || (pdwMDRequiredBufferSize == NULL)) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_READ, &fSecure); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDGetMetaDataPathsW(hActualHandle, pszMDPath, dwMDIdentifier, dwMDDataType, dwMDBufferSize, pszMDBuffer, pdwMDRequiredBufferSize ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDGetMetaDataPathsW( hActualHandle, pszMDPath, dwMDIdentifier, dwMDDataType, dwMDBufferSize, pszMDBuffer, pdwMDRequiredBufferSize ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::OpenKey( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in] */ LPCWSTR pszMDPath, /* [in] */ DWORD dwMDAccessRequested, /* [in] */ DWORD dwMDTimeOut, /* [out] */ PMETADATA_HANDLE phMDNewHandle ) /*++ Routine Description: Opens a meta object for read and/or write access. Arguments: hMDHandle - open handle pszMDPath - path of the object to be opened dwMDAccessRequested - permissions requested dwMDTimeOut - time to block waiting for open to succeed, in miliseconds. phMDNewHandle - handle to be passed to other MD routines Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; hresReturn = OpenKeyHelper(hMDHandle, pszMDPath, dwMDAccessRequested, dwMDTimeOut, phMDNewHandle); return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::CloseKey( /* [in] */ METADATA_HANDLE hMDHandle ) /*++ Routine Description: Closes a handle to a meta object. Arguments: hMDHandle - open handle Return Value: Status. --*/ { DWORD dwTemp; COpenHandle *pohHandle; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ((hMDHandle == METADATA_MASTER_ROOT_HANDLE)) { hresReturn = E_HANDLE; } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // Map Admin Handle to Actual Handle // if( (dwTemp = Lookup( hMDHandle, &hActualHandle, &HandleType, &pohHandle )) != ERROR_SUCCESS ) { hresReturn = RETURNCODETOHRESULT(dwTemp); } else { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDCloseMetaObject( hActualHandle ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDCloseMetaObject( hActualHandle ); } pohHandle->Release(this); // // Remove node from handle table // if (SUCCEEDED(hresReturn)) { pohHandle->Release(this); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::ChangePermissions( /* [in] */ METADATA_HANDLE hMDHandle, /* [in] */ DWORD dwMDTimeOut, /* [in] */ DWORD dwMDAccessRequested) /*++ Routine Description: Changes permissions on an open meta object handle. Arguments: hMDHandle - handle to be modified dwMDTimeOut - time to block waiting for open to succeed, in miliseconds. dwMDAccessRequested - requested permissions Return Value: Status. --*/ { DWORD RetCode = ERROR_SUCCESS; METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; // // Map Admin Handle to Actual Handle // if( (RetCode = Lookup( hMDHandle, &hActualHandle, &HandleType )) != ERROR_SUCCESS ) { hresReturn = RETURNCODETOHRESULT(RetCode); } else { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDChangePermissions( hActualHandle, dwMDTimeOut, dwMDAccessRequested ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDChangePermissions( hActualHandle, dwMDTimeOut, dwMDAccessRequested ); } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::SaveData( ) /*++ Routine Description: Saves all data changed since the last load or save to permanent storage. Arguments: None. Return Value: Status. --*/ { METADATA_HANDLE mdhRoot = METADATA_MASTER_ROOT_HANDLE; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (m_pNseObject != NULL) { // // call nse com api // Do this while metabase is not open, as NSE may open // metabase internally // m_pNseObject->ComMDSaveData(); } // // First try to lock the tree // hresReturn = m_pMdObject->ComMDOpenMetaObjectW(METADATA_MASTER_ROOT_HANDLE, NULL, METADATA_PERMISSION_READ, DEFAULT_SAVE_TIMEOUT, &mdhRoot); if (SUCCEEDED(hresReturn)) { // // call metadata com api // hresReturn = m_pMdObject->ComMDSaveData(mdhRoot); m_pMdObject->ComMDCloseMetaObject(mdhRoot); } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::GetHandleInfo( /* [in] */ METADATA_HANDLE hMDHandle, /* [out] */ PMETADATA_HANDLE_INFO pmdhiInfo ) /*++ Routine Description: Gets the information associated with a handle. Arguments: hMDHandle - handle to get information about pmdhiInfo - structure filled in with the information Return Value: Status. --*/ { DWORD RetCode = ERROR_SUCCESS; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (pmdhiInfo == NULL) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // Map Admin Handle to Actual Handle // if( (RetCode = Lookup( hMDHandle, &hActualHandle, &HandleType )) != ERROR_SUCCESS ) { hresReturn = RETURNCODETOHRESULT(RetCode); } else { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDGetHandleInfo( hActualHandle, pmdhiInfo ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDGetHandleInfo( hActualHandle, pmdhiInfo ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::GetSystemChangeNumber( /* [out] */ DWORD __RPC_FAR *pdwSystemChangeNumber ) /*++ Routine Description: Gets the System Change Number. Arguments: pdwSystemChangeNumber - system change number Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (pdwSystemChangeNumber == NULL) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDGetSystemChangeNumber( pdwSystemChangeNumber ); } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::GetDataSetNumber( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in] */ LPCWSTR pszMDPath, /* [out] */ DWORD __RPC_FAR *pdwMDDataSetNumber ) /*++ Routine Description: Gets all the data set number associated with a Meta Object. Arguments: hMDHandle - open handle pszMDPath - path of the meta object with which this data is associated pdwMDDataSetNumber - number associated with this data set Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (pdwMDDataSetNumber == NULL){ hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_READ); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDGetDataSetNumberW( hActualHandle, pszMDPath, pdwMDDataSetNumber ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDGetDataSetNumberW( hActualHandle, pszMDPath, pdwMDDataSetNumber ); } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::SetLastChangeTime( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [in] */ PFILETIME pftMDLastChangeTime, /* [in] */ BOOL bLocalTime) /*++ Routine Description: Set the last change time associated with a Meta Object. Arguments: hMDHandle - open handle pszMDPath - path of the affected meta object pftMDLastChangeTime - new change time for the meta object Return Value: Status. --*/ { FILETIME ftTime; FILETIME *pftTime = pftMDLastChangeTime; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (pftMDLastChangeTime == NULL){ hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if (bLocalTime) { if (!LocalFileTimeToFileTime(pftMDLastChangeTime, &ftTime)) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } pftTime = &ftTime; } if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDSetLastChangeTimeW( hActualHandle, pszMDPath, pftTime ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDSetLastChangeTimeW( hActualHandle, pszMDPath, pftTime ); } } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::GetLastChangeTime( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in][unique] */ LPCWSTR pszMDPath, /* [out] */ PFILETIME pftMDLastChangeTime, /* [in] */ BOOL bLocalTime) /*++ Routine Description: Set the last change time associated with a Meta Object. Arguments: Handle - open handle pszMDPath - path of the affected meta object pftMDLastChangeTime - place to return the change time for the meta object Return Value: Status. --*/ { DWORD RetCode = ERROR_SUCCESS; FILETIME ftTime; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (pftMDLastChangeTime == NULL){ hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_READ); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDGetLastChangeTimeW( hActualHandle, pszMDPath, &ftTime ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDGetLastChangeTimeW( hActualHandle, pszMDPath, &ftTime ); } if (bLocalTime) { if (!FileTimeToLocalFileTime(&ftTime, pftMDLastChangeTime)) { hresReturn = E_UNEXPECTED; } } else { *pftMDLastChangeTime = ftTime; } } } return hresReturn; } HRESULT CADMCOMW::BackupHelper( LPCWSTR pszMDBackupLocation, DWORD dwMDVersion, DWORD dwMDFlags, LPCWSTR pszPasswd ) { HRESULT hresWarning = ERROR_SUCCESS; METADATA_HANDLE mdhRoot = METADATA_MASTER_ROOT_HANDLE; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; hresReturn = ERROR_SUCCESS; if ( !AdminAclAccessCheck( m_pMdObject, (LPVOID)this, METADATA_MASTER_ROOT_HANDLE, L"", 0, METADATA_PERMISSION_READ, &g_ohMasterRootHandle ) ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::Backup] AdminAclAccessCheck failed, error %lx\n", GetLastError() )); hresReturn = RETURNCODETOHRESULT( GetLastError() ); } else { if ((dwMDFlags & MD_BACKUP_SAVE_FIRST) != 0) { // // First lock the tree // hresReturn = m_pMdObject->ComMDOpenMetaObjectW(METADATA_MASTER_ROOT_HANDLE, NULL, METADATA_PERMISSION_READ, DEFAULT_SAVE_TIMEOUT, &mdhRoot); } if (FAILED(hresReturn)) { if ((dwMDFlags & MD_BACKUP_FORCE_BACKUP) != 0) { hresWarning = MD_WARNING_SAVE_FAILED; hresReturn = ERROR_SUCCESS; dwMDFlags &= ~(MD_BACKUP_FORCE_BACKUP | MD_BACKUP_SAVE_FIRST); } } if (SUCCEEDED(hresReturn)) { // // call metadata com api // if( !pszPasswd ) { hresReturn = m_pMdObject->ComMDBackupW(mdhRoot, pszMDBackupLocation, dwMDVersion, dwMDFlags); } else { hresReturn = m_pMdObject->ComMDBackupWithPasswdW(mdhRoot, pszMDBackupLocation, dwMDVersion, dwMDFlags, pszPasswd); } if ((dwMDFlags & MD_BACKUP_SAVE_FIRST) != 0) { m_pMdObject->ComMDCloseMetaObject(mdhRoot); } } if (hresReturn == ERROR_SUCCESS) { hresReturn = hresWarning; } } return hresReturn; } HRESULT CADMCOMW::RestoreHelper( LPCWSTR pszMDBackupLocation, DWORD dwMDVersion, DWORD dwMDMinorVersion, LPCWSTR pszPasswd, DWORD dwMDFlags, DWORD dwRestoreType // RESTORE_HISTORY or RESTORE_BACKUP ) { DBG_ASSERT(dwRestoreType == RESTORE_HISTORY || dwRestoreType == RESTORE_BACKUP); BOOL bIsWin95 = FALSE; BOOL bIsW3svcStarted; BUFFER bufDependentServices; SC_HANDLE schSCM = NULL; SC_HANDLE schIISADMIN = NULL; DWORD dwBytesNeeded; DWORD dwNumServices = 0; LPENUM_SERVICE_STATUS pessDependentServices; SERVICE_STATUS ssDependent; HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; hresReturn = ERROR_SUCCESS; if ( !AdminAclAccessCheck( m_pMdObject, (LPVOID)this, METADATA_MASTER_ROOT_HANDLE, L"", 0, METADATA_PERMISSION_WRITE, &g_ohMasterRootHandle ) ) { if(dwRestoreType == RESTORE_HISTORY) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::RestoreHistory] AdminAclAccessCheck failed, error %lx\n", GetLastError() )); } else { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::Restore] AdminAclAccessCheck failed, error %lx\n", GetLastError() )); } hresReturn = RETURNCODETOHRESULT( GetLastError() ); } else { if ((dwRestoreType == RESTORE_BACKUP && pszMDBackupLocation == NULL) || (pszMDBackupLocation && wcslen(pszMDBackupLocation) >= MD_BACKUP_MAX_LEN)) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { WCHAR pszEnumLocation[MD_BACKUP_MAX_LEN] = {0}; DWORD dwEnumVersion; DWORD dwEnumMinorVersion; FILETIME ftEnumTime; if(pszMDBackupLocation != NULL) { wcscpy(pszEnumLocation, pszMDBackupLocation); } for (DWORD i = 0; SUCCEEDED(hresReturn); i++) { if(dwRestoreType == RESTORE_HISTORY) { hresReturn = m_pMdObject->ComMDEnumHistoryW(pszEnumLocation, &dwEnumVersion, &dwEnumMinorVersion, &ftEnumTime, i); if (SUCCEEDED(hresReturn)) { // DBG_ASSERT(_wcsicmp(pszEnumLocation, pszMDBackupLocation) == 0); if(dwMDFlags & MD_HISTORY_LATEST) { break; } else if (dwEnumVersion == dwMDVersion && dwEnumMinorVersion == dwMDMinorVersion) { break; } } } else { hresReturn = m_pMdObject->ComMDEnumBackupsW(pszEnumLocation, &dwEnumVersion, &ftEnumTime, i); if (SUCCEEDED(hresReturn)) { DBG_ASSERT(_wcsicmp(pszEnumLocation, pszMDBackupLocation) == 0); if ((dwEnumVersion == dwMDVersion) || (dwMDVersion == MD_BACKUP_HIGHEST_VERSION)) { break; } } } } if (FAILED(hresReturn)) { if (hresReturn == RETURNCODETOHRESULT(ERROR_NO_MORE_ITEMS)) { if(dwRestoreType == RESTORE_HISTORY) { if(dwMDFlags & MD_HISTORY_LATEST) { hresReturn = RETURNCODETOHRESULT(ERROR_FILE_NOT_FOUND); } else { hresReturn = RETURNCODETOHRESULT(MD_ERROR_INVALID_VERSION); } } else { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } } } else { // // Looks like a valid database // if ( IISGetPlatformType() == PtWindows95 ) { bIsWin95 = TRUE; } if (bIsWin95) { bIsW3svcStarted = IsInetinfoRunning(); if (bIsW3svcStarted) { W95ShutdownW3SVC(); WaitForW95W3svcStop(); } } else { schSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (schSCM == NULL) { hresReturn = RETURNCODETOHRESULT(GetLastError()); } else { schIISADMIN = OpenService(schSCM, "IISADMIN", STANDARD_RIGHTS_REQUIRED | SERVICE_ENUMERATE_DEPENDENTS); if (schIISADMIN == NULL) { hresReturn = RETURNCODETOHRESULT(GetLastError()); } else { if (!EnumDependentServices(schIISADMIN, SERVICE_ACTIVE, (LPENUM_SERVICE_STATUS)(bufDependentServices.QueryPtr()), bufDependentServices.QuerySize(), &dwBytesNeeded, &dwNumServices)) { if (GetLastError() == ERROR_MORE_DATA) { if (!bufDependentServices.Resize(dwBytesNeeded)) { hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY); } else { if (!EnumDependentServices(schIISADMIN, SERVICE_ACTIVE, (LPENUM_SERVICE_STATUS)(bufDependentServices.QueryPtr()), bufDependentServices.QuerySize(), &dwBytesNeeded, &dwNumServices)) { hresReturn = RETURNCODETOHRESULT(GetLastError()); } } } else { hresReturn = RETURNCODETOHRESULT(GetLastError()); } } if (SUCCEEDED(hresReturn)) { pessDependentServices = (LPENUM_SERVICE_STATUS)(bufDependentServices.QueryPtr()); if (dwNumServices != 0) { SC_HANDLE schDependent; // // Open handles and send service control stop command // for (DWORD i = 0; i < dwNumServices; i++) { //Stop Services if (pessDependentServices[i].ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) { schDependent = OpenService(schSCM, pessDependentServices[i].lpServiceName, SERVICE_ALL_ACCESS); if (schDependent != NULL) { ControlService(schDependent, SERVICE_CONTROL_STOP, &ssDependent); WaitForServiceStatus(schDependent, SERVICE_STOPPED); CloseServiceHandle(schDependent); } } } } } CloseServiceHandle(schIISADMIN); } } } if (SUCCEEDED(hresReturn)) { AdminAclDisableAclCache(); AdminAclFlushCache(); if(dwRestoreType == RESTORE_HISTORY) { hresReturn = m_pMdObject->ComMDRestoreHistoryW(pszMDBackupLocation, dwMDVersion, dwMDMinorVersion, dwMDFlags); } else { if( !pszPasswd ) { hresReturn = m_pMdObject->ComMDRestoreW(pszMDBackupLocation, dwMDVersion, dwMDFlags); } else { hresReturn = m_pMdObject->ComMDRestoreWithPasswdW(pszMDBackupLocation, dwMDVersion, dwMDFlags, pszPasswd); } } AdminAclEnableAclCache(); } if (bIsWin95) { if (bIsW3svcStarted) { W95StartW3SVC(); // // No good way to wait for service to start, so just // sleep a little while // Sleep(SLEEP_INTERVAL); } } else { if (dwNumServices != 0) { SC_HANDLE schDependent; // // Open handles and start services // Use reverse order, since EnumServices orders // list by dependencies // for (long i = (long)dwNumServices - 1; i >= 0; i--) { //Stop Services if (pessDependentServices[i].ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING) { schDependent = OpenService(schSCM, pessDependentServices[i].lpServiceName, SERVICE_ALL_ACCESS); if (schDependent != NULL) { StartService(schDependent, 0, NULL); WaitForServiceStatus(schDependent, SERVICE_RUNNING); CloseServiceHandle(schDependent); } } } } if (schSCM != NULL) { CloseServiceHandle(schSCM); } } // // Issue TaylorW 4/10/2001 // // After the restore, notify clients, as data has changed // and all handles have become invalid // // Windows Bug 82423 // } } } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::Backup( /* [string][in][unique] */ LPCWSTR pszMDBackupLocation, /* [in] */ DWORD dwMDVersion, /* [in] */ DWORD dwMDFlags) { return BackupHelper( pszMDBackupLocation, dwMDVersion, dwMDFlags ); } HRESULT STDMETHODCALLTYPE CADMCOMW::BackupWithPasswd( /* [string][in][unique] */ LPCWSTR pszMDBackupLocation, /* [in] */ DWORD dwMDVersion, /* [in] */ DWORD dwMDFlags, /* [defaultvalue][string][in][unique] */ LPCWSTR pszPasswd ) { return BackupHelper( pszMDBackupLocation, dwMDVersion, dwMDFlags, pszPasswd ); } HRESULT STDMETHODCALLTYPE CADMCOMW::Restore( /* [string][in][unique] */ LPCWSTR pszMDBackupLocation, /* [in] */ DWORD dwMDVersion, /* [in] */ DWORD dwMDFlags) { return RestoreHelper( pszMDBackupLocation, dwMDVersion, 0, NULL, dwMDFlags, RESTORE_BACKUP ); } HRESULT STDMETHODCALLTYPE CADMCOMW::RestoreWithPasswd( /* [string][in][unique] */ LPCWSTR pszMDBackupLocation, /* [in] */ DWORD dwMDVersion, /* [in] */ DWORD dwMDFlags, /* [defaultvalue][string][in][unique] */ LPCWSTR pszPasswd) { return RestoreHelper( pszMDBackupLocation, dwMDVersion, 0, pszPasswd, dwMDFlags, RESTORE_BACKUP ); } HRESULT STDMETHODCALLTYPE CADMCOMW::EnumBackups( /* [size_is][out][in] */ LPWSTR pszMDBackupLocation, /* [out] */ DWORD __RPC_FAR *pdwMDVersion, /* [out] */ PFILETIME pftMDBackupTime, /* [in] */ DWORD dwMDEnumIndex) { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ( !AdminAclAccessCheck( m_pMdObject, (LPVOID)this, METADATA_MASTER_ROOT_HANDLE, L"", 0, METADATA_PERMISSION_READ, &g_ohMasterRootHandle ) ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::EnumBackups AdminAclAccessCheck failed, error %lx\n", GetLastError() )); hresReturn = RETURNCODETOHRESULT( GetLastError() ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDEnumBackupsW(pszMDBackupLocation, pdwMDVersion, pftMDBackupTime, dwMDEnumIndex); } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::DeleteBackup( /* [string][in][unique] */ LPCWSTR pszMDBackupLocation, /* [in] */ DWORD dwMDVersion) { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ( !AdminAclAccessCheck( m_pMdObject, (LPVOID)this, METADATA_MASTER_ROOT_HANDLE, L"", 0, METADATA_PERMISSION_WRITE, &g_ohMasterRootHandle ) ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::DeleteBackup] AdminAclAccessCheck failed, error %lx\n", GetLastError() )); hresReturn = RETURNCODETOHRESULT( GetLastError() ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDDeleteBackupW(pszMDBackupLocation, dwMDVersion); } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::Export( /* [string][in][unique] */ LPCWSTR i_wszPasswd, /* [string][in][unique] */ LPCWSTR i_wszFileName, /* [string][in][unique] */ LPCWSTR i_wszSourcePath, /* [in] */ DWORD i_dwMDFlags) { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; HRESULT hresWarning = MD_ERROR_NOT_INITIALIZED; METADATA_HANDLE mdh = 0; METADATA_HANDLE mdhActual = 0; COpenHandle* pohActual = NULL; HANDLE_TYPE mdHandleType; // // parameter validation // if (i_wszFileName == NULL || i_wszSourcePath == NULL) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); return hresReturn; } hresReturn = OpenKeyHelper(METADATA_MASTER_ROOT_HANDLE, i_wszSourcePath, METADATA_PERMISSION_READ, DEFAULT_SAVE_TIMEOUT, &mdh); // // pohActual refCount = 2 after Lookup. // if(SUCCEEDED(hresReturn)) { hresReturn = Lookup(mdh, &mdhActual, &mdHandleType, &pohActual); hresReturn = RETURNCODETOHRESULT(hresReturn); } if(SUCCEEDED(hresReturn)) { // // Move refCount down to 1. // pohActual->Release(this); if( !AdminAclAccessCheck( m_pMdObject, (LPVOID)this, mdh, L"", 0, METADATA_PERMISSION_READ, pohActual ) ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::Export] AdminAclAccessCheck failed, error %lx\n", GetLastError() )); hresReturn = RETURNCODETOHRESULT( GetLastError() ); } else { // call metadata com api hresReturn = m_pMdObject->ComMDExportW(mdhActual, i_wszPasswd, i_wszFileName, i_wszSourcePath, i_dwMDFlags); } // close key if( mdHandleType == NSEPM_HANDLE ) { // call nse com api hresWarning = m_pNseObject->ComMDCloseMetaObject( mdhActual ); } else { // call metadata com api hresWarning = m_pMdObject->ComMDCloseMetaObject( mdhActual ); } pohActual->Release(this); } if(SUCCEEDED(hresReturn)) { hresReturn = hresWarning; } return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::Import( /* [string][in][unique] */ LPCWSTR i_wszPasswd, /* [string][in][unique] */ LPCWSTR i_wszFileName, /* [string][in][unique] */ LPCWSTR i_wszSourcePath, /* [string][in][unique] */ LPCWSTR i_wszDestPath, /* [in] */ DWORD i_dwMDFlags) /*++ Synopsis: Arguments: [i_wszPasswd] - [i_wszFileName] - [i_wszSourcePath] - Absolute metabase path [i_wszDestPath] - Absolute metabase path [i_dwMDFlags] - Return Value: --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; HRESULT hresWarning = MD_ERROR_NOT_INITIALIZED; METADATA_HANDLE mdh = 0; METADATA_HANDLE mdhActual = 0; COpenHandle* pohActual = NULL; HANDLE_TYPE mdHandleType; LPWSTR wszDeepest = NULL; LONG cchDeepest = 0; LPWSTR wszEnd = NULL; LONG idx = 0; WCHAR wszKeyType[METADATA_MAX_STRING_LEN] = {0}; DWORD dwRequiredSize = 0; METADATA_RECORD mr = { MD_KEY_TYPE, METADATA_NO_ATTRIBUTES, IIS_MD_UT_SERVER, STRING_METADATA, METADATA_MAX_STRING_LEN*sizeof(WCHAR), (LPBYTE)wszKeyType, 0 }; // // parameter validation // if (i_wszFileName == NULL || i_wszSourcePath == NULL || i_wszDestPath == NULL) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); return hresReturn; } if (i_wszPasswd == NULL) { i_wszPasswd = L""; } // // else we can move on, but FreeInUse() must be called before exiting this // function. this is done in exit section. // // // Copy i_wszDestPath to wszDeepest // Remove trailing slashes // cchDeepest = wcslen(i_wszDestPath); wszDeepest = new WCHAR[1+cchDeepest]; if(!wszDeepest) { hresReturn = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY); goto exit; } memcpy(wszDeepest, i_wszDestPath, sizeof(WCHAR)*(cchDeepest+1)); while( cchDeepest > 0 && IS_MD_PATH_DELIM(wszDeepest[cchDeepest-1]) ) { cchDeepest--; } // // Open the deepest level key possible // wszEnd = wszDeepest + cchDeepest; for(idx = cchDeepest; idx >= 0; idx--) { if(idx == 0 || idx == cchDeepest || IS_MD_PATH_DELIM(*wszEnd)) { *wszEnd = L'\0'; hresReturn = OpenKeyHelper( METADATA_MASTER_ROOT_HANDLE, wszDeepest, METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ, DEFAULT_SAVE_TIMEOUT, &mdh); if( FAILED(hresReturn) && hresReturn != RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND) ) { goto exit; } else if(SUCCEEDED(hresReturn)) { break; } } wszEnd--; } if(FAILED(hresReturn)) { goto exit; } // // If we are here, we now have an Open metabase handle // hresReturn = Lookup(mdh, &mdhActual, &mdHandleType, &pohActual); hresReturn = RETURNCODETOHRESULT(hresReturn); if(FAILED(hresReturn)) { // // Yes, an open key does not get closed, but Lookup really should // not fail if mdh is a valid key. // goto exit; } pohActual->Release(this); // Decrements refcount from 2 to 1. if( !AdminAclAccessCheck( m_pMdObject, (LPVOID)this, mdh, L"", 0, METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ, pohActual ) ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::Import] AdminAclAccessCheck failed, error %lx\n", GetLastError() )); hresReturn = RETURNCODETOHRESULT( GetLastError() ); goto exit; } // // Get the keytype // If the node does not exist, or node exists but keytype doesn't, we // will not set wszKeytype and hence ComMDImport will not attempt to match // the source and dest keytype // hresReturn = m_pMdObject->ComMDGetMetaDataW( mdhActual, i_wszDestPath+idx, &mr, &dwRequiredSize); if(hresReturn == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND)) { hresReturn = S_OK; } else if(hresReturn == MD_ERROR_DATA_NOT_FOUND) { hresReturn = S_OK; } if(FAILED(hresReturn)) { DBGPRINTF((DBG_CONTEXT, "Error trying to retrieve keytype for %ws\n", i_wszDestPath+idx)); goto exit; } // // Call Import // hresReturn = m_pMdObject->ComMDImportW( mdhActual, i_wszDestPath+idx, wszKeyType, i_wszPasswd, i_wszFileName, i_wszSourcePath, i_dwMDFlags); if(FAILED(hresReturn)) { goto exit; } exit: if(pohActual != NULL) { // // Close Key // if( mdHandleType == NSEPM_HANDLE ) { // call nse com api hresWarning = m_pNseObject->ComMDCloseMetaObject( mdhActual ); } else { // call metadata com api hresWarning = m_pMdObject->ComMDCloseMetaObject( mdhActual ); } pohActual->Release(this); pohActual = NULL; } delete [] wszDeepest; return (FAILED(hresReturn)) ? hresReturn : hresWarning; } HRESULT STDMETHODCALLTYPE CADMCOMW::RestoreHistory( /* [unique][in][string] */ LPCWSTR pszMDHistoryLocation, /* [in] */ DWORD dwMDMajorVersion, /* [in] */ DWORD dwMDMinorVersion, /* [in] */ DWORD dwMDFlags) { HRESULT hresReturn = ERROR_SUCCESS; if( (dwMDFlags & ~MD_HISTORY_LATEST) != 0 && dwMDFlags != 0 ) { return HRESULT_FROM_WIN32(ERROR_INVALID_FLAGS); } if( (dwMDFlags & MD_HISTORY_LATEST) && (dwMDMajorVersion != 0 || dwMDMinorVersion != 0) ) { return E_INVALIDARG; } // // parameter validation done in here. // hresReturn = RestoreHelper(pszMDHistoryLocation, dwMDMajorVersion, dwMDMinorVersion, NULL, dwMDFlags, RESTORE_HISTORY); return hresReturn; } HRESULT STDMETHODCALLTYPE CADMCOMW::EnumHistory( /* [size_is][out][in] */ LPWSTR io_wszMDHistoryLocation, /* [out] */ DWORD __RPC_FAR *o_pdwMDMajorVersion, /* [out] */ DWORD __RPC_FAR *o_pdwMDMinorVersion, /* [out] */ PFILETIME o_pftMDHistoryTime, /* [in] */ DWORD i_dwMDEnumIndex) { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if (io_wszMDHistoryLocation == NULL || o_pdwMDMajorVersion == NULL || o_pdwMDMinorVersion == NULL || o_pftMDHistoryTime == NULL) { return RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } if ( !AdminAclAccessCheck( m_pMdObject, (LPVOID)this, METADATA_MASTER_ROOT_HANDLE, L"", 0, METADATA_PERMISSION_READ, &g_ohMasterRootHandle ) ) { DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::EnumHistory AdminAclAccessCheck failed, error %lx\n", GetLastError() )); hresReturn = RETURNCODETOHRESULT( GetLastError() ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDEnumHistoryW(io_wszMDHistoryLocation, o_pdwMDMajorVersion, o_pdwMDMinorVersion, o_pftMDHistoryTime, i_dwMDEnumIndex); } return hresReturn; } VOID CADMCOMW::ReleaseNode( IN HANDLE_TABLE *phndTable ) { if ( phndTable ) { m_rHandleResource.Unlock(); } } HRESULT CADMCOMW::AddKeyHelper( IN METADATA_HANDLE hMDHandle, IN LPCWSTR pszMDPath ) /*++ Routine Description: Add meta object and adds it to the list of child objects for the object specified by Path. Arguments: hMDHandle - open handle pszMDPath - path of the object to be added Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ((pszMDPath == NULL) || (*pszMDPath == (WCHAR)'\0')) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; // // lookup and access check // hresReturn = LookupAndAccessCheck(hMDHandle, &hActualHandle, &HandleType, pszMDPath, 0, METADATA_PERMISSION_WRITE); if (SUCCEEDED(hresReturn)) { if( HandleType == NSEPM_HANDLE ) { // // call nse com api // hresReturn = m_pNseObject->ComMDAddMetaObjectW( hActualHandle, pszMDPath ); } else { // // call metadata com api // hresReturn = m_pMdObject->ComMDAddMetaObjectW( hActualHandle, pszMDPath ); } } } return hresReturn; } HRESULT CADMCOMW::OpenKeyHelper( /* [in] */ METADATA_HANDLE hMDHandle, /* [string][in] */ LPCWSTR pszMDPath, /* [in] */ DWORD dwMDAccessRequested, /* [in] */ DWORD dwMDTimeOut, /* [out] */ PMETADATA_HANDLE phMDNewHandle ) /*++ Routine Description: Opens a meta object for read and/or write access. - This is used by Export. Arguments: hMDHandle - open handle pszMDPath - path of the object to be opened dwMDAccessRequested - permissions requested dwMDTimeOut - time to block waiting for open to succeed, in miliseconds. phMDNewHandle - handle to be passed to other MD routines Return Value: Status. --*/ { HRESULT hresReturn = MD_ERROR_NOT_INITIALIZED; if ((phMDNewHandle == NULL) || ((dwMDAccessRequested & (METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE)) == 0)) { hresReturn = RETURNCODETOHRESULT(ERROR_INVALID_PARAMETER); } else { METADATA_HANDLE hNewHandle; METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; DWORD RetCode; HANDLE_TABLE *phtNode; UINT cL; COpenHandle *pohParent; // // Map Admin Handle to Actual Handle // // // This Addrefs pohParent, which makes sure it doesn't do away // pohParent is needed by AddNode // RetCode = Lookup( hMDHandle, &hActualHandle, &HandleType, &pohParent); if( RetCode == ERROR_SUCCESS) { if(HandleType == NSEPM_HANDLE || (HandleType == ALL_HANDLE && pszMDPath != NULL && IsValidNsepmPath( pszMDPath )) ) { // // call nse com api // hresReturn = m_pNseObject->ComMDOpenMetaObjectW( hActualHandle, pszMDPath, dwMDAccessRequested, dwMDTimeOut, &hNewHandle ); if( SUCCEEDED(hresReturn) ) { hresReturn = AddNode( hNewHandle, pohParent, NSEPM_HANDLE, phMDNewHandle, pszMDPath ); if (FAILED(hresReturn)) { m_pNseObject->ComMDCloseMetaObject( hNewHandle ); } } } else { DBG_ASSERT( HandleType == META_HANDLE || HandleType == ALL_HANDLE ); // // call metadata com api // hresReturn = m_pMdObject->ComMDOpenMetaObjectW( hActualHandle, pszMDPath, dwMDAccessRequested, dwMDTimeOut, &hNewHandle ); if( SUCCEEDED(hresReturn) ) { hresReturn = AddNode( hNewHandle, pohParent, META_HANDLE, phMDNewHandle, pszMDPath ); if (FAILED(hresReturn)) { m_pMdObject->ComMDCloseMetaObject( hNewHandle ); } } } pohParent->Release(this); } else { hresReturn = RETURNCODETOHRESULT(RetCode); } } return hresReturn; } DWORD CADMCOMW::Lookup( IN METADATA_HANDLE hHandle, OUT METADATA_HANDLE *phActualHandle, OUT HANDLE_TYPE *HandleType, OUT COpenHandle **ppohHandle ) { HANDLE_TABLE *phtNode; DWORD dwReturn = ERROR_INVALID_HANDLE; if( hHandle == METADATA_MASTER_ROOT_HANDLE ) { *phActualHandle = g_MasterRoot.hActualHandle; *HandleType = g_MasterRoot.HandleType; if (ppohHandle != NULL) { *ppohHandle = g_MasterRoot.pohHandle; (*ppohHandle)->AddRef(); } dwReturn = ERROR_SUCCESS; } else { m_rHandleResource.Lock(TSRES_LOCK_READ); for( phtNode = m_hashtab[(DWORD)hHandle % HASHSIZE]; phtNode != NULL; phtNode = phtNode->next ) { if( phtNode->hAdminHandle == hHandle ) { *phActualHandle = phtNode->hActualHandle; *HandleType = phtNode->HandleType; if (ppohHandle != NULL) { *ppohHandle = phtNode->pohHandle; (*ppohHandle)->AddRef(); } dwReturn = ERROR_SUCCESS; break; } } m_rHandleResource.Unlock(); } return dwReturn; } VOID CADMCOMW::DisableAllHandles( ) { HANDLE_TABLE *phtNode; DWORD i; // // At this point, all metadata handles should be closed because a retore // just happened. So don't need to close these handles. // // // Can't just delete them, becuase of syncronization problems // with CloseKey and Lookup. Set the hande to an invalid value // So Lookup won't use them. // m_rHandleResource.Lock(TSRES_LOCK_WRITE); for( i = 0; i < HASHSIZE; i++ ) { for( phtNode = m_hashtab[i]; phtNode != NULL; phtNode = phtNode->next ) { phtNode->hAdminHandle = INVALID_ADMINHANDLE_VALUE; } } if ( m_pNseObject ) { m_pNseObject->ComMDRestoreW( NULL, 0, 0 ); } m_rHandleResource.Unlock(); } HRESULT CADMCOMW::LookupAndAccessCheck( IN METADATA_HANDLE hHandle, OUT METADATA_HANDLE *phActualHandle, OUT HANDLE_TYPE *pHandleType, IN LPCWSTR pszPath, IN DWORD dwId, // check for MD_ADMIN_ACL, must have special right to write them IN DWORD dwAccess, // METADATA_PERMISSION_* OUT LPBOOL pfEnableSecureAccess ) { DWORD dwReturn = ERROR_SUCCESS; COpenHandle *pohParent; // // Map Admin Handle to Actual Handle // // // This Addrefs pohParent, which makes sure it doesn't go away // until AdminAclAccessCheck is done // dwReturn = Lookup( hHandle, phActualHandle, pHandleType, &pohParent); if (dwReturn == ERROR_SUCCESS) { if (!AdminAclAccessCheck(m_pMdObject, (LPVOID)this, hHandle, pszPath, dwId, dwAccess, pohParent, pfEnableSecureAccess)) { dwReturn = GetLastError(); } pohParent->Release(this); } return RETURNCODETOHRESULT(dwReturn); } DWORD CADMCOMW::LookupActualHandle( IN METADATA_HANDLE hHandle ) { HANDLE_TABLE *phtNode; DWORD i; DWORD dwReturn = ERROR_INVALID_HANDLE; m_rHandleResource.Lock(TSRES_LOCK_READ); for( i = 0; (i < HASHSIZE) && (dwReturn != ERROR_SUCCESS); i++ ) { for( phtNode = m_hashtab[i]; (phtNode != NULL) && (dwReturn != ERROR_SUCCESS); phtNode = phtNode->next ) { if( phtNode->hActualHandle == hHandle ) { dwReturn = ERROR_SUCCESS; } } } m_rHandleResource.Unlock(); return dwReturn; } HRESULT CADMCOMW::AddNode( METADATA_HANDLE hActualHandle, COpenHandle *pohParentHandle, enum HANDLE_TYPE HandleType, PMETADATA_HANDLE phAdminHandle, LPCWSTR pszPath ) { HANDLE_TABLE *phtNode = (HANDLE_TABLE *)LocalAlloc(LMEM_FIXED, sizeof(*phtNode)); DWORD hashVal; HRESULT hresReturn = ERROR_SUCCESS; COpenHandle * pohHandle = new COpenHandle; METADATA_HANDLE hParentActualHandle; HANDLE_TYPE htParentType; if ((phtNode == NULL) || (pohHandle == NULL)) { hresReturn = E_OUTOFMEMORY; if( phtNode ) { LocalFree(phtNode); } if( pohHandle ) { delete pohHandle; } } else { m_rHandleResource.Lock(TSRES_LOCK_WRITE); hresReturn = pohHandle->Init(m_dwHandleValue, pszPath, pohParentHandle->GetPath(), (HandleType == NSEPM_HANDLE) ? TRUE : FALSE); if (FAILED(hresReturn)) { LocalFree(phtNode); delete pohHandle; } else { phtNode->pohHandle = pohHandle; phtNode->hAdminHandle = m_dwHandleValue; *phAdminHandle = m_dwHandleValue++; phtNode->hActualHandle = hActualHandle; phtNode->HandleType = HandleType; hashVal = (phtNode->hAdminHandle) % HASHSIZE; phtNode->next = m_hashtab[hashVal]; m_hashtab[hashVal] = phtNode; } m_rHandleResource.Unlock(); } return hresReturn; } DWORD CADMCOMW::DeleteNode( METADATA_HANDLE hHandle ) { HANDLE_TABLE *phtNode; HANDLE_TABLE *phtDelNode; DWORD HashValue = (DWORD)hHandle % HASHSIZE; if( hHandle == METADATA_MASTER_ROOT_HANDLE ) { return ERROR_SUCCESS; } m_rHandleResource.Lock(TSRES_LOCK_WRITE); phtNode = m_hashtab[HashValue]; // // check single node linked list // if( phtNode->hAdminHandle == hHandle ) { m_hashtab[HashValue] = phtNode->next; delete phtNode->pohHandle; LocalFree(phtNode); } else { for( ; phtNode != NULL; phtNode = phtNode->next ) { phtDelNode = phtNode->next; if( phtDelNode != NULL ) { if( phtDelNode->hAdminHandle == hHandle ) { phtNode->next = phtDelNode->next; delete phtDelNode->pohHandle; LocalFree(phtDelNode); break; } } } } m_rHandleResource.Unlock(); return ERROR_SUCCESS; } //--------------- /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M Method: COPaper::NotifySinks Summary: Internal utility method of this COM object used to fire event notification calls to all listening connection sinks in the client. Args: PAPER_EVENT PaperEvent Type of notification event. SHORT nX X cordinate. Value is 0 unless event needs it. SHORT nY Y cordinate. Value is 0 unless event needs it. SHORT nInkWidth Ink Width. Value is 0 unless event needs it. SHORT crInkColor COLORREF RGB color value. Value is 0 unless event needs it. Modifies: ... Returns: HRESULT Standard OLE result code. NOERROR for success. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/ HRESULT CADMCOMW::NotifySinks( /* [in] */ METADATA_HANDLE hMDHandle, /* [in] */ DWORD dwMDNumElements, /* [size_is][in] */ MD_CHANGE_OBJECT_W __RPC_FAR pcoChangeList[ ], /* [in] */ BOOL bIsMainNotification) { // DBGPRINTF(( DBG_CONTEXT, "[CADMCOMW::NotifySink]\n" )); HRESULT hr = NOERROR; IConnectionPoint* pIConnectionPoint; IEnumConnections* pIEnum; CONNECTDATA ConnData; HRESULT hrTemp; HANDLE_TABLE *node; m_rSinkResource.Lock(TSRES_LOCK_READ); if (m_bCallSinks) { // // if the meta handle is for this object, return ERROR_SUCCESS to // the caller (admin's sink); // if( !bIsMainNotification || (LookupActualHandle( hMDHandle ) != ERROR_SUCCESS) ) { // // Correct broken connections. // It's not likely to be a high number so // save a memory allocation by using an array. // DWORD pdwLostConnections[MAX_SINK_CALLS_TOBE_REMOVED]; DWORD dwNumLostConnections = 0; // If there was a paper event, broadcast appropriate notifications to // all Sinks connected to each connection point. // if (PAPER_EVENT_NONE != PaperEvent) { // Here is the section for the PaperSink connection point--currently // this is the only connection point offered by COPaper objects. pIConnectionPoint = m_aConnectionPoints[ADM_CONNPOINT_WRITESINK]; if (NULL != pIConnectionPoint) { pIConnectionPoint->AddRef(); hr = pIConnectionPoint->EnumConnections(&pIEnum); if (SUCCEEDED(hr)) { // Loop thru the connection point's connections and if the // listening connection supports IPaperSink (ie, PaperSink events) // then dispatch the PaperEvent event notification to that sink. while (NOERROR == pIEnum->Next(1, &ConnData, NULL)) { IMSAdminBaseSinkW *pIADMCOMSINKW_Synchro = NULL; AsyncIMSAdminBaseSinkW *pIADMCOMSINKW_Async = NULL; ICallFactory *pCF = NULL; HRESULT hr ; hr = ConnData.pUnk->QueryInterface(IID_ICallFactory, (void **)&pCF); if (SUCCEEDED(hr)) { hr = pCF->CreateCall(IID_AsyncIMSAdminBaseSink_W, NULL, IID_AsyncIMSAdminBaseSink_W, (IUnknown **)&pIADMCOMSINKW_Async); if (SUCCEEDED(hr)) { if (bIsMainNotification) { hr = pIADMCOMSINKW_Async->Begin_SinkNotify(dwMDNumElements, pcoChangeList); } else { hr = pIADMCOMSINKW_Async->Begin_ShutdownNotify(); } pIADMCOMSINKW_Async->Release(); } else { DBGPRINTF(( DBG_CONTEXT, "Failled in CreateCall to ICallFactory !!!!\n" )); } pCF->Release(); } else { hr = ConnData.pUnk->QueryInterface(IID_IMSAdminBaseSink_W, (PPVOID)&pIADMCOMSINKW_Synchro); if (SUCCEEDED(hr)) { if (bIsMainNotification) { hr = pIADMCOMSINKW_Synchro->SinkNotify(dwMDNumElements, pcoChangeList); } else { hr= pIADMCOMSINKW_Synchro->ShutdownNotify(); } pIADMCOMSINKW_Synchro->Release(); } else { DBGPRINTF(( DBG_CONTEXT, "Failled in QueryInterface for synchro version of IID_IMSAdminBaseSink_W\n" )); } } 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))) { if (dwNumLostConnections < MAX_SINK_CALLS_TOBE_REMOVED) { pdwLostConnections[dwNumLostConnections++] = ConnData.dwCookie; } } } ConnData.pUnk->Release(); } pIEnum->Release(); } while (dwNumLostConnections > 0) { m_rSinkResource.Convert(TSRES_CONV_WRITE); ((COConnectionPoint *)pIConnectionPoint)->Unadvise_Worker( pdwLostConnections[--dwNumLostConnections]); } pIConnectionPoint->Release(); } } } } m_rSinkResource.Unlock(); return hr; } // // Stubs for routine that clients shouldn't be calling anyway. // HRESULT CADMCOMW::KeyExchangePhase1() { return E_FAIL; } HRESULT CADMCOMW::KeyExchangePhase2() { return E_FAIL; } HRESULT STDMETHODCALLTYPE CADMCOMW::GetServerGuid( void) { return E_FAIL; } HRESULT STDMETHODCALLTYPE CADMCOMW::UnmarshalInterface( /* [out] */ IMSAdminBaseW __RPC_FAR *__RPC_FAR *piadmbwInterface) { AddRef(); // Always return interfaces addref'ed *piadmbwInterface = (IMSAdminBaseW *)this; return(NOERROR); } BOOL CADMCOMW::CheckGetAttributes(DWORD dwAttributes) { DWORD dwReturn = TRUE; if ((dwAttributes & METADATA_REFERENCE) || ((dwAttributes & METADATA_PARTIAL_PATH) && !(dwAttributes & METADATA_INHERIT))) { dwReturn = FALSE; } return dwReturn; } VOID WaitForW95W3svcStop() { DWORD dwSleepTotal = 0; while (dwSleepTotal < MAX_SLEEP) { if (!IsInetinfoRunning()) { break; } else { // // Still pending... // Sleep(SLEEP_INTERVAL); dwSleepTotal += SLEEP_INTERVAL; } } } VOID WaitForServiceStatus(SC_HANDLE schDependent, DWORD dwDesiredServiceState) { DWORD dwSleepTotal = 0; SERVICE_STATUS ssDependent; while (dwSleepTotal < MAX_SLEEP) { if (QueryServiceStatus(schDependent, &ssDependent)) { if (ssDependent.dwCurrentState == dwDesiredServiceState) { break; } else { // // Still pending... // Sleep(SLEEP_INTERVAL); dwSleepTotal += SLEEP_INTERVAL; } } else { break; } } } DWORD CADMCOMW::IsReadAccessGranted( METADATA_HANDLE hHandle, LPWSTR pszPath, METADATA_RECORD* pmdRecord ) /*++ Routine Description: Check if read access to property granted based on ACL visible at point in metabase where property is stored ( as opposed as check made by AdminAclAccessCheck which uses the ACL visible at path specified during data access ) Arguments: hHandle - DCOM metabase handle pszPath - path relative to hHandle pmdRecord - metadata info to access property Returns: ERROR_SUCCESS if access granted, otherwise error code --*/ { DWORD dwStatus = ERROR_SUCCESS; LPWSTR pszPropPath; // // If property is not inherited then we already checked the correct ACL // if ( !(pmdRecord->dwMDAttributes & METADATA_ISINHERITED) ) { return dwStatus; } // determine from where we got it // do AccessCheck if ( (dwStatus = FindClosestProp( hHandle, pszPath, &pszPropPath, pmdRecord->dwMDIdentifier, pmdRecord->dwMDDataType, pmdRecord->dwMDUserType, METADATA_SECURE, TRUE )) == ERROR_SUCCESS ) { if ( pszPropPath ) // i.e such a property exist { dwStatus = AdminAclAccessCheck( m_pMdObject, (LPVOID)this, METADATA_MASTER_ROOT_HANDLE, pszPropPath, pmdRecord->dwMDIdentifier, METADATA_PERMISSION_READ, &g_ohMasterRootHandle ) ? ERROR_SUCCESS : GetLastError(); LocalFree( pszPropPath ); } else { dwStatus = MD_ERROR_DATA_NOT_FOUND; // // Should not happen unless handle is master root : // if we are here then we succeeded accessing data and as we have a read handle // nobody should be able to delete it // if master root handle we don't have such protection, so property could // have been deleted. // DBG_ASSERT ( METADATA_MASTER_ROOT_HANDLE == hHandle ); } } return dwStatus; } DWORD CADMCOMW::FindClosestProp( METADATA_HANDLE hHandle, LPWSTR pszRelPath, LPWSTR* ppszPropPath, DWORD dwPropId, DWORD dwDataType, DWORD dwUserType, DWORD dwAttr, BOOL fSkipCurrentNode ) /*++ Routine Description: Find the closest path where the specified property exist ( in the direction of the root ) in metabase Arguments: hHandle - DCOM metabase handle pszRelPath - path relative to hHandle ppszPropPath - updated with path to property or NULL if property not found dwPropId - property ID dwDataType - property data type dwUserType - property user type dwAttr - property attribute fSkipCurrentNode - TRUE to skip current node while scanning for property Returns: TRUE if success ( including property not found ), otherwise FALSE --*/ { DWORD dwReturn; LPWSTR pszParentPath; METADATA_HANDLE hActualHandle; HANDLE_TYPE HandleType; COpenHandle * pohParent; HRESULT hRes; METADATA_RECORD mdRecord; DWORD dwRequiredLen; LPWSTR pszPath; BOOL fFound; dwReturn = Lookup( hHandle, &hActualHandle, &HandleType, &pohParent); if ( dwReturn != ERROR_SUCCESS ) { return dwReturn; } pszParentPath = pohParent->GetPath(); if (pszRelPath == NULL) { pszRelPath = L""; } DBG_ASSERT(pszParentPath != NULL); DBG_ASSERT((*pszParentPath == (WCHAR)'\0') || ISPATHDELIMW(*pszParentPath)); // // Strip front slash now, add it in later // if (ISPATHDELIMW(*pszRelPath)) { pszRelPath++; } DWORD dwRelPathLen = wcslen(pszRelPath); DWORD dwParentPathLen = wcslen(pszParentPath); DBG_ASSERT((dwParentPathLen == 0) || (!ISPATHDELIMW(pszParentPath[dwParentPathLen -1]))); // // Get rid of trailing slash for good // if ((dwRelPathLen > 0) && (ISPATHDELIMW(pszRelPath[dwRelPathLen -1]))) { dwRelPathLen--; } // // Include space for mid slash if Relpath exists // Include space for termination // DWORD dwTotalSize = (dwRelPathLen + dwParentPathLen + 1 + ((dwRelPathLen > 0) ? 1 : 0)) * sizeof(WCHAR); *ppszPropPath = pszPath = (LPWSTR)LocalAlloc(LMEM_FIXED, dwTotalSize); if (pszPath == NULL) { dwReturn = GetLastError(); } else { // // OK to always copy the first part // memcpy(pszPath, pszParentPath, dwParentPathLen * sizeof(WCHAR)); // // Don't need slash if there is no RelPath // if (dwRelPathLen > 0) { pszPath[dwParentPathLen] = (WCHAR)'/'; memcpy(pszPath + dwParentPathLen + 1, pszRelPath, dwRelPathLen * sizeof(WCHAR)); } pszPath[(dwTotalSize / sizeof(WCHAR)) - 1] = (WCHAR)'\0'; // // Now convert \ to / for string compares // LPWSTR pszPathIndex = pszPath; while ((pszPathIndex = wcschr(pszPathIndex, (WCHAR)'\\')) != NULL) { *pszPathIndex = (WCHAR)'/'; } // scan for property pszPathIndex = pszPath + wcslen(pszPath); while ( TRUE ) { if ( !fSkipCurrentNode ) { // check prop exist mdRecord.dwMDIdentifier = dwPropId; mdRecord.dwMDAttributes = dwAttr; mdRecord.dwMDUserType = dwUserType; mdRecord.dwMDDataType = dwDataType; mdRecord.dwMDDataLen = 0; mdRecord.pbMDData = NULL; mdRecord.dwMDDataTag = NULL; hRes = m_pMdObject->ComMDGetMetaDataW( METADATA_MASTER_ROOT_HANDLE, pszPath, &mdRecord, &dwRequiredLen ); if ( hRes == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER) ) { break; } } // scan backward for delimiter fFound = FALSE; if ( pszPathIndex > pszPath ) { do { if ( *--pszPathIndex == L'/' ) { *pszPathIndex = L'\0'; fFound = TRUE; break; } } while ( pszPathIndex > pszPath ); } if ( !fFound ) { // Property not found, return OK status with NULL string *ppszPropPath = NULL; LocalFree( pszPath ); break; } fSkipCurrentNode = FALSE; } } pohParent->Release( this ); return dwReturn; } BOOL MakeParentPath( LPWSTR pszPath ) /*++ Routine Description: Make the path points to parent Arguments: pszPath - path to adjust Returns: TRUE if success, otherwise FALSE ( no parent ) --*/ { LPWSTR pszPathIndex = pszPath + wcslen( pszPath ); BOOL fFound = FALSE; while ( pszPathIndex > pszPath ) { if ( *--pszPathIndex == L'/' ) { *pszPathIndex = L'\0'; fFound = TRUE; break; } } return fFound; } BOOL IsValidNsepmPath( LPCWSTR pszMDPath ) /*++ Routine Description: Determine if pszMDPath is a valid NSEPM path. Really the following are the only valid path forms, but we are going to do a simpler test and just reject paths that have "Root" before the . /lm// /lm//<#>/ Arguments: psMDPath - the path to validate Return Value: TRUE if path is valid --*/ { BOOL ValidPath = FALSE; LPWSTR pszNsepmTag; if( pszNsepmTag = wcsstr( pszMDPath, L"" ) ) { DWORD cchPrefix = DIFF( pszNsepmTag - pszMDPath ); LPWSTR pszPrefix = (LPWSTR)LocalAlloc( LPTR, (cchPrefix + 1) * sizeof(WCHAR) ); if( pszPrefix ) { memcpy( pszPrefix, pszMDPath, cchPrefix * sizeof(WCHAR) ); pszPrefix[cchPrefix] = 0; _wcsupr( pszPrefix ); if( wcsstr( pszPrefix, L"ROOT" ) == NULL ) { ValidPath = TRUE; } LocalFree( pszPrefix ); } } return ValidPath; }