Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

6331 lines
171 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. comobj.cxx
  5. Abstract:
  6. This module defines DCOM Admin APIs.
  7. Author:
  8. Sophia Chung (sophiac) 23-Nov-1996
  9. --*/
  10. #include "precomp.hxx"
  11. #include <iadm.h>
  12. #include "coiadm.hxx"
  13. #include "admacl.hxx"
  14. //
  15. // Globals
  16. //
  17. DECLARE_DEBUG_PRINTS_OBJECT();
  18. ULONG g_dwRefCount = 0;
  19. COpenHandle g_ohMasterRootHandle;
  20. HANDLE_TABLE g_MasterRoot = {
  21. NULL,
  22. 0,
  23. METADATA_MASTER_ROOT_HANDLE,
  24. &g_ohMasterRootHandle
  25. };
  26. DWORD CADMCOMW::sm_dwProcessIdThis = 0;
  27. DWORD CADMCOMW::sm_dwProcessIdRpcSs = 0;
  28. //
  29. // Private prototypes
  30. //
  31. //
  32. // Used by RestoreHelper
  33. //
  34. #define RESTORE_HISTORY 0x1
  35. #define RESTORE_BACKUP 0x2
  36. BOOL
  37. MakeParentPath(
  38. LPWSTR pszPath
  39. );
  40. //------------------------------
  41. CADMCOMW::CADMCOMW():
  42. m_ImpIConnectionPointContainer(),
  43. m_ImpExpHelp(),
  44. m_pMdObject(NULL),
  45. m_pMdObject3(NULL),
  46. m_dwRefCount(1),
  47. m_dwHandleValue(1),
  48. m_pEventSink(NULL),
  49. m_pConnPoint(NULL),
  50. m_piuFTM(NULL),
  51. m_bTerminated(FALSE),
  52. m_bIsTerminateRoutineComplete(FALSE),
  53. m_dwProcessIdCaller(0),
  54. m_hProcessCaller(NULL),
  55. m_hWaitCaller(NULL),
  56. m_dwThreadIdDisconnect(0)
  57. {
  58. HRESULT hRes;
  59. memset((PVOID)m_hashtab, 0, sizeof(m_hashtab) );
  60. InitializeListHead( &m_ObjectListEntry );
  61. hRes = CoCreateInstance(CLSID_MDCOM, NULL, CLSCTX_INPROC_SERVER, IID_IMDCOM2, (void**) &m_pMdObject);
  62. if (FAILED(hRes))
  63. {
  64. DBGPRINTF(( DBG_CONTEXT,
  65. "[CADMCOMW::CADMCOMW] CoCreateInstance(MDCOM) failed, error %lx\n",
  66. hRes ));
  67. }
  68. else
  69. {
  70. hRes = m_pMdObject->ComMDInitialize();
  71. if (FAILED(hRes))
  72. {
  73. DBGPRINTF(( DBG_CONTEXT,
  74. "[CADMCOMW::CADMCOMW] ComMDInitialize(MDCOM) failed, error %lx\n",
  75. hRes ));
  76. m_pMdObject->Release();
  77. m_pMdObject = NULL;
  78. }
  79. }
  80. if (SUCCEEDED(hRes))
  81. {
  82. // pickup IMDCOM3 if available
  83. // ignore the return value by design
  84. // IIS5.1 metadata.dll will fail this call. IIS6.0+ metadata will succeed this call
  85. HRESULT hrTemp = m_pMdObject->QueryInterface(IID_IMDCOM3, (void**)&m_pMdObject3);
  86. DBG_ASSERT(SUCCEEDED(hrTemp) || NULL == m_pMdObject3);
  87. if ( FAILED( hrTemp ) )
  88. {
  89. m_pMdObject3 = NULL;
  90. }
  91. m_pEventSink = new CImpIMDCOMSINKW((IMSAdminBaseW*)this);
  92. if( m_pEventSink == NULL )
  93. {
  94. DBGPRINTF(( DBG_CONTEXT,
  95. "[CADMCOMW::CADMCOMW] CImpIMDCOMSINKW failed, error %lx\n",
  96. ERROR_NOT_ENOUGH_MEMORY ));
  97. hRes = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  98. }
  99. else
  100. {
  101. m_pEventSink->AddRef();
  102. // ImpExpHelp
  103. m_ImpExpHelp.Init(this);
  104. m_ImpIConnectionPointContainer.Init(this);
  105. // Rig this COPaper COM object to be connectable. Assign the connection
  106. // point array. This object's connection points are determined at
  107. // compile time--it currently has only one connection point:
  108. // the CONNPOINT_PAPERSINK connection point. Create a connection
  109. // point object for this and assign it into the array. This array could
  110. // easily grow to support additional connection points in the future.
  111. // First try initializing the connection point object. Pass 'this' as the
  112. // pHostObj pointer used by the connection point to pass its AddRef and
  113. // Release calls back to the host connectable object.
  114. // The initialization will create
  115. // its initial dynamic connection array.
  116. hRes = m_ConnectionPoint.Init(this, IID_IMSAdminBaseSink_W);
  117. if (SUCCEEDED(hRes))
  118. {
  119. //
  120. // Admin's sink
  121. //
  122. IConnectionPointContainer* pConnPointContainer = NULL;
  123. // First query the object for its Connection Point Container. This
  124. // essentially asks the object in the server if it is connectable.
  125. hRes = m_pMdObject->QueryInterface( IID_IConnectionPointContainer,
  126. (PVOID *)&pConnPointContainer);
  127. if SUCCEEDED(hRes)
  128. {
  129. // Find the requested Connection Point. This AddRef's the
  130. // returned pointer.
  131. hRes = pConnPointContainer->FindConnectionPoint(IID_IMDCOMSINK_W, &m_pConnPoint);
  132. if (SUCCEEDED(hRes))
  133. {
  134. hRes = m_pConnPoint->Advise((IUnknown *)m_pEventSink, &m_dwCookie);
  135. }
  136. pConnPointContainer->Release();
  137. pConnPointContainer = NULL;
  138. if (SUCCEEDED(hRes))
  139. {
  140. hRes = CoCreateFreeThreadedMarshaler((IUnknown *)this, &m_piuFTM);
  141. }
  142. }
  143. }
  144. else
  145. {
  146. m_ConnectionPoint.Terminate();
  147. }
  148. }
  149. }
  150. if ( SUCCEEDED( hRes ) )
  151. {
  152. // Initialize watching the caller process
  153. hRes = InitializeCallerWatch();
  154. if ( FAILED( hRes ) )
  155. {
  156. DBGPRINTF(( DBG_CONTEXT,
  157. "InitializeCallerWatch() failed in CADMCOMW::~CADMCOMW hr=0x%08x.\n",
  158. hRes ));
  159. }
  160. }
  161. SetStatus(hRes);
  162. //
  163. // Insert our object into the global list only if it is valid.
  164. //
  165. if( SUCCEEDED(hRes) )
  166. {
  167. AddObjectToList();
  168. }
  169. else
  170. {
  171. StopNotifications( TRUE );
  172. }
  173. }
  174. CADMCOMW::~CADMCOMW()
  175. {
  176. Terminate();
  177. }
  178. HRESULT
  179. CADMCOMW::StopNotifications(
  180. BOOL fRemoveAllPending)
  181. {
  182. HRESULT hr = S_OK;
  183. if ( m_pEventSink != NULL )
  184. {
  185. m_pEventSink->DetachAdminObject();
  186. }
  187. if ( ( m_dwCookie != 0 ) && ( m_pConnPoint != NULL ) )
  188. {
  189. m_pConnPoint->Unadvise(m_dwCookie);
  190. m_dwCookie = 0;
  191. }
  192. m_ConnectionPoint.Disable();
  193. if ( fRemoveAllPending )
  194. {
  195. RemoveAllPendingNotifications( TRUE );
  196. }
  197. return hr;
  198. }
  199. HRESULT
  200. CADMCOMW::RemoveAllPendingNotifications(
  201. BOOL fWaitForCurrent)
  202. {
  203. HRESULT hr = S_OK;
  204. NOTIFY_CONTEXT::RemoveWorkFor( this, fWaitForCurrent );
  205. return hr;
  206. }
  207. VOID
  208. CADMCOMW::Terminate()
  209. {
  210. HANDLE_TABLE *node;
  211. HANDLE_TABLE *nextnode;
  212. DWORD i;
  213. BOOL bTerminated;
  214. //
  215. // Terminate must only be called from two locations. And they
  216. // should synchronize correctly.
  217. //
  218. // 1. From ~CADMCOMW. Obviously this should only be called once.
  219. //
  220. // 2. From ForceTerminate. That routine should only be called in
  221. // shutdown. With a reference held on this object. So the final
  222. // release should call the dtor and this routine should noop.
  223. //
  224. bTerminated = (BOOL)InterlockedCompareExchange( (LONG*)&m_bTerminated, TRUE, FALSE );
  225. if( !bTerminated )
  226. {
  227. ShutdownCallerWatch();
  228. //
  229. // Tell ADMWPROX.DLL to release this object's associated security
  230. // context.
  231. //
  232. ReleaseObjectSecurityContextW( ( IUnknown* )this );
  233. //
  234. // Do final release of the connection point objects.
  235. // If this isn't the final release, then the client has an outstanding
  236. // unbalanced reference to a connection point and a memory leak may
  237. // likely result because the host COPaper object is now going away yet
  238. // a connection point for this host object will not end up deleting
  239. // itself (and its connections array).
  240. //
  241. m_ConnectionPoint.Terminate();
  242. if (SUCCEEDED(GetStatus()))
  243. {
  244. m_LockHandleResource.WriteLock();
  245. //
  246. // Close all opened handles
  247. //
  248. for( i = 0; i < HASHSIZE; i++ )
  249. {
  250. for( node = nextnode = m_hashtab[i]; node != NULL; node = nextnode )
  251. {
  252. if ( node->hAdminHandle != INVALID_ADMINHANDLE_VALUE )
  253. {
  254. AdminAclNotifyClose( (LPVOID)this, node->hAdminHandle );
  255. //
  256. // call metadata com api
  257. //
  258. m_pMdObject->ComMDCloseMetaObject( node->hActualHandle );
  259. }
  260. nextnode = node->next;
  261. delete node->pohHandle;
  262. LocalFree(node);
  263. }
  264. m_hashtab[i] = NULL;
  265. }
  266. //
  267. // Issue TaylorW 3/20/2001
  268. // QFE tree contains this call:
  269. //
  270. // AdminAclNotifyClose( (LPVOID)this, METADATA_MASTER_ROOT_HANDLE );
  271. //
  272. // I have no idea when this may have entered their tree or been lost
  273. // from ours. I don't see any record in source depot of it being
  274. // removed or added. Need to investigate why it would be needed.
  275. //
  276. m_LockHandleResource.WriteUnlock();
  277. }
  278. if ( m_pEventSink != NULL )
  279. {
  280. m_pEventSink->Release();
  281. m_pEventSink = NULL;
  282. }
  283. if ( m_pConnPoint != NULL )
  284. {
  285. m_pConnPoint->Release();
  286. m_pConnPoint = NULL;
  287. }
  288. if ( m_pMdObject != NULL )
  289. {
  290. m_pMdObject->ComMDTerminate(TRUE);
  291. m_pMdObject->Release();
  292. m_pMdObject = NULL;
  293. if ( m_pMdObject3 != NULL )
  294. {
  295. m_pMdObject3->Release();
  296. m_pMdObject3 = NULL;
  297. }
  298. }
  299. if ( m_piuFTM != NULL )
  300. {
  301. m_piuFTM->Release();
  302. m_piuFTM = NULL;
  303. }
  304. m_bIsTerminateRoutineComplete = TRUE;
  305. }
  306. while ( m_bIsTerminateRoutineComplete != TRUE )
  307. {
  308. Sleep( 100 );
  309. }
  310. }
  311. VOID
  312. CADMCOMW::ForceTerminate()
  313. {
  314. const INT MAX_WAIT_TRIES = 5;
  315. INT WaitTries;
  316. DBG_ASSERT( !m_bIsTerminateRoutineComplete );
  317. DBG_ASSERT( !m_bTerminated );
  318. //
  319. // Wait on the reference count of this object. But bound
  320. // the wait so a leaked in process object does not prevent
  321. // us from shutting down the service.
  322. //
  323. // Wait on a ref count of 1, because the caller better be
  324. // holding our last reference. This assumes all external
  325. // references are killed through CoDisconnect() and all
  326. // internal references are released because of dependent
  327. // services shutting down.
  328. //
  329. // Issue TaylorW 3/20/2001
  330. //
  331. // In iis 5.1 the web service will shutdown filters after
  332. // it has already reported that it is done shutting down.
  333. // This is bad, but changing the shutdown logic of the
  334. // web service is not worth doing at this time. Hopefully
  335. // the shutdown timeout will be sufficient to allow this
  336. // operation to complete.
  337. //
  338. // Windows Bugs 318006
  339. //
  340. // CoDisconnect the object and the connection point
  341. DisconnectOrphaned();
  342. for( WaitTries = 0;
  343. m_dwRefCount > 1 && WaitTries < MAX_WAIT_TRIES;
  344. WaitTries++ )
  345. {
  346. SleepEx( WaitTries*200, TRUE );
  347. }
  348. //
  349. // If we timed out. Something is wrong. Most likely someone in
  350. // process has leaked this object. These asserts are actually
  351. // overactive unless ref tracing is enabled on this object.
  352. //
  353. //
  354. // Issue TaylorW 4/9/2001
  355. //
  356. // It looks like front page leaks a base object from in process.
  357. // So these assertions need to be turned off.
  358. //
  359. #define DEBUG_BASE_OBJ_LEAK 0x80000000L
  360. IF_DEBUG( BASE_OBJ_LEAK )
  361. {
  362. DBG_ASSERT( m_dwRefCount == 1 );
  363. DBG_ASSERT( WaitTries < MAX_WAIT_TRIES );
  364. }
  365. //
  366. // Go ahead and try to clean up.
  367. //
  368. Terminate();
  369. }
  370. HRESULT
  371. CADMCOMW::QueryInterface(
  372. REFIID riid,
  373. void **ppObject)
  374. {
  375. HRESULT hr;
  376. // If caller watch is not initialized
  377. if ( !IsCallerWatchInitialized() )
  378. {
  379. // Initialize the caller watch
  380. hr = InitializeCallerWatch();
  381. if ( FAILED( hr ) )
  382. {
  383. return hr;
  384. }
  385. }
  386. if (riid==IID_IUnknown || riid==IID_IMSAdminBase_W)
  387. {
  388. *ppObject = (IMSAdminBase *) this;
  389. AddRef();
  390. }
  391. else if (IID_IMSAdminBase2_W == riid)
  392. {
  393. *ppObject = (IMSAdminBase2 *) this;
  394. AddRef();
  395. }
  396. else if (IID_IMSAdminBase3_W == riid &&
  397. NULL != m_pMdObject3)
  398. {
  399. *ppObject = (IMSAdminBase3 *) this;
  400. AddRef();
  401. }
  402. else if (IID_IMSImpExpHelp_W == riid)
  403. {
  404. *ppObject = &m_ImpExpHelp;
  405. AddRef();
  406. }
  407. else if (IID_IConnectionPointContainer == riid)
  408. {
  409. METADATA_HANDLE hActualHandle;
  410. hr = LookupAndAccessCheck( METADATA_MASTER_ROOT_HANDLE,
  411. &hActualHandle,
  412. NULL,
  413. 0,
  414. METADATA_PERMISSION_READ);
  415. if (FAILED(hr))
  416. {
  417. return hr;
  418. }
  419. *ppObject = &m_ImpIConnectionPointContainer;
  420. AddRef();
  421. }
  422. else if (IID_IMarshal == riid)
  423. {
  424. return m_piuFTM->QueryInterface(riid, ppObject);
  425. }
  426. else
  427. {
  428. return E_NOINTERFACE;
  429. }
  430. return S_OK;
  431. }
  432. ULONG
  433. CADMCOMW::AddRef( )
  434. {
  435. DWORD dwRefCount;
  436. dwRefCount = InterlockedIncrement((long *)&m_dwRefCount);
  437. if( sm_pDbgRefTraceLog )
  438. {
  439. WriteRefTraceLog( sm_pDbgRefTraceLog, dwRefCount, this );
  440. }
  441. return dwRefCount;
  442. }
  443. ULONG
  444. CADMCOMW::Release( )
  445. {
  446. DWORD dwRefCount;
  447. dwRefCount = InterlockedDecrement((long *)&m_dwRefCount);
  448. if( sm_pDbgRefTraceLog )
  449. {
  450. WriteRefTraceLog( sm_pDbgRefTraceLog, -(LONG)dwRefCount, this );
  451. }
  452. if( dwRefCount == 1 )
  453. {
  454. //
  455. // We keep a list of objects around so that we can clean up and
  456. // shutdown successfully. The list holds a reference to this object
  457. // when we hit a reference of 1, we know it is time to remove
  458. // ourselves from the list. If we are in shutdown we may already
  459. // have been removed from the list. But normally, this call to
  460. // RemoveObjectFromList removes our last reference and thus sends
  461. // us back through Release and ultimately to our destructor.
  462. //
  463. RemoveObjectFromList();
  464. }
  465. else if( dwRefCount == 0 )
  466. {
  467. delete this;
  468. }
  469. return dwRefCount;
  470. }
  471. HRESULT
  472. CADMCOMW::AddKey(
  473. IN METADATA_HANDLE hMDHandle,
  474. IN LPCWSTR pszMDPath)
  475. /*++
  476. Routine Description:
  477. Add meta object and adds it to the list of child objects for the object
  478. specified by Path.
  479. Arguments:
  480. hMDHandle - open handle
  481. pszMDPath - path of the object to be added
  482. Return Value:
  483. Status.
  484. --*/
  485. {
  486. HRESULT hresReturn = S_OK;
  487. hresReturn = AddKeyHelper(hMDHandle, pszMDPath);
  488. return hresReturn;
  489. }
  490. HRESULT
  491. CADMCOMW::DeleteKey(
  492. IN METADATA_HANDLE hMDHandle,
  493. IN LPCWSTR pszMDPath)
  494. /*++
  495. Routine Description:
  496. Deletes a meta object and all of its data.
  497. Arguments:
  498. hMDHandle - open handle
  499. pszMDPath - path of object to be deleted, relative to the path of Handle.
  500. Must not be NULL.
  501. Return Value:
  502. Status.
  503. --*/
  504. {
  505. HRESULT hresReturn = S_OK;
  506. METADATA_HANDLE hActualHandle;
  507. if (pszMDPath == NULL)
  508. {
  509. hresReturn = E_INVALIDARG;
  510. }
  511. else
  512. {
  513. //
  514. // lookup and access check
  515. //
  516. hresReturn = LookupAndAccessCheck(hMDHandle,
  517. &hActualHandle,
  518. pszMDPath,
  519. AAC_DELETEKEY,
  520. METADATA_PERMISSION_WRITE);
  521. if (SUCCEEDED(hresReturn))
  522. {
  523. //
  524. // call metadata com api
  525. //
  526. hresReturn = m_pMdObject->ComMDDeleteMetaObjectW( hActualHandle,
  527. pszMDPath );
  528. }
  529. }
  530. return hresReturn;
  531. }
  532. HRESULT STDMETHODCALLTYPE
  533. CADMCOMW::DeleteChildKeys(
  534. METADATA_HANDLE hMDHandle,
  535. LPCWSTR pszMDPath)
  536. /*++
  537. Routine Description:
  538. Deletes all child meta objects of the specified object, with all of their
  539. data.
  540. Arguments:
  541. hMDHandle - open handle
  542. pszMDPath - path of the parent of the objects to be deleted, relative to
  543. the path of Handle.
  544. Return Value:
  545. Status.
  546. --*/
  547. {
  548. HRESULT hresReturn = S_OK;
  549. METADATA_HANDLE hActualHandle;
  550. //
  551. // lookup and access check
  552. //
  553. hresReturn = LookupAndAccessCheck(hMDHandle,
  554. &hActualHandle,
  555. pszMDPath,
  556. AAC_DELETEKEY,
  557. METADATA_PERMISSION_WRITE);
  558. if (SUCCEEDED(hresReturn))
  559. {
  560. //
  561. // call metadata com api
  562. //
  563. hresReturn = m_pMdObject->ComMDDeleteChildMetaObjectsW( hActualHandle,
  564. pszMDPath );
  565. }
  566. return hresReturn;
  567. }
  568. HRESULT STDMETHODCALLTYPE
  569. CADMCOMW::EnumKeys(
  570. METADATA_HANDLE hMDHandle,
  571. LPCWSTR pszMDPath,
  572. LPWSTR pszMDName,
  573. DWORD dwMDEnumObjectIndex)
  574. /*++
  575. Routine Description:
  576. Enumerate objects in path.
  577. Arguments:
  578. hMDHandle - open handle
  579. pszMDPath - path of parent object, relative to the path of Handle
  580. eg. "Root Object/Child/GrandChild"
  581. pszMDName - buffer where the Name of the object is returned
  582. dwEnumObjectIndex - index of the value to be retrieved
  583. Return Value:
  584. Status.
  585. --*/
  586. {
  587. HRESULT hresReturn = S_OK;
  588. METADATA_HANDLE hActualHandle;
  589. if (pszMDName == NULL)
  590. {
  591. hresReturn = E_INVALIDARG;
  592. }
  593. else
  594. {
  595. //
  596. // lookup and access check
  597. //
  598. hresReturn = LookupAndAccessCheck(hMDHandle,
  599. &hActualHandle,
  600. pszMDPath,
  601. AAC_ENUM_KEYS,
  602. METADATA_PERMISSION_READ);
  603. if (SUCCEEDED(hresReturn))
  604. {
  605. //
  606. // call metadata com api
  607. //
  608. hresReturn = m_pMdObject->ComMDEnumMetaObjectsW( hActualHandle,
  609. pszMDPath,
  610. pszMDName,
  611. dwMDEnumObjectIndex );
  612. }
  613. }
  614. return hresReturn;
  615. }
  616. HRESULT STDMETHODCALLTYPE
  617. CADMCOMW::CopyKey(
  618. METADATA_HANDLE hMDSourceHandle,
  619. LPCWSTR pszMDSourcePath,
  620. METADATA_HANDLE hMDDestHandle,
  621. LPCWSTR pszMDDestPath,
  622. BOOL bMDOverwriteFlag,
  623. BOOL bMDCopyFlag)
  624. /*++
  625. Routine Description:
  626. Copy or move source meta object and its data and descendants to Dest.
  627. Arguments:
  628. hMDSourceHandle - open handle
  629. pszMDSourcePath - path of the object to be copied
  630. hMDDestHandle - handle of the new location for the object
  631. pszMDDestPath - path of the new location for the object, relative
  632. to the path of hMDDestHandle
  633. bMDOverwriteFlag - determine the behavior if a meta object with the same
  634. name as source is already a child of pszMDDestPath.
  635. bMDCopyFlag - determine whether Source is deleted from its original location
  636. Return Value:
  637. Status
  638. --*/
  639. {
  640. HRESULT hresReturn = S_OK;
  641. METADATA_HANDLE hSActualHandle;
  642. METADATA_HANDLE hDActualHandle;
  643. //
  644. // lookup and access check source
  645. //
  646. if (bMDCopyFlag)
  647. {
  648. hresReturn = LookupAndAccessCheck(hMDSourceHandle,
  649. &hSActualHandle,
  650. pszMDSourcePath,
  651. 0,
  652. METADATA_PERMISSION_READ);
  653. }
  654. else
  655. {
  656. //
  657. // Deleting source path, so need delete permission
  658. //
  659. hresReturn = LookupAndAccessCheck(hMDSourceHandle,
  660. &hSActualHandle,
  661. pszMDSourcePath,
  662. AAC_DELETEKEY,
  663. METADATA_PERMISSION_WRITE);
  664. }
  665. if (SUCCEEDED(hresReturn))
  666. {
  667. //
  668. // lookup and access check dest
  669. //
  670. hresReturn = LookupAndAccessCheck(hMDDestHandle,
  671. &hDActualHandle,
  672. pszMDDestPath,
  673. AAC_COPYKEY,
  674. METADATA_PERMISSION_WRITE);
  675. if (SUCCEEDED(hresReturn))
  676. {
  677. //
  678. // call metadata com api
  679. //
  680. hresReturn = m_pMdObject->ComMDCopyMetaObjectW( hSActualHandle,
  681. pszMDSourcePath,
  682. hDActualHandle,
  683. pszMDDestPath,
  684. bMDOverwriteFlag,
  685. bMDCopyFlag );
  686. }
  687. }
  688. return hresReturn;
  689. }
  690. HRESULT STDMETHODCALLTYPE
  691. CADMCOMW::RenameKey(
  692. METADATA_HANDLE hMDHandle,
  693. LPCWSTR pszMDPath,
  694. LPCWSTR pszMDNewName)
  695. {
  696. HRESULT hr = S_OK;
  697. BOOL fRet;
  698. DWORD dwError;
  699. METADATA_HANDLE hActualHandle;
  700. COpenHandle *pohParent = NULL;
  701. DWORD cchMDPath;
  702. DWORD i;
  703. STRAU strNewPath;
  704. // Check args
  705. if ( ( hMDHandle == METADATA_MASTER_ROOT_HANDLE ) ||
  706. ( pszMDPath == NULL ) ||
  707. ( pszMDNewName == NULL ) ||
  708. ( *pszMDNewName == L'\0' ) ||
  709. ( wcschr( pszMDNewName, MD_PATH_DELIMETERW ) != NULL ) ||
  710. ( wcschr( pszMDNewName, MD_ALT_PATH_DELIMETERW ) != NULL ) )
  711. {
  712. hr = E_INVALIDARG;
  713. goto exit;
  714. }
  715. // Get the len of the source path
  716. cchMDPath = (DWORD)wcslen( pszMDPath );
  717. // Check
  718. if ( ( cchMDPath == 0 ) || ( cchMDPath >= METADATA_MAX_NAME_LEN ) )
  719. {
  720. hr = E_INVALIDARG;
  721. goto exit;
  722. }
  723. // Map Admin Handle to Actual Handle
  724. dwError = Lookup( hMDHandle,
  725. &hActualHandle,
  726. &pohParent );
  727. if ( dwError != ERROR_SUCCESS )
  728. {
  729. hr = HRESULT_FROM_WIN32( dwError );
  730. goto exit;
  731. }
  732. // Check access
  733. fRet = AdminAclAccessCheck( m_pMdObject,
  734. this,
  735. hMDHandle,
  736. pszMDPath,
  737. MD_ADMIN_ACL,
  738. METADATA_PERMISSION_WRITE,
  739. pohParent );
  740. if ( !fRet )
  741. {
  742. dwError = GetLastError();
  743. hr = HRESULT_FROM_WIN32( dwError );
  744. goto exit;
  745. }
  746. // Now we need to do the harder part: check whether the caller
  747. // has access to the new path. To do so we need to construct the
  748. // target path by replacing the last name in the source path with the new name.
  749. // If the source path ends with delimiter
  750. if ( ( pszMDPath[cchMDPath-1] == MD_PATH_DELIMETERW ) ||
  751. ( pszMDPath[cchMDPath-1] == MD_ALT_PATH_DELIMETERW ) )
  752. {
  753. // Ignore it
  754. cchMDPath--;
  755. // The resulting path should not be empty or ending with delimiter
  756. if ( ( cchMDPath == 0 ) ||
  757. ( pszMDPath[cchMDPath-1] == MD_PATH_DELIMETERW ) ||
  758. ( pszMDPath[cchMDPath-1] == MD_ALT_PATH_DELIMETERW ) )
  759. {
  760. hr = E_INVALIDARG;
  761. goto exit;
  762. }
  763. }
  764. // Find the last delimiter
  765. for ( i = cchMDPath; i != 0; i-- )
  766. {
  767. // Delimiter?
  768. if ( ( pszMDPath[i-1] == MD_PATH_DELIMETERW ) ||
  769. ( pszMDPath[i-1] == MD_ALT_PATH_DELIMETERW ) )
  770. {
  771. // The part we are interested in is upto excluding the delimiter
  772. // It is valid for cchMDPath to become 0.
  773. cchMDPath = i-1;
  774. break;
  775. }
  776. }
  777. // If there was no delimiter
  778. if ( i == 0 )
  779. {
  780. // This source was just a name, so bellow we shouldn't copy anything
  781. cchMDPath = 0;
  782. }
  783. // Copy the source path w/o the last name
  784. fRet = strNewPath.Copy( (const LPWSTR)pszMDPath, cchMDPath );
  785. if ( !fRet )
  786. {
  787. hr = E_OUTOFMEMORY;
  788. goto exit;
  789. }
  790. fRet = strNewPath.Append( L"/", 1 );
  791. if ( !fRet )
  792. {
  793. hr = E_OUTOFMEMORY;
  794. goto exit;
  795. }
  796. // Append the new name
  797. fRet = strNewPath.Append( (const LPWSTR)pszMDNewName );
  798. if ( !fRet )
  799. {
  800. hr = E_OUTOFMEMORY;
  801. goto exit;
  802. }
  803. // Check access on the target path
  804. fRet = AdminAclAccessCheck( m_pMdObject,
  805. this,
  806. hMDHandle,
  807. strNewPath.QueryStrW(),
  808. MD_ADMIN_ACL,
  809. METADATA_PERMISSION_WRITE,
  810. pohParent );
  811. if ( !fRet )
  812. {
  813. dwError = GetLastError();
  814. hr = HRESULT_FROM_WIN32( dwError );
  815. goto exit;
  816. }
  817. // call metadata com api
  818. hr = m_pMdObject->ComMDRenameMetaObjectW( hActualHandle,
  819. pszMDPath,
  820. pszMDNewName );
  821. if ( FAILED( hr ) )
  822. {
  823. goto exit;
  824. }
  825. exit:
  826. if ( pohParent != NULL )
  827. {
  828. pohParent->Release(this);
  829. pohParent = NULL;
  830. }
  831. return hr;
  832. }
  833. HRESULT STDMETHODCALLTYPE
  834. CADMCOMW::SetData(
  835. METADATA_HANDLE hMDHandle,
  836. LPCWSTR pszMDPath,
  837. PMETADATA_RECORD pmdrMDData)
  838. /*++
  839. Routine Description:
  840. Set a data object.
  841. Arguments:
  842. hMDHandle - open handle
  843. pszMDPath - path of the meta object with which this data is associated
  844. pmdrMDData - data to set
  845. Return Value:
  846. Status.
  847. --*/
  848. {
  849. HRESULT hresReturn = S_OK;
  850. METADATA_HANDLE hActualHandle;
  851. //
  852. // lookup and access check
  853. //
  854. hresReturn = LookupAndAccessCheck(hMDHandle,
  855. &hActualHandle,
  856. pszMDPath,
  857. pmdrMDData->dwMDIdentifier,
  858. METADATA_PERMISSION_WRITE );
  859. if (SUCCEEDED(hresReturn))
  860. {
  861. if ( !AdminAclNotifySetOrDeleteProp(
  862. hMDHandle,
  863. pmdrMDData->dwMDIdentifier ) )
  864. {
  865. DBGPRINTF(( DBG_CONTEXT,
  866. "[CADMCOMW::SetData] AdminAclNotifySetOrDel failed, error %lx\n",
  867. GetLastError() ));
  868. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  869. }
  870. else
  871. {
  872. //
  873. // call metadata com api
  874. //
  875. hresReturn = m_pMdObject->ComMDSetMetaDataW( hActualHandle,
  876. pszMDPath,
  877. pmdrMDData );
  878. }
  879. }
  880. return hresReturn;
  881. }
  882. HRESULT STDMETHODCALLTYPE
  883. CADMCOMW::GetData(
  884. METADATA_HANDLE hMDHandle,
  885. LPCWSTR pszMDPath,
  886. PMETADATA_RECORD pmdrMDData,
  887. DWORD *pdwMDRequiredDataLen)
  888. /*++
  889. Routine Description:
  890. Get one metadata value
  891. Arguments:
  892. hMDHandle - open handle
  893. pszMDPath - path of the meta object with which this data is associated
  894. pmdrMDData - data structure
  895. pdwMDRequiredDataLen - updated with required length
  896. Return Value:
  897. Status.
  898. --*/
  899. {
  900. HRESULT hresReturn = S_OK;
  901. METADATA_HANDLE hActualHandle;
  902. BOOL fEnableSecureAccess;
  903. BOOL fRequestedInheritedStatus;
  904. DWORD dwRetCode;
  905. if ((pmdrMDData == NULL) ||
  906. ((pmdrMDData->dwMDDataLen != 0) && (pmdrMDData->pbMDData == NULL)) ||
  907. !CheckGetAttributes(pmdrMDData->dwMDAttributes) ||
  908. (pmdrMDData->dwMDDataType >= INVALID_END_METADATA))
  909. {
  910. hresReturn = E_INVALIDARG;
  911. }
  912. else
  913. {
  914. //
  915. // lookup and access check
  916. //
  917. hresReturn = LookupAndAccessCheck(hMDHandle,
  918. &hActualHandle,
  919. pszMDPath,
  920. pmdrMDData->dwMDIdentifier,
  921. METADATA_PERMISSION_READ,
  922. &fEnableSecureAccess );
  923. if (SUCCEEDED(hresReturn))
  924. {
  925. fRequestedInheritedStatus = pmdrMDData->dwMDAttributes & METADATA_ISINHERITED;
  926. pmdrMDData->dwMDAttributes |= METADATA_ISINHERITED;
  927. //
  928. // call metadata com api
  929. //
  930. hresReturn = m_pMdObject->ComMDGetMetaDataW( hActualHandle,
  931. pszMDPath,
  932. pmdrMDData,
  933. pdwMDRequiredDataLen );
  934. //
  935. // if metadata is secure, check if can access this property from
  936. // where it is defined, i.e using the ACL visible at the definition
  937. // point in tree.
  938. //
  939. if ( SUCCEEDED( hresReturn ) &&
  940. (pmdrMDData->dwMDAttributes & METADATA_SECURE) &&
  941. (dwRetCode = IsReadAccessGranted( hMDHandle,
  942. (LPWSTR)pszMDPath,
  943. pmdrMDData ))
  944. != ERROR_SUCCESS )
  945. {
  946. hresReturn = RETURNCODETOHRESULT( dwRetCode );
  947. }
  948. if ( !fRequestedInheritedStatus )
  949. {
  950. pmdrMDData->dwMDAttributes &= ~METADATA_ISINHERITED;
  951. }
  952. //
  953. // if metadata secure, check access allowed to secure properties
  954. //
  955. if ( SUCCEEDED( hresReturn ) &&
  956. (pmdrMDData->dwMDAttributes & METADATA_SECURE) &&
  957. !fEnableSecureAccess)
  958. {
  959. *pdwMDRequiredDataLen = 0;
  960. pmdrMDData->dwMDDataLen = 0;
  961. hresReturn = RETURNCODETOHRESULT( ERROR_ACCESS_DENIED );
  962. }
  963. }
  964. }
  965. return hresReturn;
  966. }
  967. HRESULT STDMETHODCALLTYPE
  968. CADMCOMW::DeleteData(
  969. METADATA_HANDLE hMDHandle,
  970. LPCWSTR pszMDPath,
  971. DWORD dwMDIdentifier,
  972. DWORD dwMDDataType)
  973. /*++
  974. Routine Description:
  975. Deletes a data object.
  976. Arguments:
  977. hMDHandle - open handle
  978. pszMDPath - path of the meta object with which this data is associated
  979. dwMDIdentifier - identifier of the data to remove
  980. dwMDDataType - optional type of the data to remove
  981. Return Value:
  982. Status.
  983. --*/
  984. {
  985. HRESULT hresReturn = S_OK;
  986. METADATA_HANDLE hActualHandle;
  987. if (dwMDDataType >= INVALID_END_METADATA)
  988. {
  989. hresReturn = E_INVALIDARG;
  990. }
  991. else
  992. {
  993. //
  994. // lookup and access check
  995. //
  996. hresReturn = LookupAndAccessCheck(hMDHandle,
  997. &hActualHandle,
  998. pszMDPath,
  999. dwMDIdentifier,
  1000. METADATA_PERMISSION_WRITE);
  1001. if (SUCCEEDED(hresReturn))
  1002. {
  1003. if ( !AdminAclNotifySetOrDeleteProp(
  1004. hMDHandle,
  1005. dwMDIdentifier ) )
  1006. {
  1007. DBGPRINTF(( DBG_CONTEXT,
  1008. "[CADMCOMW::DeleteData] AdminAclNotifySetOrDel failed, error %lx\n",
  1009. GetLastError() ));
  1010. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  1011. }
  1012. else
  1013. {
  1014. //
  1015. // call metadata com api
  1016. //
  1017. hresReturn = m_pMdObject->ComMDDeleteMetaDataW( hActualHandle,
  1018. pszMDPath,
  1019. dwMDIdentifier,
  1020. dwMDDataType );
  1021. }
  1022. }
  1023. }
  1024. return hresReturn;
  1025. }
  1026. HRESULT STDMETHODCALLTYPE
  1027. CADMCOMW::EnumData(
  1028. METADATA_HANDLE hMDHandle,
  1029. LPCWSTR pszMDPath,
  1030. PMETADATA_RECORD pmdrMDData,
  1031. DWORD dwMDEnumDataIndex,
  1032. DWORD *pdwMDRequiredDataLen)
  1033. /*++
  1034. Routine Description:
  1035. Enumerate properties of object.
  1036. Arguments:
  1037. hMDHandle - open handle
  1038. pszMDPath - path of the meta object with which this data is associated
  1039. pmdrMDData - data structure
  1040. pdwMDRequiredDataLen - updated with required length
  1041. Return Value:
  1042. Status.
  1043. --*/
  1044. {
  1045. HRESULT hresReturn = S_OK;
  1046. METADATA_HANDLE hActualHandle;
  1047. BOOL fSecure;
  1048. BOOL fRequestedInheritedStatus;
  1049. DWORD dwRetCode;
  1050. if ((pmdrMDData == NULL) ||
  1051. ((pmdrMDData->dwMDDataLen != 0) && (pmdrMDData->pbMDData == NULL)) ||
  1052. !CheckGetAttributes(pmdrMDData->dwMDAttributes) ||
  1053. (pmdrMDData->dwMDDataType >= INVALID_END_METADATA))
  1054. {
  1055. hresReturn = E_INVALIDARG;
  1056. }
  1057. else
  1058. {
  1059. //
  1060. // lookup and access check
  1061. //
  1062. hresReturn = LookupAndAccessCheck(hMDHandle,
  1063. &hActualHandle,
  1064. pszMDPath,
  1065. 0,
  1066. METADATA_PERMISSION_READ,
  1067. &fSecure);
  1068. if (SUCCEEDED(hresReturn))
  1069. {
  1070. fRequestedInheritedStatus = pmdrMDData->dwMDAttributes & METADATA_ISINHERITED;
  1071. pmdrMDData->dwMDAttributes |= METADATA_ISINHERITED;
  1072. //
  1073. // call metadata com api
  1074. //
  1075. hresReturn = m_pMdObject->ComMDEnumMetaDataW( hActualHandle,
  1076. pszMDPath,
  1077. pmdrMDData,
  1078. dwMDEnumDataIndex,
  1079. pdwMDRequiredDataLen );
  1080. //
  1081. // if metadata is secure, check if can access this property from
  1082. // where it is defined, i.e using the ACL visible at the definition
  1083. // point in tree.
  1084. //
  1085. if ( SUCCEEDED( hresReturn ) &&
  1086. (pmdrMDData->dwMDAttributes & METADATA_SECURE) &&
  1087. (dwRetCode = IsReadAccessGranted( hMDHandle,
  1088. (LPWSTR)pszMDPath,
  1089. pmdrMDData ))
  1090. != ERROR_SUCCESS )
  1091. {
  1092. hresReturn = RETURNCODETOHRESULT( dwRetCode );
  1093. if ( !pmdrMDData->dwMDDataTag )
  1094. {
  1095. memset( pmdrMDData->pbMDData, 0x0, pmdrMDData->dwMDDataLen );
  1096. }
  1097. }
  1098. if ( !fRequestedInheritedStatus )
  1099. {
  1100. pmdrMDData->dwMDAttributes &= ~METADATA_ISINHERITED;
  1101. }
  1102. if ( !fSecure && SUCCEEDED(hresReturn) )
  1103. {
  1104. if ( pmdrMDData->dwMDAttributes & METADATA_SECURE )
  1105. {
  1106. hresReturn = RETURNCODETOHRESULT( ERROR_ACCESS_DENIED );
  1107. if ( !pmdrMDData->dwMDDataTag )
  1108. {
  1109. memset( pmdrMDData->pbMDData, 0x0, pmdrMDData->dwMDDataLen );
  1110. }
  1111. }
  1112. }
  1113. }
  1114. }
  1115. return hresReturn;
  1116. }
  1117. HRESULT STDMETHODCALLTYPE
  1118. CADMCOMW::GetAllData(
  1119. METADATA_HANDLE hMDHandle,
  1120. LPCWSTR pszMDPath,
  1121. DWORD dwMDAttributes,
  1122. DWORD dwMDUserType,
  1123. DWORD dwMDDataType,
  1124. DWORD *pdwMDNumDataEntries,
  1125. DWORD *pdwMDDataSetNumber,
  1126. DWORD dwMDBufferSize,
  1127. unsigned char *pbMDBuffer,
  1128. DWORD *pdwMDRequiredBufferSize)
  1129. /*++
  1130. Routine Description:
  1131. Gets all data associated with a Meta Object
  1132. Arguments:
  1133. hMDHandle - open handle
  1134. pszMDPath - path of the meta object with which this data is associated
  1135. dwMDAttributes - flags for the data
  1136. dwMDUserType - user Type for the data
  1137. dwMDDataType - type of the data
  1138. pdwMDNumDataEntries - number of entries copied to Buffer
  1139. pdwMDDataSetNumber - number associated with this data set
  1140. dwMDBufferSize - size in bytes of buffer
  1141. pbMDBuffer - buffer to store the data
  1142. pdwMDRequiredBufferSize - updated with required length of buffer
  1143. Return Value:
  1144. Status.
  1145. --*/
  1146. {
  1147. HRESULT hresReturn = S_OK;
  1148. METADATA_HANDLE hActualHandle;
  1149. BOOL fSecure;
  1150. BOOL fRequestedInheritedStatus;
  1151. if ((pdwMDNumDataEntries == NULL) || ((dwMDBufferSize != 0) && (pbMDBuffer == NULL)) ||
  1152. !CheckGetAttributes(dwMDAttributes) ||
  1153. (dwMDDataType >= INVALID_END_METADATA))
  1154. {
  1155. hresReturn = E_INVALIDARG;
  1156. }
  1157. else
  1158. {
  1159. //
  1160. // lookup and access check
  1161. //
  1162. hresReturn = LookupAndAccessCheck(hMDHandle,
  1163. &hActualHandle,
  1164. pszMDPath,
  1165. AAC_GETALL,
  1166. METADATA_PERMISSION_READ,
  1167. &fSecure );
  1168. if (SUCCEEDED(hresReturn))
  1169. {
  1170. fRequestedInheritedStatus = dwMDAttributes & METADATA_ISINHERITED;
  1171. dwMDAttributes |= METADATA_ISINHERITED;
  1172. //
  1173. // call metadata com api
  1174. //
  1175. hresReturn = m_pMdObject->ComMDGetAllMetaDataW( hActualHandle,
  1176. pszMDPath,
  1177. dwMDAttributes,
  1178. dwMDUserType,
  1179. dwMDDataType,
  1180. pdwMDNumDataEntries,
  1181. pdwMDDataSetNumber,
  1182. dwMDBufferSize,
  1183. pbMDBuffer,
  1184. pdwMDRequiredBufferSize );
  1185. if ( SUCCEEDED(hresReturn) )
  1186. {
  1187. PMETADATA_GETALL_RECORD pMDRecord;
  1188. DWORD iP;
  1189. //
  1190. // Scan for secure properties
  1191. // For such properties, check if user has access to it using following rules:
  1192. // - must have right to access secure properties in ACE
  1193. // - must have access to property using ACL visible where property is defined
  1194. // if no access to property then remove it from list of returned properties
  1195. pMDRecord = (PMETADATA_GETALL_RECORD)pbMDBuffer;
  1196. for ( iP = 0 ; iP < *pdwMDNumDataEntries ; )
  1197. {
  1198. if ( pMDRecord->dwMDAttributes & METADATA_SECURE )
  1199. {
  1200. if ( !fSecure ||
  1201. IsReadAccessGranted( hMDHandle,
  1202. (LPWSTR)pszMDPath,
  1203. (PMETADATA_RECORD)pMDRecord ) != ERROR_SUCCESS )
  1204. {
  1205. //
  1206. // remove this property from METADATA_RECORD list,
  1207. // zero out content
  1208. //
  1209. memset( pbMDBuffer + pMDRecord->dwMDDataOffset,
  1210. 0x0,
  1211. pMDRecord->dwMDDataLen );
  1212. --*pdwMDNumDataEntries;
  1213. memmove( pMDRecord,
  1214. pMDRecord + 1,
  1215. sizeof(METADATA_GETALL_RECORD) * (*pdwMDNumDataEntries-iP) );
  1216. continue;
  1217. }
  1218. }
  1219. if ( !fRequestedInheritedStatus )
  1220. {
  1221. pMDRecord->dwMDAttributes &= ~METADATA_ISINHERITED;
  1222. }
  1223. ++iP;
  1224. ++pMDRecord;
  1225. }
  1226. }
  1227. }
  1228. }
  1229. return hresReturn;
  1230. }
  1231. HRESULT STDMETHODCALLTYPE
  1232. CADMCOMW::DeleteAllData(
  1233. METADATA_HANDLE hMDHandle,
  1234. LPCWSTR pszMDPath,
  1235. DWORD dwMDUserType,
  1236. DWORD dwMDDataType)
  1237. {
  1238. HRESULT hresReturn = S_OK;
  1239. METADATA_HANDLE hActualHandle;
  1240. if (dwMDDataType >= INVALID_END_METADATA)
  1241. {
  1242. hresReturn = E_INVALIDARG;
  1243. }
  1244. else
  1245. {
  1246. //
  1247. // lookup and access check
  1248. //
  1249. hresReturn = LookupAndAccessCheck(hMDHandle,
  1250. &hActualHandle,
  1251. pszMDPath,
  1252. 0,
  1253. METADATA_PERMISSION_WRITE);
  1254. if (SUCCEEDED(hresReturn))
  1255. {
  1256. //
  1257. // call metadata com api
  1258. //
  1259. hresReturn = m_pMdObject->ComMDDeleteAllMetaDataW( hActualHandle,
  1260. pszMDPath,
  1261. dwMDUserType,
  1262. dwMDDataType );
  1263. }
  1264. }
  1265. return hresReturn;
  1266. }
  1267. HRESULT STDMETHODCALLTYPE
  1268. CADMCOMW::CopyData(
  1269. METADATA_HANDLE hMDSourceHandle,
  1270. LPCWSTR pszMDSourcePath,
  1271. METADATA_HANDLE hMDDestHandle,
  1272. LPCWSTR pszMDDestPath,
  1273. DWORD dwMDAttributes,
  1274. DWORD dwMDUserType,
  1275. DWORD dwMDDataType,
  1276. BOOL bMDCopyFlag)
  1277. /*++
  1278. Routine Description:
  1279. Copies or moves data associated with the source object to the destination
  1280. object.
  1281. Arguments:
  1282. hMDSourceHandle - open handle
  1283. pszMDSourcePath - path of the meta object with which then source data is
  1284. associated
  1285. hMDDestHandle - handle returned by MDOpenKey with write permission
  1286. pszMDDestPath - path of the meta object for data to be copied to
  1287. dwMDAttributes - flags for the data
  1288. dwMDUserType - user Type for the data
  1289. dwMDDataType - optional type of the data to copy
  1290. bMDCopyFlag - if true, data will be copied; if false, data will be moved.
  1291. Return Value:
  1292. Status.
  1293. --*/
  1294. {
  1295. HRESULT hresReturn = S_OK;
  1296. METADATA_HANDLE hSActualHandle;
  1297. METADATA_HANDLE hDActualHandle;
  1298. if (((!bMDCopyFlag) && (dwMDAttributes & METADATA_INHERIT)) ||
  1299. ((dwMDAttributes & METADATA_PARTIAL_PATH) && !(dwMDAttributes & METADATA_INHERIT)))
  1300. {
  1301. hresReturn = E_INVALIDARG;
  1302. }
  1303. else
  1304. {
  1305. //
  1306. // lookup and access check source
  1307. //
  1308. if (bMDCopyFlag)
  1309. {
  1310. hresReturn = LookupAndAccessCheck(hMDSourceHandle,
  1311. &hSActualHandle,
  1312. pszMDSourcePath,
  1313. 0,
  1314. METADATA_PERMISSION_READ);
  1315. }
  1316. else
  1317. {
  1318. //
  1319. // Deleting source data, so need delete permission
  1320. //
  1321. hresReturn = LookupAndAccessCheck(hMDSourceHandle,
  1322. &hSActualHandle,
  1323. pszMDSourcePath,
  1324. 0,
  1325. METADATA_PERMISSION_WRITE);
  1326. }
  1327. if (SUCCEEDED(hresReturn))
  1328. {
  1329. //
  1330. // lookup and access check dest
  1331. //
  1332. hresReturn = LookupAndAccessCheck(hMDDestHandle,
  1333. &hDActualHandle,
  1334. pszMDDestPath,
  1335. 0,
  1336. METADATA_PERMISSION_WRITE);
  1337. if (SUCCEEDED(hresReturn))
  1338. {
  1339. //
  1340. // call metadata com api
  1341. //
  1342. hresReturn = m_pMdObject->ComMDCopyMetaDataW(hSActualHandle,
  1343. pszMDSourcePath,
  1344. hDActualHandle,
  1345. pszMDDestPath,
  1346. dwMDAttributes,
  1347. dwMDUserType,
  1348. dwMDDataType,
  1349. bMDCopyFlag );
  1350. }
  1351. }
  1352. }
  1353. return hresReturn;
  1354. }
  1355. HRESULT STDMETHODCALLTYPE
  1356. CADMCOMW::GetDataPaths(
  1357. METADATA_HANDLE hMDHandle,
  1358. LPCWSTR pszMDPath,
  1359. DWORD dwMDIdentifier,
  1360. DWORD dwMDDataType,
  1361. DWORD dwMDBufferSize,
  1362. LPWSTR pszMDBuffer,
  1363. DWORD *pdwMDRequiredBufferSize)
  1364. {
  1365. HRESULT hresReturn = S_OK;
  1366. METADATA_HANDLE hActualHandle;
  1367. BOOL fSecure;
  1368. if (((pszMDBuffer == NULL) && (dwMDBufferSize != 0)) ||
  1369. (dwMDDataType >= INVALID_END_METADATA) ||
  1370. (pdwMDRequiredBufferSize == NULL))
  1371. {
  1372. hresReturn = E_INVALIDARG;
  1373. }
  1374. else
  1375. {
  1376. //
  1377. // lookup and access check
  1378. //
  1379. hresReturn = LookupAndAccessCheck(hMDHandle,
  1380. &hActualHandle,
  1381. pszMDPath,
  1382. 0,
  1383. METADATA_PERMISSION_READ,
  1384. &fSecure);
  1385. if (SUCCEEDED(hresReturn))
  1386. {
  1387. //
  1388. // call metadata com api
  1389. //
  1390. hresReturn = m_pMdObject->ComMDGetMetaDataPathsW( hActualHandle,
  1391. pszMDPath,
  1392. dwMDIdentifier,
  1393. dwMDDataType,
  1394. dwMDBufferSize,
  1395. pszMDBuffer,
  1396. pdwMDRequiredBufferSize );
  1397. }
  1398. }
  1399. return hresReturn;
  1400. }
  1401. HRESULT STDMETHODCALLTYPE
  1402. CADMCOMW::OpenKey(
  1403. METADATA_HANDLE hMDHandle,
  1404. LPCWSTR pszMDPath,
  1405. DWORD dwMDAccessRequested,
  1406. DWORD dwMDTimeOut,
  1407. PMETADATA_HANDLE phMDNewHandle)
  1408. /*++
  1409. Routine Description:
  1410. Opens a meta object for read and/or write access.
  1411. Arguments:
  1412. hMDHandle - open handle
  1413. pszMDPath - path of the object to be opened
  1414. dwMDAccessRequested - permissions requested
  1415. dwMDTimeOut - time to block waiting for open to succeed, in miliseconds.
  1416. phMDNewHandle - handle to be passed to other MD routines
  1417. Return Value:
  1418. Status.
  1419. --*/
  1420. {
  1421. HRESULT hresReturn = S_OK;
  1422. // If caller watch is not initialized
  1423. if ( !IsCallerWatchInitialized() )
  1424. {
  1425. // Initialize the caller watch
  1426. hresReturn = InitializeCallerWatch();
  1427. if ( FAILED( hresReturn ) )
  1428. {
  1429. return hresReturn;
  1430. }
  1431. }
  1432. hresReturn = OpenKeyHelper(hMDHandle, pszMDPath, dwMDAccessRequested, dwMDTimeOut, phMDNewHandle);
  1433. return hresReturn;
  1434. }
  1435. HRESULT STDMETHODCALLTYPE
  1436. CADMCOMW::CloseKey(
  1437. METADATA_HANDLE hMDHandle)
  1438. /*++
  1439. Routine Description:
  1440. Closes a handle to a meta object.
  1441. Arguments:
  1442. hMDHandle - open handle
  1443. Return Value:
  1444. Status.
  1445. --*/
  1446. {
  1447. HRESULT hresReturn = S_OK;
  1448. METADATA_HANDLE hActualHandle;
  1449. DWORD dwTemp;
  1450. COpenHandle *pohHandle;
  1451. if ((hMDHandle == METADATA_MASTER_ROOT_HANDLE))
  1452. {
  1453. hresReturn = E_HANDLE;
  1454. }
  1455. else
  1456. {
  1457. //
  1458. // Map Admin Handle to Actual Handle
  1459. //
  1460. if( (dwTemp = Lookup( hMDHandle,
  1461. &hActualHandle,
  1462. &pohHandle )) != ERROR_SUCCESS )
  1463. {
  1464. hresReturn = RETURNCODETOHRESULT(dwTemp);
  1465. }
  1466. else
  1467. {
  1468. //
  1469. // call metadata com api
  1470. //
  1471. hresReturn = m_pMdObject->ComMDCloseMetaObject( hActualHandle );
  1472. pohHandle->Release(this);
  1473. //
  1474. // Remove node from handle table
  1475. //
  1476. if (SUCCEEDED(hresReturn))
  1477. {
  1478. pohHandle->Release(this);
  1479. }
  1480. }
  1481. }
  1482. return hresReturn;
  1483. }
  1484. HRESULT STDMETHODCALLTYPE
  1485. CADMCOMW::ChangePermissions(
  1486. METADATA_HANDLE hMDHandle,
  1487. DWORD dwMDTimeOut,
  1488. DWORD dwMDAccessRequested)
  1489. /*++
  1490. Routine Description:
  1491. Changes permissions on an open meta object handle.
  1492. Arguments:
  1493. hMDHandle - handle to be modified
  1494. dwMDTimeOut - time to block waiting for open to succeed, in miliseconds.
  1495. dwMDAccessRequested - requested permissions
  1496. Return Value:
  1497. Status.
  1498. --*/
  1499. {
  1500. HRESULT hr = S_OK;
  1501. METADATA_HANDLE hActualHandle;
  1502. if ( hMDHandle == METADATA_MASTER_ROOT_HANDLE )
  1503. {
  1504. hr = E_HANDLE;
  1505. goto exit;
  1506. }
  1507. if ( ( ( dwMDAccessRequested & ( METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) == 0 ) ||
  1508. ( ( dwMDAccessRequested & ~( METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) != 0 ) )
  1509. {
  1510. hr = E_INVALIDARG;
  1511. goto exit;
  1512. }
  1513. //
  1514. // Map Admin Handle to Actual Handle
  1515. // and check access
  1516. //
  1517. hr = LookupAndAccessCheck( hMDHandle,
  1518. &hActualHandle,
  1519. L"",
  1520. 0,
  1521. dwMDAccessRequested );
  1522. if( FAILED( hr ) )
  1523. {
  1524. goto exit;
  1525. }
  1526. //
  1527. // call metadata com api
  1528. //
  1529. hr = m_pMdObject->ComMDChangePermissions( hActualHandle,
  1530. dwMDTimeOut,
  1531. dwMDAccessRequested );
  1532. exit:
  1533. return hr;
  1534. }
  1535. HRESULT STDMETHODCALLTYPE
  1536. CADMCOMW::SaveData( )
  1537. /*++
  1538. Routine Description:
  1539. Saves all data changed since the last load or save to permanent storage.
  1540. Arguments:
  1541. None.
  1542. Return Value:
  1543. Status.
  1544. --*/
  1545. {
  1546. HRESULT hr = S_OK;
  1547. METADATA_HANDLE mdhRoot = METADATA_MASTER_ROOT_HANDLE;
  1548. METADATA_HANDLE hActualHandle;
  1549. //
  1550. // lookup and access check
  1551. //
  1552. hr = LookupAndAccessCheck( METADATA_MASTER_ROOT_HANDLE,
  1553. &hActualHandle,
  1554. L"",
  1555. 0,
  1556. METADATA_PERMISSION_READ);
  1557. if ( FAILED( hr ) )
  1558. {
  1559. goto exit;
  1560. }
  1561. //
  1562. // First try to lock the tree
  1563. //
  1564. hr = m_pMdObject->ComMDOpenMetaObjectW( METADATA_MASTER_ROOT_HANDLE,
  1565. NULL,
  1566. METADATA_PERMISSION_READ,
  1567. DEFAULT_SAVE_TIMEOUT,
  1568. &mdhRoot );
  1569. if ( FAILED( hr ) )
  1570. {
  1571. goto exit;
  1572. }
  1573. //
  1574. // call metadata com api
  1575. //
  1576. hr = m_pMdObject->ComMDSaveData(mdhRoot);
  1577. m_pMdObject->ComMDCloseMetaObject(mdhRoot);
  1578. exit:
  1579. return hr;
  1580. }
  1581. HRESULT STDMETHODCALLTYPE
  1582. CADMCOMW::GetHandleInfo(
  1583. METADATA_HANDLE hMDHandle,
  1584. PMETADATA_HANDLE_INFO pmdhiInfo)
  1585. /*++
  1586. Routine Description:
  1587. Gets the information associated with a handle.
  1588. Arguments:
  1589. hMDHandle - handle to get information about
  1590. pmdhiInfo - structure filled in with the information
  1591. Return Value:
  1592. Status.
  1593. --*/
  1594. {
  1595. HRESULT hresReturn = S_OK;
  1596. METADATA_HANDLE hActualHandle;
  1597. DWORD dwRetCode = ERROR_SUCCESS;
  1598. if (pmdhiInfo == NULL)
  1599. {
  1600. hresReturn = E_INVALIDARG;
  1601. }
  1602. else
  1603. {
  1604. //
  1605. // Map Admin Handle to Actual Handle
  1606. //
  1607. if( (dwRetCode = Lookup( hMDHandle,
  1608. &hActualHandle
  1609. )) != ERROR_SUCCESS )
  1610. {
  1611. hresReturn = RETURNCODETOHRESULT(dwRetCode);
  1612. }
  1613. else
  1614. {
  1615. //
  1616. // call metadata com api
  1617. //
  1618. hresReturn = m_pMdObject->ComMDGetHandleInfo( hActualHandle,
  1619. pmdhiInfo );
  1620. }
  1621. }
  1622. return hresReturn;
  1623. }
  1624. HRESULT STDMETHODCALLTYPE
  1625. CADMCOMW::GetSystemChangeNumber(
  1626. DWORD *pdwSystemChangeNumber)
  1627. /*++
  1628. Routine Description:
  1629. Gets the System Change Number.
  1630. Arguments:
  1631. pdwSystemChangeNumber - system change number
  1632. Return Value:
  1633. Status.
  1634. --*/
  1635. {
  1636. HRESULT hr = S_OK;
  1637. METADATA_HANDLE hActualHandle;
  1638. // Check args
  1639. if ( pdwSystemChangeNumber == NULL )
  1640. {
  1641. hr = E_INVALIDARG;
  1642. goto exit;
  1643. }
  1644. //
  1645. // lookup and access check
  1646. //
  1647. hr = LookupAndAccessCheck( METADATA_MASTER_ROOT_HANDLE,
  1648. &hActualHandle,
  1649. L"",
  1650. 0,
  1651. METADATA_PERMISSION_READ );
  1652. if ( FAILED( hr ) )
  1653. {
  1654. goto exit;
  1655. }
  1656. //
  1657. // call metadata com api
  1658. //
  1659. hr = m_pMdObject->ComMDGetSystemChangeNumber( pdwSystemChangeNumber );
  1660. exit:
  1661. return hr;
  1662. }
  1663. HRESULT STDMETHODCALLTYPE
  1664. CADMCOMW::GetDataSetNumber(
  1665. METADATA_HANDLE hMDHandle,
  1666. LPCWSTR pszMDPath,
  1667. DWORD *pdwMDDataSetNumber)
  1668. /*++
  1669. Routine Description:
  1670. Gets all the data set number associated with a Meta Object.
  1671. Arguments:
  1672. hMDHandle - open handle
  1673. pszMDPath - path of the meta object with which this data is associated
  1674. pdwMDDataSetNumber - number associated with this data set
  1675. Return Value:
  1676. Status.
  1677. --*/
  1678. {
  1679. HRESULT hresReturn = S_OK;
  1680. METADATA_HANDLE hActualHandle;
  1681. if (pdwMDDataSetNumber == NULL)
  1682. {
  1683. hresReturn = E_INVALIDARG;
  1684. }
  1685. else
  1686. {
  1687. //
  1688. // lookup and access check
  1689. //
  1690. hresReturn = LookupAndAccessCheck(hMDHandle,
  1691. &hActualHandle,
  1692. pszMDPath,
  1693. 0,
  1694. METADATA_PERMISSION_READ);
  1695. if (SUCCEEDED(hresReturn))
  1696. {
  1697. //
  1698. // call metadata com api
  1699. //
  1700. hresReturn = m_pMdObject->ComMDGetDataSetNumberW( hActualHandle,
  1701. pszMDPath,
  1702. pdwMDDataSetNumber );
  1703. }
  1704. }
  1705. return hresReturn;
  1706. }
  1707. HRESULT STDMETHODCALLTYPE
  1708. CADMCOMW::SetLastChangeTime(
  1709. METADATA_HANDLE hMDHandle,
  1710. LPCWSTR pszMDPath,
  1711. PFILETIME pftMDLastChangeTime,
  1712. BOOL bLocalTime)
  1713. /*++
  1714. Routine Description:
  1715. Set the last change time associated with a Meta Object.
  1716. Arguments:
  1717. hMDHandle - open handle
  1718. pszMDPath - path of the affected meta object
  1719. pftMDLastChangeTime - new change time for the meta object
  1720. Return Value:
  1721. Status.
  1722. --*/
  1723. {
  1724. HRESULT hr = S_OK;
  1725. BOOL fRet;
  1726. DWORD dwError;
  1727. METADATA_HANDLE hActualHandle;
  1728. FILETIME ftTime;
  1729. FILETIME *pftTime = NULL;
  1730. // Check arhs
  1731. if ( ( pftMDLastChangeTime == NULL ) ||
  1732. ( hMDHandle == METADATA_MASTER_ROOT_HANDLE ) )
  1733. {
  1734. hr = E_INVALIDARG;
  1735. goto exit;
  1736. }
  1737. // lookup and access check
  1738. hr = LookupAndAccessCheck( hMDHandle,
  1739. &hActualHandle,
  1740. pszMDPath,
  1741. 0,
  1742. METADATA_PERMISSION_WRITE );
  1743. if ( FAILED( hr ) )
  1744. {
  1745. goto exit;
  1746. }
  1747. if ( bLocalTime )
  1748. {
  1749. fRet = LocalFileTimeToFileTime( pftMDLastChangeTime, &ftTime );
  1750. if ( !fRet )
  1751. {
  1752. dwError = GetLastError();
  1753. hr = HRESULT_FROM_WIN32( dwError );
  1754. goto exit;
  1755. }
  1756. pftTime = &ftTime;
  1757. }
  1758. else
  1759. {
  1760. pftTime = pftMDLastChangeTime;
  1761. }
  1762. // call metadata com api
  1763. hr = m_pMdObject->ComMDSetLastChangeTimeW( hActualHandle,
  1764. pszMDPath,
  1765. pftTime );
  1766. if ( FAILED( hr ) )
  1767. {
  1768. goto exit;
  1769. }
  1770. exit:
  1771. return hr;
  1772. }
  1773. HRESULT STDMETHODCALLTYPE
  1774. CADMCOMW::GetLastChangeTime(
  1775. METADATA_HANDLE hMDHandle,
  1776. LPCWSTR pszMDPath,
  1777. PFILETIME pftMDLastChangeTime,
  1778. BOOL bLocalTime)
  1779. /*++
  1780. Routine Description:
  1781. Set the last change time associated with a Meta Object.
  1782. Arguments:
  1783. Handle - open handle
  1784. pszMDPath - path of the affected meta object
  1785. pftMDLastChangeTime - place to return the change time for the meta object
  1786. Return Value:
  1787. Status.
  1788. --*/
  1789. {
  1790. HRESULT hresReturn = S_OK;
  1791. METADATA_HANDLE hActualHandle;
  1792. FILETIME ftTime;
  1793. if (pftMDLastChangeTime == NULL)
  1794. {
  1795. hresReturn = E_INVALIDARG;
  1796. }
  1797. else
  1798. {
  1799. //
  1800. // lookup and access check
  1801. //
  1802. hresReturn = LookupAndAccessCheck(hMDHandle,
  1803. &hActualHandle,
  1804. pszMDPath,
  1805. 0,
  1806. METADATA_PERMISSION_READ);
  1807. if (SUCCEEDED(hresReturn))
  1808. {
  1809. //
  1810. // call metadata com api
  1811. //
  1812. hresReturn = m_pMdObject->ComMDGetLastChangeTimeW( hActualHandle,
  1813. pszMDPath,
  1814. &ftTime );
  1815. if (bLocalTime)
  1816. {
  1817. if (!FileTimeToLocalFileTime(&ftTime, pftMDLastChangeTime))
  1818. {
  1819. hresReturn = E_UNEXPECTED;
  1820. }
  1821. }
  1822. else
  1823. {
  1824. *pftMDLastChangeTime = ftTime;
  1825. }
  1826. }
  1827. }
  1828. return hresReturn;
  1829. }
  1830. HRESULT
  1831. CADMCOMW::BackupHelper(
  1832. LPCWSTR pszMDBackupLocation,
  1833. DWORD dwMDVersion,
  1834. DWORD dwMDFlags,
  1835. LPCWSTR pszPasswd)
  1836. {
  1837. HRESULT hresReturn = S_OK;
  1838. HRESULT hresWarning = S_OK;
  1839. METADATA_HANDLE mdhRoot = METADATA_MASTER_ROOT_HANDLE;
  1840. if ( !AdminAclAccessCheck( m_pMdObject,
  1841. (LPVOID)this,
  1842. METADATA_MASTER_ROOT_HANDLE,
  1843. L"",
  1844. MD_ADMIN_ACL,
  1845. METADATA_PERMISSION_WRITE,
  1846. &g_ohMasterRootHandle ) )
  1847. {
  1848. DBGPRINTF(( DBG_CONTEXT,
  1849. "[CADMCOMW::Backup] AdminAclAccessCheck failed, error %lx\n",
  1850. GetLastError() ));
  1851. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  1852. }
  1853. else
  1854. {
  1855. if ((dwMDFlags & MD_BACKUP_SAVE_FIRST) != 0)
  1856. {
  1857. //
  1858. // First lock the tree
  1859. //
  1860. hresReturn = m_pMdObject->ComMDOpenMetaObjectW( METADATA_MASTER_ROOT_HANDLE,
  1861. NULL,
  1862. METADATA_PERMISSION_READ,
  1863. DEFAULT_SAVE_TIMEOUT,
  1864. &mdhRoot);
  1865. }
  1866. if (FAILED(hresReturn))
  1867. {
  1868. if ((dwMDFlags & MD_BACKUP_FORCE_BACKUP) != 0)
  1869. {
  1870. hresWarning = MD_WARNING_SAVE_FAILED;
  1871. hresReturn = ERROR_SUCCESS;
  1872. dwMDFlags &= ~(MD_BACKUP_FORCE_BACKUP | MD_BACKUP_SAVE_FIRST);
  1873. }
  1874. }
  1875. if (SUCCEEDED(hresReturn))
  1876. {
  1877. //
  1878. // call metadata com api
  1879. //
  1880. if( !pszPasswd )
  1881. {
  1882. hresReturn = m_pMdObject->ComMDBackupW(mdhRoot,
  1883. pszMDBackupLocation,
  1884. dwMDVersion,
  1885. dwMDFlags);
  1886. }
  1887. else
  1888. {
  1889. hresReturn = m_pMdObject->ComMDBackupWithPasswdW(mdhRoot,
  1890. pszMDBackupLocation,
  1891. dwMDVersion,
  1892. dwMDFlags,
  1893. pszPasswd);
  1894. }
  1895. if ((dwMDFlags & MD_BACKUP_SAVE_FIRST) != 0)
  1896. {
  1897. m_pMdObject->ComMDCloseMetaObject(mdhRoot);
  1898. }
  1899. }
  1900. if (hresReturn == ERROR_SUCCESS)
  1901. {
  1902. hresReturn = hresWarning;
  1903. }
  1904. }
  1905. return hresReturn;
  1906. }
  1907. #define MD_DEFAULT_BACKUP_LOCATION_W L"MDBackUp"
  1908. HRESULT
  1909. CADMCOMW::RestoreHelper(
  1910. LPCWSTR pszMDBackupLocation,
  1911. DWORD dwMDVersion,
  1912. DWORD dwMDMinorVersion,
  1913. LPCWSTR pszPasswd,
  1914. DWORD dwMDFlags,
  1915. DWORD dwRestoreType) // RESTORE_HISTORY or RESTORE_BACKUP
  1916. {
  1917. HRESULT hr = S_OK;
  1918. DWORD dwError;
  1919. BOOL fRet;
  1920. BUFFER bufDependentServices;
  1921. DWORD cServices = 0;
  1922. WCHAR pszEnumLocation[MD_BACKUP_MAX_LEN] = {0};
  1923. DWORD dwEnumVersion;
  1924. DWORD dwEnumMinorVersion;
  1925. FILETIME ftEnumTime;
  1926. DWORD i;
  1927. DWORD dwEnableHistory = FALSE;
  1928. DWORD dwEnableEWR = FALSE;
  1929. BOOL fEnableAclCache = FALSE;
  1930. // This should be called only internally, so passing wrong restore type is a bug
  1931. DBG_ASSERT( dwRestoreType == RESTORE_HISTORY || dwRestoreType == RESTORE_BACKUP );
  1932. // Check args
  1933. if ( ( dwRestoreType != RESTORE_HISTORY && dwRestoreType != RESTORE_BACKUP ) ||
  1934. ( dwRestoreType == RESTORE_BACKUP && pszMDBackupLocation == NULL ) ||
  1935. ( pszMDBackupLocation && wcslen(pszMDBackupLocation) >= MD_BACKUP_MAX_LEN ) )
  1936. {
  1937. hr = E_INVALIDARG;
  1938. goto exit;
  1939. }
  1940. // Check access
  1941. fRet = AdminAclAccessCheck( m_pMdObject,
  1942. (LPVOID)this,
  1943. METADATA_MASTER_ROOT_HANDLE,
  1944. L"",
  1945. MD_ADMIN_ACL,
  1946. METADATA_PERMISSION_WRITE,
  1947. &g_ohMasterRootHandle );
  1948. if ( !fRet )
  1949. {
  1950. dwError = GetLastError();
  1951. DBGPRINTF(( DBG_CONTEXT,
  1952. ( ( dwRestoreType == RESTORE_HISTORY ) ?
  1953. "[CADMCOMW::RestoreHistory] AdminAclAccessCheck failed, error %lx\n" :
  1954. "[CADMCOMW::Restore] AdminAclAccessCheck failed, error %lx\n" ),
  1955. dwError ));
  1956. hr = HRESULT_FROM_WIN32( dwError );
  1957. goto exit;
  1958. }
  1959. // Find the requested backup/history
  1960. for ( i = 0; SUCCEEDED( hr ); i++ )
  1961. {
  1962. if ( dwRestoreType == RESTORE_HISTORY )
  1963. {
  1964. if( pszMDBackupLocation != NULL )
  1965. {
  1966. wcscpy( pszEnumLocation, pszMDBackupLocation );
  1967. }
  1968. else
  1969. {
  1970. *pszEnumLocation = L'\0';
  1971. }
  1972. hr = m_pMdObject->ComMDEnumHistoryW( pszEnumLocation,
  1973. &dwEnumVersion,
  1974. &dwEnumMinorVersion,
  1975. &ftEnumTime,
  1976. i);
  1977. if ( FAILED( hr ) )
  1978. {
  1979. break;
  1980. }
  1981. if( dwMDFlags & MD_HISTORY_LATEST )
  1982. {
  1983. break;
  1984. }
  1985. else
  1986. {
  1987. if ( ( dwEnumVersion == dwMDVersion ) &&
  1988. ( dwEnumMinorVersion == dwMDMinorVersion ) )
  1989. {
  1990. break;
  1991. }
  1992. }
  1993. }
  1994. else
  1995. {
  1996. if( pszMDBackupLocation != NULL )
  1997. {
  1998. wcscpy( pszEnumLocation, pszMDBackupLocation );
  1999. }
  2000. else
  2001. {
  2002. wcscpy( pszEnumLocation, MD_DEFAULT_BACKUP_LOCATION_W );
  2003. }
  2004. hr = m_pMdObject->ComMDEnumBackupsW( pszEnumLocation,
  2005. &dwEnumVersion,
  2006. &ftEnumTime,
  2007. i);
  2008. if ( FAILED( hr ) )
  2009. {
  2010. break;
  2011. }
  2012. if ( ( dwEnumVersion == dwMDVersion ) ||
  2013. ( dwMDVersion == MD_BACKUP_HIGHEST_VERSION ) )
  2014. {
  2015. break;
  2016. }
  2017. }
  2018. }
  2019. // If we failed to find the requested backup/history
  2020. if ( FAILED( hr ) )
  2021. {
  2022. // If asked for an version that doesn't exist
  2023. // adjust the error code
  2024. if ( hr == HRESULT_FROM_WIN32( ERROR_NO_MORE_ITEMS ) )
  2025. {
  2026. if( dwRestoreType == RESTORE_HISTORY )
  2027. {
  2028. if( dwMDFlags & MD_HISTORY_LATEST )
  2029. {
  2030. hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  2031. }
  2032. else
  2033. {
  2034. hr = MD_ERROR_INVALID_VERSION;
  2035. }
  2036. }
  2037. else
  2038. {
  2039. hr = E_INVALIDARG;
  2040. }
  2041. }
  2042. goto exit;
  2043. }
  2044. //
  2045. // Looks like a valid metabase
  2046. //
  2047. // Disable History (and EWR) to prevent the dependent services creating
  2048. // history and deleting currently valid history files during their stoppping.
  2049. // Keep the current state of EnableHistory and EnableEWR, so we can restore
  2050. // them if restore fails.
  2051. hr = DisableHistory(&dwEnableHistory, &dwEnableEWR);
  2052. if ( FAILED( hr ) )
  2053. {
  2054. goto exit;
  2055. }
  2056. // Stop all dependent services, keeping their list so later we can start them again
  2057. hr = EnumAndStopDependentServices( &cServices, &bufDependentServices );
  2058. if ( FAILED( hr ) )
  2059. {
  2060. goto exit;
  2061. }
  2062. // Disable the Acl cache, since we are going to re-load the whole metabase
  2063. AdminAclDisableAclCache();
  2064. // Remember to re-enable it
  2065. fEnableAclCache = TRUE;
  2066. // Discard everything from the Acl caches
  2067. AdminAclFlushCache();
  2068. // Finally call the CMDCOM method
  2069. if( dwRestoreType == RESTORE_HISTORY )
  2070. {
  2071. hr = m_pMdObject->ComMDRestoreHistoryW( pszMDBackupLocation,
  2072. dwMDVersion,
  2073. dwMDMinorVersion,
  2074. dwMDFlags );
  2075. }
  2076. else
  2077. {
  2078. if( !pszPasswd )
  2079. {
  2080. hr = m_pMdObject->ComMDRestoreW( pszMDBackupLocation,
  2081. dwMDVersion,
  2082. dwMDFlags );
  2083. }
  2084. else
  2085. {
  2086. hr = m_pMdObject->ComMDRestoreWithPasswdW( pszMDBackupLocation,
  2087. dwMDVersion,
  2088. dwMDFlags,
  2089. pszPasswd );
  2090. }
  2091. }
  2092. if ( FAILED( hr ) )
  2093. {
  2094. goto exit;
  2095. }
  2096. //
  2097. // Issue TaylorW 4/10/2001
  2098. //
  2099. // After the restore, notify clients, as data has changed
  2100. // and all handles have become invalid
  2101. //
  2102. // Windows Bug 82423
  2103. //
  2104. // If restore succeed the values of the EnableHistory and EnableEWR are
  2105. // set as from the backup/history file, so we don't restore them.
  2106. dwEnableHistory = FALSE;
  2107. dwEnableEWR = FALSE;
  2108. exit:
  2109. // If something went wrong after we got the EnableHistoy and EnableEWR and
  2110. // at least one of them was not FALSE set them back
  2111. if ( dwEnableHistory || dwEnableEWR )
  2112. {
  2113. SetHistoryAndEWR( dwEnableHistory, dwEnableEWR );
  2114. }
  2115. // If we disable the acl cache
  2116. if ( fEnableAclCache )
  2117. {
  2118. // Re-enable it
  2119. AdminAclEnableAclCache();
  2120. }
  2121. // If we stopped any services
  2122. if ( cServices )
  2123. {
  2124. // Enable them back
  2125. StartDependentServices( cServices, (ENUM_SERVICE_STATUS*)bufDependentServices.QueryPtr() );
  2126. }
  2127. return hr;
  2128. }
  2129. HRESULT
  2130. CADMCOMW::EnumAndStopDependentServices(
  2131. DWORD *pcServices,
  2132. BUFFER *pbufDependentServices)
  2133. {
  2134. // Locals
  2135. HRESULT hr = S_OK;
  2136. DWORD dwError;
  2137. BOOL fRet;
  2138. SC_HANDLE schSCM = NULL;
  2139. SC_HANDLE schIISADMIN = NULL;
  2140. SC_HANDLE schDependent = NULL;
  2141. SERVICE_STATUS ssDependent;
  2142. DWORD dwBytesNeeded;
  2143. ENUM_SERVICE_STATUS *pessDependentServices = NULL;
  2144. DWORD cServices = 0;
  2145. DWORD i;
  2146. // Check args
  2147. DBG_ASSERT( ( pcServices != NULL ) && ( pbufDependentServices != NULL ) );
  2148. if ( ( pcServices == NULL ) || ( pbufDependentServices == NULL ) )
  2149. {
  2150. hr = E_INVALIDARG;
  2151. goto exit;
  2152. }
  2153. // Init
  2154. *pcServices = 0;
  2155. // Open SCM
  2156. schSCM = OpenSCManager( NULL,
  2157. NULL,
  2158. SC_MANAGER_ALL_ACCESS );
  2159. if ( schSCM == NULL )
  2160. {
  2161. dwError = GetLastError();
  2162. hr = HRESULT_FROM_WIN32( dwError );
  2163. goto exit;
  2164. }
  2165. // Open IISADMIN
  2166. schIISADMIN = OpenService( schSCM,
  2167. "IISADMIN",
  2168. STANDARD_RIGHTS_REQUIRED | SERVICE_ENUMERATE_DEPENDENTS );
  2169. if ( schIISADMIN == NULL )
  2170. {
  2171. dwError = GetLastError();
  2172. hr = HRESULT_FROM_WIN32( dwError );
  2173. goto exit;
  2174. }
  2175. pessDependentServices = (ENUM_SERVICE_STATUS*)pbufDependentServices->QueryPtr();
  2176. DBG_ASSERT( pessDependentServices );
  2177. fRet = EnumDependentServices( schIISADMIN,
  2178. SERVICE_ACTIVE,
  2179. pessDependentServices,
  2180. pbufDependentServices->QuerySize(),
  2181. &dwBytesNeeded,
  2182. &cServices );
  2183. // The buffer is too small?
  2184. if ( !fRet && ( GetLastError() == ERROR_MORE_DATA ) )
  2185. {
  2186. // Resize the buffer
  2187. fRet = pbufDependentServices->Resize( dwBytesNeeded );
  2188. if ( !fRet )
  2189. {
  2190. hr = E_OUTOFMEMORY;
  2191. goto exit;
  2192. }
  2193. // Retry the call
  2194. pessDependentServices = (ENUM_SERVICE_STATUS*)pbufDependentServices->QueryPtr();
  2195. DBG_ASSERT( pessDependentServices );
  2196. fRet = EnumDependentServices( schIISADMIN,
  2197. SERVICE_ACTIVE,
  2198. pessDependentServices,
  2199. dwBytesNeeded,
  2200. &dwBytesNeeded,
  2201. &cServices );
  2202. }
  2203. if ( !fRet )
  2204. {
  2205. dwError = GetLastError();
  2206. hr = HRESULT_FROM_WIN32( dwError );
  2207. goto exit;
  2208. }
  2209. //
  2210. // Open handles and send service control stop command
  2211. //
  2212. for ( i = 0; i < cServices; i++ )
  2213. {
  2214. if ( ( pessDependentServices[i].ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING ) ||
  2215. ( pessDependentServices[i].ServiceStatus.dwCurrentState == SERVICE_STOPPED ) )
  2216. {
  2217. continue;
  2218. }
  2219. schDependent = OpenService( schSCM,
  2220. pessDependentServices[i].lpServiceName,
  2221. SERVICE_ALL_ACCESS );
  2222. if ( schDependent == NULL )
  2223. {
  2224. continue;
  2225. }
  2226. //Stop Service
  2227. ControlService( schDependent, SERVICE_CONTROL_STOP, &ssDependent );
  2228. WaitForServiceStatus( schDependent, SERVICE_STOPPED );
  2229. CloseServiceHandle( schDependent );
  2230. schDependent = NULL;
  2231. }
  2232. // Return
  2233. *pcServices = cServices;
  2234. exit:
  2235. if ( schSCM != NULL )
  2236. {
  2237. CloseServiceHandle( schSCM );
  2238. schSCM = NULL;
  2239. }
  2240. if ( schIISADMIN != NULL )
  2241. {
  2242. CloseServiceHandle( schIISADMIN );
  2243. schIISADMIN = NULL;
  2244. }
  2245. if ( schDependent != NULL )
  2246. {
  2247. CloseServiceHandle( schDependent );
  2248. schDependent = NULL;
  2249. }
  2250. return hr;
  2251. }
  2252. HRESULT
  2253. CADMCOMW::StartDependentServices(
  2254. DWORD cServices,
  2255. ENUM_SERVICE_STATUS *pessDependentServices)
  2256. {
  2257. // Locals
  2258. HRESULT hr = S_OK;
  2259. DWORD dwError;
  2260. DWORD i = 0;
  2261. SC_HANDLE schSCM = NULL;
  2262. SC_HANDLE schDependent = NULL;
  2263. // Check agrs
  2264. if ( cServices == 0 )
  2265. {
  2266. // Nop
  2267. goto exit;
  2268. }
  2269. DBG_ASSERT( pessDependentServices != NULL );
  2270. if ( pessDependentServices == NULL )
  2271. {
  2272. hr = E_INVALIDARG;
  2273. goto exit;
  2274. }
  2275. // Open SCM
  2276. schSCM = OpenSCManager( NULL,
  2277. NULL,
  2278. SC_MANAGER_ALL_ACCESS );
  2279. if ( schSCM == NULL )
  2280. {
  2281. dwError = GetLastError();
  2282. hr = HRESULT_FROM_WIN32( dwError );
  2283. goto exit;
  2284. }
  2285. //
  2286. // Open handles and start services
  2287. // Use reverse order, since EnumServices orders
  2288. // list by dependencies
  2289. //
  2290. for ( i = 0; i < cServices; i++ )
  2291. {
  2292. if ( ( pessDependentServices[cServices-1-i].ServiceStatus.dwCurrentState == SERVICE_STOP_PENDING ) ||
  2293. ( pessDependentServices[cServices-1-i].ServiceStatus.dwCurrentState == SERVICE_STOPPED ) )
  2294. {
  2295. continue;
  2296. }
  2297. schDependent = OpenService( schSCM,
  2298. pessDependentServices[cServices-1-i].lpServiceName,
  2299. SERVICE_ALL_ACCESS );
  2300. if ( schDependent == NULL )
  2301. {
  2302. continue;
  2303. }
  2304. //Start Service
  2305. StartService( schDependent, 0, NULL );
  2306. WaitForServiceStatus( schDependent, SERVICE_RUNNING );
  2307. CloseServiceHandle( schDependent );
  2308. schDependent = NULL;
  2309. }
  2310. exit:
  2311. if ( schSCM != NULL )
  2312. {
  2313. CloseServiceHandle( schSCM );
  2314. schSCM = NULL;
  2315. }
  2316. if ( schDependent != NULL )
  2317. {
  2318. CloseServiceHandle( schDependent );
  2319. schDependent = NULL;
  2320. }
  2321. return hr;
  2322. }
  2323. HRESULT
  2324. CADMCOMW::SetHistoryAndEWR(
  2325. DWORD dwEnableHistory,
  2326. DWORD dwEnableEWR)
  2327. {
  2328. // Locals
  2329. HRESULT hr = S_OK;
  2330. METADATA_HANDLE mdhRoot = METADATA_MASTER_ROOT_HANDLE;
  2331. METADATA_RECORD mdrHistory = {
  2332. MD_ROOT_ENABLE_HISTORY,
  2333. METADATA_NO_ATTRIBUTES,
  2334. IIS_MD_UT_SERVER,
  2335. DWORD_METADATA,
  2336. sizeof(DWORD),
  2337. (BYTE*)&dwEnableHistory,
  2338. 0
  2339. };
  2340. METADATA_RECORD mdrEWR = {
  2341. MD_ROOT_ENABLE_EDIT_WHILE_RUNNING,
  2342. METADATA_NO_ATTRIBUTES,
  2343. IIS_MD_UT_SERVER,
  2344. DWORD_METADATA,
  2345. sizeof(DWORD),
  2346. (BYTE*)&dwEnableEWR,
  2347. 0
  2348. };
  2349. // Open the the root for writting
  2350. hr = m_pMdObject->ComMDOpenMetaObjectW( METADATA_MASTER_ROOT_HANDLE,
  2351. L"/LM",
  2352. METADATA_PERMISSION_WRITE,
  2353. DEFAULT_SAVE_TIMEOUT,
  2354. &mdhRoot );
  2355. if ( FAILED( hr ) )
  2356. {
  2357. goto exit;
  2358. }
  2359. // Set EWR 1st
  2360. hr = m_pMdObject->ComMDSetMetaDataW( mdhRoot,
  2361. L"",
  2362. &mdrEWR );
  2363. if ( FAILED( hr ) )
  2364. {
  2365. goto exit;
  2366. }
  2367. // Set History after EWR
  2368. hr = m_pMdObject->ComMDSetMetaDataW( mdhRoot,
  2369. L"",
  2370. &mdrHistory );
  2371. if ( FAILED( hr ) )
  2372. {
  2373. goto exit;
  2374. }
  2375. // Close the write handle to allow saving the metabase
  2376. DBG_ASSERT( mdhRoot != METADATA_MASTER_ROOT_HANDLE );
  2377. m_pMdObject->ComMDCloseMetaObject( mdhRoot );
  2378. mdhRoot = METADATA_MASTER_ROOT_HANDLE;
  2379. // Save the metabase
  2380. hr = m_pMdObject->ComMDSaveData();
  2381. if ( FAILED( hr ) )
  2382. {
  2383. goto exit;
  2384. }
  2385. exit:
  2386. if ( mdhRoot != METADATA_MASTER_ROOT_HANDLE )
  2387. {
  2388. m_pMdObject->ComMDCloseMetaObject( mdhRoot );
  2389. mdhRoot = METADATA_MASTER_ROOT_HANDLE;
  2390. }
  2391. return hr;
  2392. }
  2393. HRESULT
  2394. CADMCOMW::DisableHistory(
  2395. DWORD *pdwEnableHistoryOld,
  2396. DWORD *pdwEnableEWROld)
  2397. {
  2398. // Locals
  2399. HRESULT hr = S_OK;
  2400. DWORD dwEnableHistory = FALSE;
  2401. DWORD dwEnableEWR = FALSE;
  2402. DWORD dwT;
  2403. METADATA_HANDLE mdhRoot = METADATA_MASTER_ROOT_HANDLE;
  2404. METADATA_RECORD mdrHistory = {
  2405. MD_ROOT_ENABLE_HISTORY,
  2406. METADATA_NO_ATTRIBUTES,
  2407. IIS_MD_UT_SERVER,
  2408. DWORD_METADATA,
  2409. sizeof(DWORD),
  2410. (BYTE*)&dwEnableHistory,
  2411. 0
  2412. };
  2413. METADATA_RECORD mdrEWR = {
  2414. MD_ROOT_ENABLE_EDIT_WHILE_RUNNING,
  2415. METADATA_NO_ATTRIBUTES,
  2416. IIS_MD_UT_SERVER,
  2417. DWORD_METADATA,
  2418. sizeof(DWORD),
  2419. (BYTE*)&dwEnableEWR,
  2420. 0
  2421. };
  2422. // Check agrs
  2423. if ( ( pdwEnableHistoryOld == NULL ) || ( pdwEnableEWROld == NULL ) )
  2424. {
  2425. hr = E_INVALIDARG;
  2426. goto exit;
  2427. }
  2428. // Intialize
  2429. *pdwEnableHistoryOld = FALSE;
  2430. *pdwEnableEWROld = FALSE;
  2431. hr = m_pMdObject->ComMDOpenMetaObjectW( METADATA_MASTER_ROOT_HANDLE,
  2432. L"/LM",
  2433. METADATA_PERMISSION_READ,
  2434. DEFAULT_SAVE_TIMEOUT,
  2435. &mdhRoot );
  2436. if ( hr == HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) )
  2437. {
  2438. // If /LM is not there don't fail.
  2439. // Treat as if EWR and History are not enabled (*pdwEnableHistoryOld and *pdwEnableEWROld are initialized to FALSE)
  2440. // This can happen only during sysprep.
  2441. hr = S_OK;
  2442. goto exit;
  2443. }
  2444. if ( FAILED( hr ) )
  2445. {
  2446. goto exit;
  2447. }
  2448. // Get EWR
  2449. hr = m_pMdObject->ComMDGetMetaDataW( mdhRoot,
  2450. L"",
  2451. &mdrEWR,
  2452. &dwT );
  2453. if ( hr == MD_ERROR_DATA_NOT_FOUND )
  2454. {
  2455. // If the property is not there don't fail.
  2456. // Treat as if EWR is not enabled (dwEnableEWR is initialized to FALSE)
  2457. hr = S_OK;
  2458. }
  2459. if ( FAILED( hr ) )
  2460. {
  2461. goto exit;
  2462. }
  2463. // Get History
  2464. hr = m_pMdObject->ComMDGetMetaDataW( mdhRoot,
  2465. L"",
  2466. &mdrHistory,
  2467. &dwT );
  2468. if ( hr == MD_ERROR_DATA_NOT_FOUND )
  2469. {
  2470. // If the property is not there don't fail.
  2471. // Treat as if History is not enabled (dwEnableHistory is initialized to FALSE)
  2472. hr = S_OK;
  2473. }
  2474. if ( FAILED( hr ) )
  2475. {
  2476. goto exit;
  2477. }
  2478. // If both are already disabled
  2479. if ( !dwEnableHistory && !dwEnableEWR )
  2480. {
  2481. // No need to change anything in the metabase.
  2482. // No need to change the out parameters,
  2483. // because they are already initialized to FALSE
  2484. // Just exit.
  2485. goto exit;
  2486. }
  2487. // Close the read handle to allow writing in SetHistoryAndEWR
  2488. DBG_ASSERT( mdhRoot != METADATA_MASTER_ROOT_HANDLE );
  2489. m_pMdObject->ComMDCloseMetaObject( mdhRoot );
  2490. mdhRoot = METADATA_MASTER_ROOT_HANDLE;
  2491. // Disable history and ewr
  2492. // They have to be changed in pairs, because EWR turns history on
  2493. hr = SetHistoryAndEWR( FALSE, FALSE );
  2494. if ( FAILED( hr ) )
  2495. {
  2496. goto exit;
  2497. }
  2498. // Return
  2499. *pdwEnableHistoryOld = dwEnableHistory;
  2500. *pdwEnableEWROld = dwEnableEWR;
  2501. exit:
  2502. if ( mdhRoot != METADATA_MASTER_ROOT_HANDLE )
  2503. {
  2504. m_pMdObject->ComMDCloseMetaObject( mdhRoot );
  2505. mdhRoot = METADATA_MASTER_ROOT_HANDLE;
  2506. }
  2507. return hr;
  2508. }
  2509. HRESULT STDMETHODCALLTYPE
  2510. CADMCOMW::Backup(
  2511. LPCWSTR pszMDBackupLocation,
  2512. DWORD dwMDVersion,
  2513. DWORD dwMDFlags)
  2514. {
  2515. return BackupHelper( pszMDBackupLocation,
  2516. dwMDVersion,
  2517. dwMDFlags );
  2518. }
  2519. HRESULT STDMETHODCALLTYPE
  2520. CADMCOMW::BackupWithPasswd(
  2521. LPCWSTR pszMDBackupLocation,
  2522. DWORD dwMDVersion,
  2523. DWORD dwMDFlags,
  2524. LPCWSTR pszPasswd)
  2525. {
  2526. return BackupHelper( pszMDBackupLocation,
  2527. dwMDVersion,
  2528. dwMDFlags,
  2529. pszPasswd );
  2530. }
  2531. HRESULT STDMETHODCALLTYPE
  2532. CADMCOMW::Restore(
  2533. LPCWSTR pszMDBackupLocation,
  2534. DWORD dwMDVersion,
  2535. DWORD dwMDFlags)
  2536. {
  2537. return RestoreHelper( pszMDBackupLocation,
  2538. dwMDVersion,
  2539. 0,
  2540. NULL,
  2541. dwMDFlags,
  2542. RESTORE_BACKUP );
  2543. }
  2544. HRESULT STDMETHODCALLTYPE
  2545. CADMCOMW::RestoreWithPasswd(
  2546. LPCWSTR pszMDBackupLocation,
  2547. DWORD dwMDVersion,
  2548. DWORD dwMDFlags,
  2549. LPCWSTR pszPasswd)
  2550. {
  2551. return RestoreHelper( pszMDBackupLocation,
  2552. dwMDVersion,
  2553. 0,
  2554. pszPasswd,
  2555. dwMDFlags,
  2556. RESTORE_BACKUP );
  2557. }
  2558. HRESULT STDMETHODCALLTYPE
  2559. CADMCOMW::EnumBackups(
  2560. LPWSTR pszMDBackupLocation,
  2561. DWORD *pdwMDVersion,
  2562. PFILETIME pftMDBackupTime,
  2563. DWORD dwMDEnumIndex)
  2564. {
  2565. HRESULT hresReturn = S_OK;
  2566. if ( !AdminAclAccessCheck( m_pMdObject,
  2567. (LPVOID)this,
  2568. METADATA_MASTER_ROOT_HANDLE,
  2569. L"",
  2570. MD_ADMIN_ACL,
  2571. METADATA_PERMISSION_WRITE,
  2572. &g_ohMasterRootHandle ) )
  2573. {
  2574. DBGPRINTF(( DBG_CONTEXT,
  2575. "[CADMCOMW::EnumBackups AdminAclAccessCheck failed, error %lx\n",
  2576. GetLastError() ));
  2577. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  2578. }
  2579. else
  2580. {
  2581. //
  2582. // call metadata com api
  2583. //
  2584. hresReturn = m_pMdObject->ComMDEnumBackupsW(pszMDBackupLocation,
  2585. pdwMDVersion,
  2586. pftMDBackupTime,
  2587. dwMDEnumIndex);
  2588. }
  2589. return hresReturn;
  2590. }
  2591. HRESULT STDMETHODCALLTYPE
  2592. CADMCOMW::DeleteBackup(
  2593. LPCWSTR pszMDBackupLocation,
  2594. DWORD dwMDVersion)
  2595. {
  2596. HRESULT hresReturn = S_OK;
  2597. if ( !AdminAclAccessCheck( m_pMdObject,
  2598. (LPVOID)this,
  2599. METADATA_MASTER_ROOT_HANDLE,
  2600. L"",
  2601. MD_ADMIN_ACL,
  2602. METADATA_PERMISSION_WRITE,
  2603. &g_ohMasterRootHandle ) )
  2604. {
  2605. DBGPRINTF(( DBG_CONTEXT,
  2606. "[CADMCOMW::DeleteBackup] AdminAclAccessCheck failed, error %lx\n",
  2607. GetLastError() ));
  2608. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  2609. }
  2610. else
  2611. {
  2612. //
  2613. // call metadata com api
  2614. //
  2615. hresReturn = m_pMdObject->ComMDDeleteBackupW(pszMDBackupLocation,
  2616. dwMDVersion);
  2617. }
  2618. return hresReturn;
  2619. }
  2620. HRESULT STDMETHODCALLTYPE
  2621. CADMCOMW::Export(
  2622. LPCWSTR i_wszPasswd,
  2623. LPCWSTR i_wszFileName,
  2624. LPCWSTR i_wszSourcePath,
  2625. DWORD i_dwMDFlags)
  2626. {
  2627. HRESULT hr = S_OK;
  2628. DWORD dwError;
  2629. METADATA_HANDLE mdh = METADATA_MASTER_ROOT_HANDLE;
  2630. METADATA_HANDLE mdhActual = METADATA_MASTER_ROOT_HANDLE;
  2631. COpenHandle* pohActual = NULL;
  2632. STRAU strFileName;
  2633. //
  2634. // parameter validation
  2635. //
  2636. if ( ( i_wszFileName == NULL ) || ( *i_wszFileName == L'\0' ) ||
  2637. ( i_wszSourcePath == NULL ) )
  2638. {
  2639. hr = E_INVALIDARG;
  2640. goto exit;
  2641. }
  2642. hr = CoImpersonateClient();
  2643. if ( FAILED( hr ) )
  2644. {
  2645. goto exit;
  2646. }
  2647. // IVANPASH 598894 (SCR)
  2648. // Restrict the access to Export only to administrators
  2649. if ( !AdminAclAccessCheck( m_pMdObject,
  2650. (LPVOID)this,
  2651. METADATA_MASTER_ROOT_HANDLE,
  2652. L"",
  2653. MD_ADMIN_ACL,
  2654. METADATA_PERMISSION_WRITE,
  2655. &g_ohMasterRootHandle ) )
  2656. {
  2657. dwError = GetLastError();
  2658. DBGPRINTF(( DBG_CONTEXT,
  2659. "[CADMCOMW::Export] AdminAclAccessCheck failed, error %lx\n",
  2660. dwError ));
  2661. hr = RETURNCODETOHRESULT( dwError );
  2662. goto exit;
  2663. }
  2664. hr = OpenKeyHelper( METADATA_MASTER_ROOT_HANDLE,
  2665. i_wszSourcePath,
  2666. METADATA_PERMISSION_READ,
  2667. DEFAULT_SAVE_TIMEOUT,
  2668. &mdh);
  2669. if ( FAILED( hr ) )
  2670. {
  2671. goto exit;
  2672. }
  2673. //
  2674. // pohActual refCount = 2 after Lookup.
  2675. //
  2676. dwError = Lookup(mdh, &mdhActual, &pohActual);
  2677. if ( dwError != ERROR_SUCCESS )
  2678. {
  2679. hr = RETURNCODETOHRESULT( dwError );
  2680. DBG_ASSERT( pohActual == NULL );
  2681. //
  2682. // Yes, an open key does not get closed, but Lookup really should
  2683. // not fail if mdh is a valid key.
  2684. // Also CloseKey would do exactly the same Lookup call and will fail too.
  2685. //
  2686. goto exit;
  2687. }
  2688. //
  2689. // Move refCount down to 1.
  2690. //
  2691. pohActual->Release(this);
  2692. if( !AdminAclAccessCheck( m_pMdObject,
  2693. (LPVOID)this,
  2694. mdh,
  2695. L"",
  2696. MD_ADMIN_ACL,
  2697. METADATA_PERMISSION_WRITE,
  2698. pohActual ) )
  2699. {
  2700. dwError = GetLastError();
  2701. DBGPRINTF(( DBG_CONTEXT,
  2702. "[CADMCOMW::Export] AdminAclAccessCheck failed, error %lx\n",
  2703. dwError ));
  2704. hr = RETURNCODETOHRESULT( dwError );
  2705. goto exit;
  2706. }
  2707. // IVANPASH 598894 (SCR)
  2708. // Prepend the file name with \\?\ (or \\?\UNC\) to prevent canonicalization
  2709. hr = MakePathCanonicalizationProof( i_wszFileName, FALSE, &strFileName );
  2710. if ( FAILED( hr ) )
  2711. {
  2712. goto exit;
  2713. }
  2714. // Don't use i_wszFileName any more
  2715. i_wszFileName = NULL;
  2716. // call metadata com api
  2717. hr = m_pMdObject->ComMDExportW( mdhActual,
  2718. i_wszPasswd,
  2719. strFileName.QueryStrW(),
  2720. i_wszSourcePath,
  2721. i_dwMDFlags);
  2722. if ( FAILED( hr ) )
  2723. {
  2724. goto exit;
  2725. }
  2726. exit:
  2727. // At this moment mdh can actually contain a valid CMDCOMW handle.
  2728. // It is not explicitely closed, because the code bellow actually does
  2729. // the same as CloseKey(mdh).
  2730. if ( pohActual )
  2731. {
  2732. // close key
  2733. if ( mdhActual != METADATA_MASTER_ROOT_HANDLE )
  2734. {
  2735. // call metadata com api
  2736. m_pMdObject->ComMDCloseMetaObject( mdhActual );
  2737. }
  2738. // Remove node from handle table
  2739. pohActual->Release(this);
  2740. pohActual=NULL;
  2741. }
  2742. return hr;
  2743. }
  2744. HRESULT STDMETHODCALLTYPE
  2745. CADMCOMW::Import(
  2746. LPCWSTR i_wszPasswd,
  2747. LPCWSTR i_wszFileName,
  2748. LPCWSTR i_wszSourcePath,
  2749. LPCWSTR i_wszDestPath,
  2750. DWORD i_dwMDFlags)
  2751. /*++
  2752. Synopsis:
  2753. Arguments: [i_wszPasswd] -
  2754. [i_wszFileName] -
  2755. [i_wszSourcePath] - Absolute metabase path
  2756. [i_wszDestPath] - Absolute metabase path
  2757. [i_dwMDFlags] -
  2758. Return Value:
  2759. --*/
  2760. {
  2761. HRESULT hr = S_OK;
  2762. DWORD dwError;
  2763. METADATA_HANDLE mdh = 0;
  2764. METADATA_HANDLE mdhActual = 0;
  2765. COpenHandle* pohActual = NULL;
  2766. LPWSTR wszDeepest = NULL;
  2767. LONG cchDeepest = 0;
  2768. LPWSTR wszEnd = NULL;
  2769. LONG idx = 0;
  2770. WCHAR wszKeyType[METADATA_MAX_STRING_LEN] = {0};
  2771. DWORD dwRequiredSize = 0;
  2772. METADATA_RECORD mr =
  2773. {
  2774. MD_KEY_TYPE,
  2775. METADATA_NO_ATTRIBUTES,
  2776. IIS_MD_UT_SERVER,
  2777. STRING_METADATA,
  2778. METADATA_MAX_STRING_LEN*sizeof(WCHAR),
  2779. (LPBYTE)wszKeyType,
  2780. 0
  2781. };
  2782. STRAU strFileName;
  2783. //
  2784. // parameter validation
  2785. //
  2786. if ( ( i_wszFileName == NULL ) || ( *i_wszFileName == L'\0' ) ||
  2787. ( i_wszSourcePath == NULL ) ||
  2788. ( i_wszDestPath == NULL ) )
  2789. {
  2790. hr = E_INVALIDARG;
  2791. goto exit;
  2792. }
  2793. if (i_wszPasswd == NULL)
  2794. {
  2795. i_wszPasswd = L"";
  2796. }
  2797. hr = CoImpersonateClient();
  2798. if ( FAILED( hr ) )
  2799. {
  2800. goto exit;
  2801. }
  2802. // IVANPASH 598894 (SCR)
  2803. // Restrict the access to Import only to administrators
  2804. if ( !AdminAclAccessCheck( m_pMdObject,
  2805. (LPVOID)this,
  2806. METADATA_MASTER_ROOT_HANDLE,
  2807. L"",
  2808. MD_ADMIN_ACL,
  2809. METADATA_PERMISSION_WRITE,
  2810. &g_ohMasterRootHandle ) )
  2811. {
  2812. dwError = GetLastError();
  2813. DBGPRINTF(( DBG_CONTEXT,
  2814. "[CADMCOMW::Import] AdminAclAccessCheck failed, error %lx\n",
  2815. dwError ));
  2816. hr = RETURNCODETOHRESULT( dwError );
  2817. goto exit;
  2818. }
  2819. //
  2820. // Copy i_wszDestPath to wszDeepest
  2821. // Remove trailing slashes
  2822. //
  2823. cchDeepest = (LONG)wcslen(i_wszDestPath);
  2824. wszDeepest = new WCHAR[1+cchDeepest];
  2825. if(!wszDeepest)
  2826. {
  2827. hr = RETURNCODETOHRESULT(ERROR_NOT_ENOUGH_MEMORY);
  2828. goto exit;
  2829. }
  2830. memcpy(wszDeepest, i_wszDestPath, sizeof(WCHAR)*(cchDeepest+1));
  2831. while( cchDeepest > 0 && IS_MD_PATH_DELIM(wszDeepest[cchDeepest-1]) )
  2832. {
  2833. cchDeepest--;
  2834. }
  2835. //
  2836. // Open the deepest level key possible
  2837. //
  2838. wszEnd = wszDeepest + cchDeepest;
  2839. for(idx = cchDeepest; idx >= 0; idx--)
  2840. {
  2841. if(idx == 0 || idx == cchDeepest || IS_MD_PATH_DELIM(*wszEnd))
  2842. {
  2843. *wszEnd = L'\0';
  2844. hr = OpenKeyHelper(
  2845. METADATA_MASTER_ROOT_HANDLE,
  2846. wszDeepest,
  2847. METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ,
  2848. DEFAULT_SAVE_TIMEOUT,
  2849. &mdh);
  2850. if( FAILED(hr) &&
  2851. hr != RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND) )
  2852. {
  2853. goto exit;
  2854. }
  2855. else if(SUCCEEDED(hr))
  2856. {
  2857. break;
  2858. }
  2859. }
  2860. wszEnd--;
  2861. }
  2862. if(FAILED(hr))
  2863. {
  2864. goto exit;
  2865. }
  2866. //
  2867. // If we are here, we now have an Open metabase handle
  2868. //
  2869. dwError = Lookup(mdh, &mdhActual, &pohActual);
  2870. hr = RETURNCODETOHRESULT(dwError);
  2871. if(FAILED(hr))
  2872. {
  2873. //
  2874. // Yes, an open key does not get closed, but Lookup really should
  2875. // not fail if mdh is a valid key.
  2876. // Also CloseKey would do exactly the same Lookup call and will fail too.
  2877. //
  2878. goto exit;
  2879. }
  2880. pohActual->Release(this); // Decrements refcount from 2 to 1.
  2881. if( !AdminAclAccessCheck( m_pMdObject,
  2882. (LPVOID)this,
  2883. mdh,
  2884. L"",
  2885. MD_ADMIN_ACL,
  2886. METADATA_PERMISSION_WRITE | METADATA_PERMISSION_READ,
  2887. pohActual ) )
  2888. {
  2889. DBGPRINTF(( DBG_CONTEXT,
  2890. "[CADMCOMW::Import] AdminAclAccessCheck failed, error %lx\n",
  2891. GetLastError() ));
  2892. hr = RETURNCODETOHRESULT( GetLastError() );
  2893. goto exit;
  2894. }
  2895. //
  2896. // Get the keytype
  2897. // If the node does not exist, or node exists but keytype doesn't, we
  2898. // will not set wszKeytype and hence ComMDImport will not attempt to match
  2899. // the source and dest keytype
  2900. //
  2901. hr = m_pMdObject->ComMDGetMetaDataW(
  2902. mdhActual,
  2903. i_wszDestPath+idx,
  2904. &mr,
  2905. &dwRequiredSize);
  2906. if(hr == RETURNCODETOHRESULT(ERROR_PATH_NOT_FOUND))
  2907. {
  2908. hr = S_OK;
  2909. }
  2910. else if(hr == MD_ERROR_DATA_NOT_FOUND)
  2911. {
  2912. hr = S_OK;
  2913. }
  2914. if(FAILED(hr))
  2915. {
  2916. DBGPRINTF((DBG_CONTEXT, "Error trying to retrieve keytype for %ws\n", i_wszDestPath+idx));
  2917. goto exit;
  2918. }
  2919. // IVANPASH 598894 (SCR)
  2920. // Prepend the file name with \\?\ (or \\?\UNC\) to prevent canonicalization
  2921. hr = MakePathCanonicalizationProof( i_wszFileName, TRUE, &strFileName );
  2922. if ( FAILED( hr ) )
  2923. {
  2924. goto exit;
  2925. }
  2926. // Don't use i_wszFileName any more
  2927. i_wszFileName = NULL;
  2928. //
  2929. // Call Import
  2930. //
  2931. hr = m_pMdObject->ComMDImportW(
  2932. mdhActual,
  2933. i_wszDestPath+idx,
  2934. wszKeyType,
  2935. i_wszPasswd,
  2936. strFileName.QueryStrW(),
  2937. i_wszSourcePath,
  2938. i_dwMDFlags);
  2939. if(FAILED(hr))
  2940. {
  2941. goto exit;
  2942. }
  2943. exit:
  2944. if(pohActual != NULL)
  2945. {
  2946. //
  2947. // Close Key
  2948. //
  2949. m_pMdObject->ComMDCloseMetaObject( mdhActual );
  2950. pohActual->Release(this);
  2951. pohActual = NULL;
  2952. }
  2953. if ( wszDeepest )
  2954. {
  2955. delete [] wszDeepest;
  2956. wszDeepest = NULL;
  2957. }
  2958. return hr;
  2959. }
  2960. HRESULT STDMETHODCALLTYPE
  2961. CADMCOMW::RestoreHistory(
  2962. LPCWSTR pszMDHistoryLocation,
  2963. DWORD dwMDMajorVersion,
  2964. DWORD dwMDMinorVersion,
  2965. DWORD dwMDFlags)
  2966. {
  2967. HRESULT hresReturn = S_OK;
  2968. if( (dwMDFlags & ~MD_HISTORY_LATEST) != 0 &&
  2969. dwMDFlags != 0 )
  2970. {
  2971. return HRESULT_FROM_WIN32(ERROR_INVALID_FLAGS);
  2972. }
  2973. if( (dwMDFlags & MD_HISTORY_LATEST) &&
  2974. (dwMDMajorVersion != 0 || dwMDMinorVersion != 0) )
  2975. {
  2976. return E_INVALIDARG;
  2977. }
  2978. //
  2979. // parameter validation done in here.
  2980. //
  2981. hresReturn = RestoreHelper(pszMDHistoryLocation,
  2982. dwMDMajorVersion,
  2983. dwMDMinorVersion,
  2984. NULL,
  2985. dwMDFlags,
  2986. RESTORE_HISTORY);
  2987. return hresReturn;
  2988. }
  2989. HRESULT STDMETHODCALLTYPE
  2990. CADMCOMW::EnumHistory(
  2991. LPWSTR io_wszMDHistoryLocation,
  2992. DWORD *o_pdwMDMajorVersion,
  2993. DWORD *o_pdwMDMinorVersion,
  2994. PFILETIME o_pftMDHistoryTime,
  2995. DWORD i_dwMDEnumIndex)
  2996. {
  2997. HRESULT hresReturn = S_OK;
  2998. if (io_wszMDHistoryLocation == NULL ||
  2999. o_pdwMDMajorVersion == NULL ||
  3000. o_pdwMDMinorVersion == NULL ||
  3001. o_pftMDHistoryTime == NULL)
  3002. {
  3003. return E_INVALIDARG;
  3004. }
  3005. if ( !AdminAclAccessCheck( m_pMdObject,
  3006. (LPVOID)this,
  3007. METADATA_MASTER_ROOT_HANDLE,
  3008. L"",
  3009. MD_ADMIN_ACL,
  3010. METADATA_PERMISSION_WRITE,
  3011. &g_ohMasterRootHandle ) )
  3012. {
  3013. DBGPRINTF(( DBG_CONTEXT,
  3014. "[CADMCOMW::EnumHistory AdminAclAccessCheck failed, error %lx\n",
  3015. GetLastError() ));
  3016. hresReturn = RETURNCODETOHRESULT( GetLastError() );
  3017. }
  3018. else
  3019. {
  3020. //
  3021. // call metadata com api
  3022. //
  3023. hresReturn = m_pMdObject->ComMDEnumHistoryW(io_wszMDHistoryLocation,
  3024. o_pdwMDMajorVersion,
  3025. o_pdwMDMinorVersion,
  3026. o_pftMDHistoryTime,
  3027. i_dwMDEnumIndex);
  3028. }
  3029. return hresReturn;
  3030. }
  3031. HRESULT STDMETHODCALLTYPE
  3032. CADMCOMW::GetChildPaths(
  3033. METADATA_HANDLE hMDHandle,
  3034. LPCWSTR pszMDPath,
  3035. DWORD cchMDBufferSize,
  3036. WCHAR *pszBuffer,
  3037. DWORD *pcchMDRequiredBufferSize)
  3038. /*++
  3039. Routine Description:
  3040. Retrieves all child keys of a given path from a given handle
  3041. Arguments:
  3042. hMDHandle - open handle
  3043. pszMDPath - path of the meta object with which this data is associated
  3044. cchMDBufferSize - sizeof buffer passed in, in wchars
  3045. pszBuffer - buffer, allocated by caller, that result is placed into
  3046. pcchMDRequiredBufferSize - required size, filled in only if buffer is insufficient
  3047. Return Value:
  3048. Status. s_ok on success.
  3049. --*/
  3050. {
  3051. HRESULT hr = S_OK;
  3052. METADATA_HANDLE hActualHandle;
  3053. BOOL fSecure;
  3054. //
  3055. // lookup and access check
  3056. //
  3057. hr = LookupAndAccessCheck(hMDHandle,
  3058. &hActualHandle,
  3059. pszMDPath,
  3060. 0,
  3061. METADATA_PERMISSION_READ,
  3062. &fSecure);
  3063. if (FAILED(hr))
  3064. {
  3065. goto done;
  3066. }
  3067. DBG_ASSERT( NULL != m_pMdObject3 );
  3068. hr = m_pMdObject3->ComMDGetChildPathsW(hActualHandle,
  3069. pszMDPath,
  3070. cchMDBufferSize,
  3071. pszBuffer,
  3072. pcchMDRequiredBufferSize);
  3073. if (FAILED(hr))
  3074. {
  3075. goto done;
  3076. }
  3077. hr = S_OK;
  3078. done:
  3079. return hr;
  3080. }
  3081. HRESULT
  3082. CADMCOMW::AddKeyHelper(
  3083. IN METADATA_HANDLE hMDHandle,
  3084. IN LPCWSTR pszMDPath)
  3085. /*++
  3086. Routine Description:
  3087. Add meta object and adds it to the list of child objects for the object
  3088. specified by Path.
  3089. Arguments:
  3090. hMDHandle - open handle
  3091. pszMDPath - path of the object to be added
  3092. Return Value:
  3093. Status.
  3094. --*/
  3095. {
  3096. HRESULT hresReturn = S_OK;
  3097. METADATA_HANDLE hActualHandle;
  3098. if ((pszMDPath == NULL) ||
  3099. (*pszMDPath == (WCHAR)'\0'))
  3100. {
  3101. hresReturn = E_INVALIDARG;
  3102. }
  3103. else
  3104. {
  3105. //
  3106. // lookup and access check
  3107. //
  3108. hresReturn = LookupAndAccessCheck(hMDHandle,
  3109. &hActualHandle,
  3110. pszMDPath,
  3111. 0,
  3112. METADATA_PERMISSION_WRITE);
  3113. if (SUCCEEDED(hresReturn))
  3114. {
  3115. //
  3116. // call metadata com api
  3117. //
  3118. hresReturn = m_pMdObject->ComMDAddMetaObjectW( hActualHandle,
  3119. pszMDPath );
  3120. }
  3121. }
  3122. return hresReturn;
  3123. }
  3124. HRESULT
  3125. CADMCOMW::OpenKeyHelper(
  3126. METADATA_HANDLE hMDHandle,
  3127. LPCWSTR pszMDPath,
  3128. DWORD dwMDAccessRequested,
  3129. DWORD dwMDTimeOut,
  3130. PMETADATA_HANDLE phMDNewHandle)
  3131. /*++
  3132. Routine Description:
  3133. Opens a meta object for read and/or write access.
  3134. - This is used by Export.
  3135. Arguments:
  3136. hMDHandle - open handle
  3137. pszMDPath - path of the object to be opened
  3138. dwMDAccessRequested - permissions requested
  3139. dwMDTimeOut - time to block waiting for open to succeed, in miliseconds.
  3140. phMDNewHandle - handle to be passed to other MD routines
  3141. Return Value:
  3142. Status.
  3143. --*/
  3144. {
  3145. HRESULT hr = S_OK;
  3146. DWORD dwError;
  3147. BOOL fRet;
  3148. METADATA_HANDLE hNewHandle = METADATA_MASTER_ROOT_HANDLE;
  3149. METADATA_HANDLE hActualHandle = METADATA_MASTER_ROOT_HANDLE;
  3150. COpenHandle *pohParent = NULL;
  3151. // Check args
  3152. if ( ( phMDNewHandle == NULL ) ||
  3153. ( ( dwMDAccessRequested & ( METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) == 0 ) ||
  3154. ( ( dwMDAccessRequested & ~( METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE ) ) != 0 ) ||
  3155. ( ( pszMDPath != NULL ) && ( wcsstr( pszMDPath, L"<nsepm>" ) != NULL ) ) )
  3156. {
  3157. //
  3158. // <nsepm> used to be magic name for the Name Space Extension access
  3159. // It was removed for IIS6 but to prevent legacy applications
  3160. // to write obsolete and unusable data to metabase deny access to path
  3161. // containing <nsepm>
  3162. //
  3163. hr = E_INVALIDARG;
  3164. goto exit;
  3165. }
  3166. //
  3167. // Map Admin Handle to Actual Handle
  3168. //
  3169. //
  3170. // This Addrefs pohParent, which makes sure it doesn't do away
  3171. // pohParent is needed by AddNode
  3172. //
  3173. dwError = Lookup( hMDHandle,
  3174. &hActualHandle,
  3175. &pohParent );
  3176. if( dwError != ERROR_SUCCESS )
  3177. {
  3178. hr = HRESULT_FROM_WIN32( dwError );
  3179. goto exit;
  3180. }
  3181. // Check access
  3182. fRet = AdminAclAccessCheck( m_pMdObject,
  3183. this,
  3184. hMDHandle,
  3185. pszMDPath,
  3186. 0,
  3187. dwMDAccessRequested,
  3188. pohParent );
  3189. if ( !fRet )
  3190. {
  3191. dwError = GetLastError();
  3192. if ( dwError != ERROR_ACCESS_DENIED )
  3193. {
  3194. hr = HRESULT_FROM_WIN32( dwError );
  3195. goto exit;
  3196. }
  3197. // If failed with access denied for writing or writing+reading
  3198. if ( ( dwMDAccessRequested & METADATA_PERMISSION_WRITE ) != 0 )
  3199. {
  3200. // Retry checking access for writing MD_ADMIN_ACL
  3201. // AdminAclAccessCheck will try 1st to check MD_ACR_RESTRICTED_WRITE and than for MD_ACR_WRITE_DAC
  3202. fRet = AdminAclAccessCheck( m_pMdObject,
  3203. this,
  3204. hMDHandle,
  3205. pszMDPath,
  3206. MD_ADMIN_ACL,
  3207. dwMDAccessRequested,
  3208. pohParent );
  3209. }
  3210. else
  3211. {
  3212. // If failed with access denied for reading (and the write bit is not set)
  3213. if ( dwMDAccessRequested == METADATA_PERMISSION_READ )
  3214. {
  3215. // Retry checking access for enum only
  3216. // AdminAclAccessCheck internally already check for both MD_ACR_UNSECURE_PROPS_READ and MD_ACR_READ
  3217. fRet = AdminAclAccessCheck( m_pMdObject,
  3218. this,
  3219. hMDHandle,
  3220. pszMDPath,
  3221. AAC_ENUM_KEYS,
  3222. dwMDAccessRequested,
  3223. pohParent );
  3224. }
  3225. }
  3226. }
  3227. if ( !fRet )
  3228. {
  3229. dwError = GetLastError();
  3230. hr = HRESULT_FROM_WIN32( dwError );
  3231. goto exit;
  3232. }
  3233. //
  3234. // call metadata com api
  3235. //
  3236. hr = m_pMdObject->ComMDOpenMetaObjectW( hActualHandle,
  3237. pszMDPath,
  3238. dwMDAccessRequested,
  3239. dwMDTimeOut,
  3240. &hNewHandle );
  3241. if( FAILED( hr ) )
  3242. {
  3243. goto exit;
  3244. }
  3245. // Add the opened handle to table
  3246. hr = AddNode( hNewHandle,
  3247. pohParent,
  3248. phMDNewHandle,
  3249. pszMDPath );
  3250. if( FAILED( hr ) )
  3251. {
  3252. goto exit;
  3253. }
  3254. // Don't close the metadata handle
  3255. hNewHandle = METADATA_MASTER_ROOT_HANDLE;
  3256. exit:
  3257. if ( hNewHandle != METADATA_MASTER_ROOT_HANDLE )
  3258. {
  3259. m_pMdObject->ComMDCloseMetaObject( hNewHandle );
  3260. hNewHandle = METADATA_MASTER_ROOT_HANDLE;
  3261. }
  3262. if ( pohParent != NULL )
  3263. {
  3264. pohParent->Release(this);
  3265. pohParent = NULL;
  3266. }
  3267. return hr;
  3268. }
  3269. DWORD
  3270. CADMCOMW::Lookup(
  3271. IN METADATA_HANDLE hHandle,
  3272. OUT METADATA_HANDLE *phActualHandle,
  3273. OUT COpenHandle **ppohHandle)
  3274. {
  3275. HANDLE_TABLE *phtNode;
  3276. DWORD dwReturn = ERROR_INVALID_HANDLE;
  3277. if( hHandle == METADATA_MASTER_ROOT_HANDLE )
  3278. {
  3279. *phActualHandle = g_MasterRoot.hActualHandle;
  3280. if (ppohHandle != NULL)
  3281. {
  3282. *ppohHandle = g_MasterRoot.pohHandle;
  3283. (*ppohHandle)->AddRef();
  3284. }
  3285. dwReturn = ERROR_SUCCESS;
  3286. }
  3287. else
  3288. {
  3289. m_LockHandleResource.ReadLock();
  3290. for( phtNode = m_hashtab[(DWORD)hHandle % HASHSIZE]; phtNode != NULL;
  3291. phtNode = phtNode->next )
  3292. {
  3293. if( phtNode->hAdminHandle == hHandle )
  3294. {
  3295. *phActualHandle = phtNode->hActualHandle;
  3296. if (ppohHandle != NULL)
  3297. {
  3298. *ppohHandle = phtNode->pohHandle;
  3299. (*ppohHandle)->AddRef();
  3300. }
  3301. dwReturn = ERROR_SUCCESS;
  3302. break;
  3303. }
  3304. }
  3305. m_LockHandleResource.ReadUnlock();
  3306. }
  3307. return dwReturn;
  3308. }
  3309. VOID
  3310. CADMCOMW::DisableAllHandles( )
  3311. {
  3312. HANDLE_TABLE *phtNode;
  3313. DWORD i;
  3314. //
  3315. // At this point, all metadata handles should be closed because a retore
  3316. // just happened. So don't need to close these handles.
  3317. //
  3318. //
  3319. // Can't just delete them, becuase of syncronization problems
  3320. // with CloseKey and Lookup. Set the hande to an invalid value
  3321. // So Lookup won't use them.
  3322. //
  3323. m_LockHandleResource.WriteLock();
  3324. for( i = 0; i < HASHSIZE; i++ )
  3325. {
  3326. for( phtNode = m_hashtab[i]; phtNode != NULL; phtNode = phtNode->next )
  3327. {
  3328. phtNode->hAdminHandle = INVALID_ADMINHANDLE_VALUE;
  3329. }
  3330. }
  3331. m_LockHandleResource.WriteUnlock();
  3332. }
  3333. HRESULT
  3334. CADMCOMW::LookupAndAccessCheck(
  3335. IN METADATA_HANDLE hHandle,
  3336. OUT METADATA_HANDLE *phActualHandle,
  3337. IN LPCWSTR pszPath,
  3338. IN DWORD dwId, // check for MD_ADMIN_ACL, must have special right to write them
  3339. IN DWORD dwAccess, // METADATA_PERMISSION_*
  3340. OUT LPBOOL pfEnableSecureAccess)
  3341. {
  3342. DWORD dwReturn = ERROR_SUCCESS;
  3343. COpenHandle *pohParent;
  3344. //
  3345. // Map Admin Handle to Actual Handle
  3346. //
  3347. //
  3348. // This Addrefs pohParent, which makes sure it doesn't go away
  3349. // until AdminAclAccessCheck is done
  3350. //
  3351. dwReturn = Lookup( hHandle,
  3352. phActualHandle,
  3353. &pohParent);
  3354. if (dwReturn == ERROR_SUCCESS)
  3355. {
  3356. if (!AdminAclAccessCheck(m_pMdObject,
  3357. (LPVOID)this,
  3358. hHandle,
  3359. pszPath,
  3360. dwId,
  3361. dwAccess,
  3362. pohParent,
  3363. pfEnableSecureAccess))
  3364. {
  3365. dwReturn = GetLastError();
  3366. }
  3367. pohParent->Release(this);
  3368. }
  3369. return RETURNCODETOHRESULT(dwReturn);
  3370. }
  3371. DWORD
  3372. CADMCOMW::LookupActualHandle(
  3373. IN METADATA_HANDLE hHandle)
  3374. {
  3375. HANDLE_TABLE *phtNode;
  3376. DWORD i;
  3377. DWORD dwReturn = ERROR_INVALID_HANDLE;
  3378. m_LockHandleResource.ReadLock();
  3379. for( i = 0; (i < HASHSIZE) && (dwReturn != ERROR_SUCCESS); i++ )
  3380. {
  3381. for( phtNode = m_hashtab[i]; (phtNode != NULL) && (dwReturn != ERROR_SUCCESS); phtNode = phtNode->next )
  3382. {
  3383. if( phtNode->hActualHandle == hHandle )
  3384. {
  3385. dwReturn = ERROR_SUCCESS;
  3386. }
  3387. }
  3388. }
  3389. m_LockHandleResource.ReadUnlock();
  3390. return dwReturn;
  3391. }
  3392. HRESULT
  3393. CADMCOMW::AddNode(
  3394. METADATA_HANDLE hActualHandle,
  3395. COpenHandle *pohParentHandle,
  3396. PMETADATA_HANDLE phAdminHandle,
  3397. LPCWSTR pszPath)
  3398. {
  3399. HRESULT hresReturn = S_OK;
  3400. HANDLE_TABLE *phtNode = (HANDLE_TABLE *)LocalAlloc(LMEM_FIXED, sizeof(*phtNode));
  3401. DWORD hashVal;
  3402. COpenHandle *pohHandle = new COpenHandle;
  3403. if ((phtNode == NULL) ||
  3404. (pohHandle == NULL))
  3405. {
  3406. hresReturn = E_OUTOFMEMORY;
  3407. if( phtNode )
  3408. {
  3409. LocalFree(phtNode);
  3410. }
  3411. if( pohHandle )
  3412. {
  3413. delete pohHandle;
  3414. }
  3415. }
  3416. else
  3417. {
  3418. m_LockHandleResource.WriteLock();
  3419. hresReturn = pohHandle->Init( m_dwHandleValue,
  3420. pszPath,
  3421. pohParentHandle->GetPath() );
  3422. if (FAILED(hresReturn))
  3423. {
  3424. LocalFree(phtNode);
  3425. delete pohHandle;
  3426. }
  3427. else
  3428. {
  3429. phtNode->pohHandle = pohHandle;
  3430. phtNode->hAdminHandle = m_dwHandleValue;
  3431. *phAdminHandle = m_dwHandleValue++;
  3432. phtNode->hActualHandle = hActualHandle;
  3433. hashVal = (phtNode->hAdminHandle) % HASHSIZE;
  3434. phtNode->next = m_hashtab[hashVal];
  3435. m_hashtab[hashVal] = phtNode;
  3436. }
  3437. m_LockHandleResource.WriteUnlock();
  3438. }
  3439. return hresReturn;
  3440. }
  3441. DWORD
  3442. CADMCOMW::DeleteNode(
  3443. METADATA_HANDLE hHandle)
  3444. {
  3445. HANDLE_TABLE *phtNode;
  3446. HANDLE_TABLE *phtDelNode;
  3447. DWORD HashValue = (DWORD)hHandle % HASHSIZE;
  3448. if( hHandle == METADATA_MASTER_ROOT_HANDLE )
  3449. {
  3450. return ERROR_SUCCESS;
  3451. }
  3452. m_LockHandleResource.WriteLock();
  3453. phtNode = m_hashtab[HashValue];
  3454. //
  3455. // check single node linked list
  3456. //
  3457. if( phtNode->hAdminHandle == hHandle )
  3458. {
  3459. m_hashtab[HashValue] = phtNode->next;
  3460. delete phtNode->pohHandle;
  3461. LocalFree(phtNode);
  3462. }
  3463. else
  3464. {
  3465. for( ; phtNode != NULL; phtNode = phtNode->next )
  3466. {
  3467. phtDelNode = phtNode->next;
  3468. if( phtDelNode != NULL )
  3469. {
  3470. if( phtDelNode->hAdminHandle == hHandle )
  3471. {
  3472. phtNode->next = phtDelNode->next;
  3473. delete phtDelNode->pohHandle;
  3474. LocalFree(phtDelNode);
  3475. break;
  3476. }
  3477. }
  3478. }
  3479. }
  3480. m_LockHandleResource.WriteUnlock();
  3481. return ERROR_SUCCESS;
  3482. }
  3483. //---------------
  3484. /*M+M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M+++M
  3485. Method: CADMCOMW::NotifySinks
  3486. Summary: Internal utility method of this COM object used to fire event
  3487. notification calls to all listening connection sinks in the
  3488. client.
  3489. Args: PAPER_EVENT PaperEvent
  3490. Type of notification event.
  3491. SHORT nX
  3492. X cordinate. Value is 0 unless event needs it.
  3493. SHORT nY
  3494. Y cordinate. Value is 0 unless event needs it.
  3495. SHORT nInkWidth
  3496. Ink Width. Value is 0 unless event needs it.
  3497. SHORT crInkColor
  3498. COLORREF RGB color value. Value is 0 unless event needs it.
  3499. Modifies: ...
  3500. Returns: HRESULT
  3501. Standard OLE result code. NOERROR for success.
  3502. M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M---M-M*/
  3503. // Initialize class static members
  3504. NOTIFY_CONTEXT * NOTIFY_CONTEXT::s_pCurrentlyWorkingOn = NULL;
  3505. CReaderWriterLock3 NOTIFY_CONTEXT::s_LockCurrentlyWorkingOn;
  3506. LIST_ENTRY NOTIFY_CONTEXT::s_listEntry;
  3507. CRITICAL_SECTION NOTIFY_CONTEXT::s_critSec;
  3508. BOOL NOTIFY_CONTEXT::s_fInitializedCritSec = FALSE;
  3509. HANDLE NOTIFY_CONTEXT::s_hShutdown = NULL;
  3510. HANDLE NOTIFY_CONTEXT::s_hDataAvailable = NULL;
  3511. HANDLE NOTIFY_CONTEXT::s_hThread = NULL;
  3512. DWORD NOTIFY_CONTEXT::s_dwThreadId = 0;
  3513. HRESULT
  3514. CADMCOMW::NotifySinks(
  3515. METADATA_HANDLE hMDHandle,
  3516. DWORD dwMDNumElements,
  3517. MD_CHANGE_OBJECT_W pcoChangeList[],
  3518. BOOL bIsMainNotification)
  3519. {
  3520. HRESULT hr = S_OK;
  3521. // if the object is terminated, or calling sinks is disabled or IISADMIN is shutting
  3522. // down ignore the notification and return S_OK to the caller.
  3523. if ( m_bTerminated || sm_fShutdownInProgress )
  3524. {
  3525. goto done;
  3526. }
  3527. //
  3528. // if the meta handle is for this object, return S_OK to
  3529. // the caller (admin's sink).
  3530. //
  3531. if( bIsMainNotification && ( LookupActualHandle( hMDHandle ) == ERROR_SUCCESS ) )
  3532. {
  3533. goto done;
  3534. }
  3535. // Any listeners registered for notifications?
  3536. hr = m_ConnectionPoint.ListenersPresent();
  3537. if ( hr != S_OK )
  3538. {
  3539. // We are going to ingore this notification, but return S_OK to the caller.
  3540. hr = S_OK;
  3541. goto done;
  3542. }
  3543. // Enqueue the notification, which will AddRef this.
  3544. hr = NOTIFY_CONTEXT::CreateNewContext( this,
  3545. hMDHandle,
  3546. dwMDNumElements,
  3547. pcoChangeList,
  3548. bIsMainNotification );
  3549. if (FAILED(hr))
  3550. {
  3551. goto done;
  3552. }
  3553. hr = S_OK;
  3554. done:
  3555. return hr;
  3556. }
  3557. NOTIFY_CONTEXT::NOTIFY_CONTEXT() :
  3558. _dwSignature(NOTIFY_CONTEXT_SIGNATURE),
  3559. _pCADMCOMW(NULL),
  3560. _dwMDNumElements(0),
  3561. _pcoChangeList(NULL),
  3562. _bIsMainNotification(FALSE)
  3563. {
  3564. InitializeListHead(&_listEntry);
  3565. }
  3566. NOTIFY_CONTEXT::~NOTIFY_CONTEXT()
  3567. {
  3568. InitializeListHead(&_listEntry);
  3569. _dwSignature = NOTIFY_CONTEXT_SIGNATURE_FREE;
  3570. s_LockCurrentlyWorkingOn.ReadLock();
  3571. if ( this == s_pCurrentlyWorkingOn )
  3572. {
  3573. s_LockCurrentlyWorkingOn.ConvertSharedToExclusive();
  3574. if ( this == s_pCurrentlyWorkingOn )
  3575. {
  3576. s_pCurrentlyWorkingOn = NULL;
  3577. }
  3578. s_LockCurrentlyWorkingOn.WriteUnlock();
  3579. }
  3580. else
  3581. {
  3582. s_LockCurrentlyWorkingOn.ReadUnlock();
  3583. }
  3584. if (_pCADMCOMW)
  3585. {
  3586. _pCADMCOMW->Release();
  3587. _pCADMCOMW = NULL;
  3588. }
  3589. if (_pcoChangeList)
  3590. {
  3591. for (DWORD i = 0; i < _dwMDNumElements; i++)
  3592. {
  3593. delete [] _pcoChangeList[i].pszMDPath;
  3594. _pcoChangeList[i].pszMDPath = NULL;
  3595. _pcoChangeList[i].dwMDChangeType = 0;
  3596. _pcoChangeList[i].dwMDNumDataIDs = 0;
  3597. delete [] _pcoChangeList[i].pdwMDDataIDs;
  3598. _pcoChangeList[i].pdwMDDataIDs = NULL;
  3599. }
  3600. }
  3601. _dwMDNumElements = 0;
  3602. delete [] _pcoChangeList;
  3603. _pcoChangeList = NULL;
  3604. _bIsMainNotification = FALSE;
  3605. }
  3606. //static
  3607. HRESULT
  3608. NOTIFY_CONTEXT::CreateNewContext(
  3609. CADMCOMW *pCADMCOMW,
  3610. METADATA_HANDLE ,
  3611. DWORD dwMDNumElements,
  3612. MD_CHANGE_OBJECT_W *pcoChangeList,
  3613. BOOL bIsMainNotification)
  3614. {
  3615. HRESULT hr = S_OK;
  3616. BOOL fRet = FALSE;
  3617. NOTIFY_CONTEXT *pContext = NULL;
  3618. DBG_ASSERT( pCADMCOMW != NULL );
  3619. if ( pCADMCOMW == NULL )
  3620. {
  3621. hr = E_INVALIDARG;
  3622. goto done;
  3623. }
  3624. pContext = new NOTIFY_CONTEXT;
  3625. if (NULL == pContext)
  3626. {
  3627. hr = E_OUTOFMEMORY;
  3628. goto done;
  3629. }
  3630. pContext->_pCADMCOMW = pCADMCOMW;
  3631. pContext->_pCADMCOMW->AddRef();
  3632. pContext->_dwMDNumElements = dwMDNumElements;
  3633. pContext->_bIsMainNotification = bIsMainNotification;
  3634. pContext->_pcoChangeList = new MD_CHANGE_OBJECT_W[dwMDNumElements];
  3635. if (NULL == pContext->_pcoChangeList)
  3636. {
  3637. hr = E_OUTOFMEMORY;
  3638. goto done;
  3639. }
  3640. ZeroMemory(pContext->_pcoChangeList, dwMDNumElements * sizeof(MD_CHANGE_OBJECT_W));
  3641. for (DWORD i = 0; i < dwMDNumElements; i++)
  3642. {
  3643. DWORD dwLength = (DWORD)wcslen(pcoChangeList[i].pszMDPath);
  3644. pContext->_pcoChangeList[i].pszMDPath = new WCHAR[dwLength + 1];
  3645. if (NULL == pContext->_pcoChangeList[i].pszMDPath)
  3646. {
  3647. hr = E_OUTOFMEMORY;
  3648. goto done;
  3649. }
  3650. wcscpy(pContext->_pcoChangeList[i].pszMDPath, pcoChangeList[i].pszMDPath);
  3651. pContext->_pcoChangeList[i].dwMDChangeType = pcoChangeList[i].dwMDChangeType;
  3652. pContext->_pcoChangeList[i].dwMDNumDataIDs = pcoChangeList[i].dwMDNumDataIDs;
  3653. pContext->_pcoChangeList[i].pdwMDDataIDs = new DWORD[pContext->_pcoChangeList[i].dwMDNumDataIDs];
  3654. if (NULL == pContext->_pcoChangeList[i].pdwMDDataIDs)
  3655. {
  3656. hr = E_OUTOFMEMORY;
  3657. goto done;
  3658. }
  3659. memcpy(pContext->_pcoChangeList[i].pdwMDDataIDs,
  3660. pcoChangeList[i].pdwMDDataIDs,
  3661. sizeof(DWORD) * pContext->_pcoChangeList[i].dwMDNumDataIDs);
  3662. }
  3663. EnterCriticalSection(&s_critSec);
  3664. InsertTailList(&s_listEntry, &pContext->_listEntry);
  3665. LeaveCriticalSection(&s_critSec);
  3666. fRet = SetEvent(s_hDataAvailable);
  3667. if (FALSE == fRet)
  3668. {
  3669. hr = HRESULT_FROM_WIN32(GetLastError());
  3670. goto done;
  3671. }
  3672. hr = S_OK;
  3673. done:
  3674. if (FAILED(hr))
  3675. {
  3676. delete pContext;
  3677. }
  3678. return hr;
  3679. }
  3680. //static
  3681. HRESULT
  3682. NOTIFY_CONTEXT::Initialize()
  3683. {
  3684. HRESULT hr = S_OK;
  3685. BOOL fRet = FALSE;
  3686. s_hShutdown = NULL;
  3687. s_hDataAvailable = NULL;
  3688. s_fInitializedCritSec = FALSE;
  3689. InitializeListHead(&s_listEntry);
  3690. fRet = InitializeCriticalSectionAndSpinCount(&s_critSec, 0x80000001);
  3691. if (FALSE == fRet)
  3692. {
  3693. hr = HRESULT_FROM_WIN32(GetLastError());
  3694. goto done;
  3695. }
  3696. s_fInitializedCritSec = TRUE;
  3697. s_hShutdown = CreateEvent(NULL, // security descrpitor
  3698. TRUE, // manual reset
  3699. FALSE, // initial state
  3700. NULL); // name
  3701. if (NULL == s_hShutdown)
  3702. {
  3703. hr = HRESULT_FROM_WIN32(GetLastError());
  3704. goto done;
  3705. }
  3706. s_hDataAvailable = CreateEvent(NULL, // security descriptor
  3707. FALSE, // auto reset
  3708. FALSE, // initial state
  3709. NULL); // name
  3710. if (NULL == s_hDataAvailable)
  3711. {
  3712. hr = HRESULT_FROM_WIN32(GetLastError());
  3713. goto done;
  3714. }
  3715. s_hThread = CreateThread(NULL,
  3716. 0,
  3717. NotifyThreadProc,
  3718. NULL,
  3719. 0,
  3720. &s_dwThreadId);
  3721. if (NULL == s_hThread)
  3722. {
  3723. hr = HRESULT_FROM_WIN32(GetLastError());
  3724. goto done;
  3725. }
  3726. hr = S_OK;
  3727. done:
  3728. return hr;
  3729. }
  3730. //static
  3731. VOID
  3732. NOTIFY_CONTEXT::RemoveWorkFor(
  3733. CADMCOMW *pCADMCOMW,
  3734. BOOL fWaitForCurrent)
  3735. {
  3736. LIST_ENTRY ListToDelete;
  3737. LIST_ENTRY *ple;
  3738. NOTIFY_CONTEXT *pContext;
  3739. LIST_ENTRY *pleNext;
  3740. CADMCOMW *pCurrentCADMCOMW;
  3741. if ( !s_fInitializedCritSec )
  3742. {
  3743. return;
  3744. }
  3745. InitializeListHead( &ListToDelete );
  3746. EnterCriticalSection(&s_critSec);
  3747. // eat all remaining data
  3748. ple = s_listEntry.Flink;
  3749. while ( ple != &s_listEntry )
  3750. {
  3751. pleNext = ple->Flink;
  3752. pContext = NOTIFY_CONTEXTFromListEntry( ple );
  3753. if ( pContext->_pCADMCOMW == pCADMCOMW )
  3754. {
  3755. RemoveEntryList( ple );
  3756. InitializeListHead( ple );
  3757. InsertTailList( &ListToDelete, ple );
  3758. }
  3759. pContext = NULL;
  3760. ple = pleNext;
  3761. }
  3762. LeaveCriticalSection(&s_critSec);
  3763. // Delete all collected notification contexts
  3764. ple = ListToDelete.Flink;
  3765. while ( ple != &ListToDelete )
  3766. {
  3767. pleNext = ple->Flink;
  3768. RemoveEntryList( ple );
  3769. InitializeListHead( ple );
  3770. pContext = NOTIFY_CONTEXTFromListEntry( ple );
  3771. delete pContext;
  3772. pContext = NULL;
  3773. ple = pleNext;
  3774. }
  3775. if ( fWaitForCurrent && ( s_dwThreadId != GetCurrentThreadId() ) )
  3776. {
  3777. do
  3778. {
  3779. s_LockCurrentlyWorkingOn.ReadLock();
  3780. if ( s_pCurrentlyWorkingOn != NULL )
  3781. {
  3782. pCurrentCADMCOMW = s_pCurrentlyWorkingOn->_pCADMCOMW;
  3783. }
  3784. else
  3785. {
  3786. pCurrentCADMCOMW = NULL;
  3787. }
  3788. s_LockCurrentlyWorkingOn.ReadUnlock();
  3789. // waiting for the NOTIFY_CONTEXT currently being processed to be
  3790. // released so we can return and guarantee that no more work is queued.
  3791. if ( pCADMCOMW == pCurrentCADMCOMW )
  3792. {
  3793. Sleep(100);
  3794. }
  3795. }
  3796. while ( pCADMCOMW == pCurrentCADMCOMW );
  3797. }
  3798. }
  3799. //static
  3800. VOID
  3801. NOTIFY_CONTEXT::RemoveAllWork( VOID )
  3802. {
  3803. LIST_ENTRY * ple;
  3804. NOTIFY_CONTEXT * pContext;
  3805. LIST_ENTRY * pleNext;
  3806. LIST_ENTRY ListToDelete;
  3807. BOOL fShutdownNotifications = FALSE;
  3808. if ( !s_fInitializedCritSec )
  3809. {
  3810. return;
  3811. }
  3812. InitializeListHead( &ListToDelete );
  3813. EnterCriticalSection( &s_critSec );
  3814. // Delete all data notifications
  3815. ple = s_listEntry.Flink;
  3816. while ( ple != &s_listEntry )
  3817. {
  3818. pleNext = ple->Flink;
  3819. pContext = NOTIFY_CONTEXTFromListEntry( ple );
  3820. if ( pContext->_bIsMainNotification )
  3821. {
  3822. RemoveEntryList( ple );
  3823. InitializeListHead( ple );
  3824. InsertTailList( &ListToDelete, ple );
  3825. }
  3826. else
  3827. {
  3828. fShutdownNotifications = TRUE;
  3829. }
  3830. pContext = NULL;
  3831. ple = pleNext;
  3832. }
  3833. LeaveCriticalSection( &s_critSec );
  3834. // Delete all collected notification contexts
  3835. ple = ListToDelete.Flink;
  3836. while ( ple != &ListToDelete )
  3837. {
  3838. pleNext = ple->Flink;
  3839. RemoveEntryList( ple );
  3840. InitializeListHead( ple );
  3841. pContext = NOTIFY_CONTEXTFromListEntry( ple );
  3842. delete pContext;
  3843. pContext = NULL;
  3844. ple = pleNext;
  3845. }
  3846. if ( fShutdownNotifications )
  3847. {
  3848. Sleep( 1000 );
  3849. }
  3850. EnterCriticalSection( &s_critSec );
  3851. ple = s_listEntry.Flink;
  3852. InitializeListHead( &s_listEntry );
  3853. LeaveCriticalSection( &s_critSec );
  3854. // eat all remaining data
  3855. while ( ple != &s_listEntry )
  3856. {
  3857. pleNext = ple->Flink;
  3858. InitializeListHead( ple );
  3859. pContext = NOTIFY_CONTEXTFromListEntry(ple);
  3860. delete pContext;
  3861. pContext = NULL;
  3862. ple = pleNext;
  3863. }
  3864. if ( s_dwThreadId != GetCurrentThreadId() )
  3865. {
  3866. while( s_pCurrentlyWorkingOn )
  3867. {
  3868. // waiting for the NOTIFY_CONTEXT currently being processed to be
  3869. // released so we can return and guarantee that no more work is queued.
  3870. Sleep(100);
  3871. }
  3872. }
  3873. }
  3874. //static
  3875. VOID
  3876. NOTIFY_CONTEXT::Terminate()
  3877. {
  3878. DWORD dwRet;
  3879. DBG_ASSERT(IsListEmpty(&s_listEntry));
  3880. if (s_hShutdown)
  3881. {
  3882. SetEvent(s_hShutdown);
  3883. }
  3884. if (s_hThread)
  3885. {
  3886. // need thread to terminate before shutting down more
  3887. dwRet = WaitForSingleObject(s_hThread, INFINITE);
  3888. DBG_ASSERT(WAIT_OBJECT_0 == dwRet);
  3889. CloseHandle(s_hThread);
  3890. s_hThread = NULL;
  3891. }
  3892. if (s_hDataAvailable)
  3893. {
  3894. CloseHandle(s_hDataAvailable);
  3895. s_hDataAvailable = NULL;
  3896. }
  3897. if (s_hShutdown)
  3898. {
  3899. CloseHandle(s_hShutdown);
  3900. s_hShutdown = NULL;
  3901. }
  3902. if (s_fInitializedCritSec)
  3903. {
  3904. DeleteCriticalSection(&s_critSec);
  3905. s_fInitializedCritSec = FALSE;
  3906. }
  3907. }
  3908. //static
  3909. HRESULT
  3910. NOTIFY_CONTEXT::GetNextContext(
  3911. NOTIFY_CONTEXT ** ppContext)
  3912. {
  3913. HRESULT hr = S_OK;
  3914. DWORD dwRet;
  3915. NOTIFY_CONTEXT * pContext = NULL;
  3916. PLIST_ENTRY ple;
  3917. HANDLE arrHandles[2];
  3918. DBG_ASSERT(ppContext != NULL);
  3919. *ppContext = NULL;
  3920. EnterCriticalSection(&s_critSec);
  3921. if (!IsListEmpty(&s_listEntry))
  3922. {
  3923. ple = RemoveHeadList(&s_listEntry);
  3924. InitializeListHead( ple );
  3925. pContext = NOTIFY_CONTEXTFromListEntry(ple);
  3926. }
  3927. LeaveCriticalSection(&s_critSec);
  3928. arrHandles[0] = s_hDataAvailable;
  3929. arrHandles[1] = s_hShutdown;
  3930. while ( pContext == NULL )
  3931. {
  3932. dwRet = WaitForMultipleObjects( 2,
  3933. arrHandles,
  3934. FALSE,
  3935. INFINITE);
  3936. if (dwRet == WAIT_OBJECT_0)
  3937. {
  3938. // data was signalled as available
  3939. EnterCriticalSection(&s_critSec);
  3940. if (!IsListEmpty(&s_listEntry))
  3941. {
  3942. ple = RemoveHeadList(&s_listEntry);
  3943. InitializeListHead( ple );
  3944. pContext = NOTIFY_CONTEXTFromListEntry(ple);
  3945. }
  3946. LeaveCriticalSection(&s_critSec);
  3947. }
  3948. else if (dwRet == WAIT_OBJECT_0 + 1)
  3949. {
  3950. hr = HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  3951. goto done;
  3952. }
  3953. else
  3954. {
  3955. DBG_ASSERT( ( dwRet == WAIT_OBJECT_0 ) || ( dwRet == WAIT_OBJECT_0+1 ) );
  3956. hr = E_UNEXPECTED;
  3957. goto done;
  3958. }
  3959. }
  3960. DBG_ASSERT( pContext );
  3961. s_LockCurrentlyWorkingOn.WriteLock();
  3962. s_pCurrentlyWorkingOn = pContext;
  3963. s_LockCurrentlyWorkingOn.WriteUnlock();
  3964. *ppContext = pContext;
  3965. pContext = NULL;
  3966. hr = S_OK;
  3967. done:
  3968. DBG_ASSERT( pContext == NULL );
  3969. return hr;
  3970. }
  3971. //static
  3972. DWORD WINAPI
  3973. NOTIFY_CONTEXT::NotifyThreadProc(
  3974. LPVOID )
  3975. {
  3976. HRESULT hr = S_OK;
  3977. CADMCOMW *pCADMCOMW;
  3978. NOTIFY_CONTEXT *pContext = NULL;
  3979. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  3980. if (FAILED(hr))
  3981. {
  3982. // bleh. Nothing to be done then.
  3983. return (DWORD)-1;
  3984. }
  3985. for( ; ; )
  3986. {
  3987. hr = NOTIFY_CONTEXT::GetNextContext(&pContext);
  3988. if (FAILED(hr))
  3989. {
  3990. goto done;
  3991. }
  3992. DBG_ASSERT(NULL != pContext);
  3993. DBG_ASSERT(NULL != pContext->_pCADMCOMW);
  3994. pCADMCOMW = pContext->_pCADMCOMW;
  3995. // Keep the object alive during the call to NotifySinksAsync
  3996. pCADMCOMW->AddRef();
  3997. pCADMCOMW->NotifySinksAsync(
  3998. pContext->_dwMDNumElements,
  3999. pContext->_pcoChangeList,
  4000. pContext->_bIsMainNotification );
  4001. delete pContext;
  4002. // Release after deleting the context
  4003. pCADMCOMW->Release();
  4004. pCADMCOMW = NULL;
  4005. }
  4006. done:
  4007. CoUninitialize();
  4008. return 0;
  4009. }
  4010. HRESULT
  4011. CADMCOMW::NotifySinksAsync(
  4012. DWORD dwMDNumElements,
  4013. MD_CHANGE_OBJECT_W pcoChangeList[],
  4014. BOOL bIsMainNotification)
  4015. {
  4016. HRESULT hr = S_OK;
  4017. CONNECTDATA *pConnData = NULL;
  4018. ULONG cConnData = 0;
  4019. ULONG i;
  4020. if ( m_bTerminated )
  4021. {
  4022. goto exit;
  4023. }
  4024. hr = m_ConnectionPoint.ListenersPresent();
  4025. if ( hr != S_OK )
  4026. {
  4027. goto exit;
  4028. }
  4029. hr = m_ConnectionPoint.InternalEnumSinks( &pConnData, &cConnData );
  4030. if ( FAILED( hr ) || ( cConnData == 0 ) )
  4031. {
  4032. goto exit;
  4033. }
  4034. // Loop thru the connection point's connections
  4035. // and dispatch the event notification to that sink.
  4036. for ( i = 0; i<cConnData; i++ )
  4037. {
  4038. DBG_ASSERT( pConnData[i].pUnk != NULL );
  4039. // Notify the sink
  4040. NotifySinkHelper( pConnData[i].pUnk,
  4041. dwMDNumElements,
  4042. pcoChangeList,
  4043. bIsMainNotification );
  4044. pConnData[i].pUnk->Release();
  4045. pConnData[i].pUnk = NULL;
  4046. pConnData[i].dwCookie = 0;
  4047. }
  4048. exit:
  4049. if ( pConnData != NULL )
  4050. {
  4051. for ( i = 0; i<cConnData; i++ )
  4052. {
  4053. if ( pConnData[i].pUnk != NULL )
  4054. {
  4055. pConnData[i].pUnk->Release();
  4056. pConnData[i].pUnk = NULL;
  4057. }
  4058. }
  4059. delete [] pConnData;
  4060. pConnData = NULL;
  4061. }
  4062. return hr;
  4063. }
  4064. HRESULT
  4065. CADMCOMW::NotifySinkHelper(
  4066. IUnknown *pUnk,
  4067. DWORD dwMDNumElements,
  4068. MD_CHANGE_OBJECT_W pcoChangeList[],
  4069. BOOL bIsMainNotification)
  4070. {
  4071. // Locals
  4072. HRESULT hr = S_OK;
  4073. ICallFactory *pCF = NULL;
  4074. IMSAdminBaseSinkW *pIADMCOMSINKW_Synchro = NULL;
  4075. AsyncIMSAdminBaseSinkW *pIADMCOMSINKW_Async = NULL;
  4076. // Check args
  4077. DBG_ASSERT( pUnk != NULL );
  4078. if ( pUnk == NULL )
  4079. {
  4080. hr = E_INVALIDARG;
  4081. goto exit;
  4082. }
  4083. // If we are talking to a proxy
  4084. if ( m_dwProcessIdCaller != sm_dwProcessIdThis )
  4085. {
  4086. //
  4087. // asynchronous callback
  4088. //
  4089. // Get the call factory
  4090. hr = pUnk->QueryInterface( IID_ICallFactory,
  4091. (VOID**)&pCF );
  4092. if ( FAILED( hr ) )
  4093. {
  4094. DBGPRINTF(( DBG_CONTEXT, "Failled in to get ICallFactory !!!\n" ));
  4095. goto exit;
  4096. }
  4097. // Create a asynchronous call
  4098. hr = pCF->CreateCall( IID_AsyncIMSAdminBaseSink_W,
  4099. NULL,
  4100. IID_AsyncIMSAdminBaseSink_W,
  4101. (IUnknown**)&pIADMCOMSINKW_Async );
  4102. if ( FAILED( hr ) )
  4103. {
  4104. DBGPRINTF(( DBG_CONTEXT, "Failled in CreateCall to ICallFactory !!!\n" ));
  4105. goto exit;
  4106. }
  4107. // Set the impersonation level to identify to prevent
  4108. // elevation to LocalSystem in the client process.
  4109. hr = SetSinkCallbackSecurityBlanket( pIADMCOMSINKW_Async );
  4110. if ( FAILED( hr ) )
  4111. {
  4112. DBGPRINTF(( DBG_CONTEXT, "SetSinkCallbackSecurityBlanket failled for the async sink !!!\n" ));
  4113. goto exit;
  4114. }
  4115. if (bIsMainNotification)
  4116. {
  4117. hr = pIADMCOMSINKW_Async->Begin_SinkNotify( dwMDNumElements,
  4118. pcoChangeList );
  4119. }
  4120. else
  4121. {
  4122. hr = pIADMCOMSINKW_Async->Begin_ShutdownNotify();
  4123. }
  4124. }
  4125. else
  4126. {
  4127. // The client is inproc -> synchronous notifications
  4128. //
  4129. // synchronous callback
  4130. //
  4131. hr = pUnk->QueryInterface( IID_IMSAdminBaseSink_W,
  4132. (VOID**)&pIADMCOMSINKW_Synchro );
  4133. if ( FAILED( hr ) )
  4134. {
  4135. DBGPRINTF(( DBG_CONTEXT, "Failled in QueryInterface for IID_IMSAdminBaseSink_W\n" ));
  4136. goto exit;
  4137. }
  4138. if (bIsMainNotification)
  4139. {
  4140. hr = pIADMCOMSINKW_Synchro->SinkNotify( dwMDNumElements,
  4141. pcoChangeList );
  4142. }
  4143. else
  4144. {
  4145. hr = pIADMCOMSINKW_Synchro->ShutdownNotify();
  4146. }
  4147. }
  4148. exit:
  4149. if ( pIADMCOMSINKW_Synchro != NULL )
  4150. {
  4151. pIADMCOMSINKW_Synchro->Release();
  4152. pIADMCOMSINKW_Synchro = NULL;
  4153. }
  4154. if ( pIADMCOMSINKW_Async != NULL )
  4155. {
  4156. pIADMCOMSINKW_Async->Release();
  4157. pIADMCOMSINKW_Async = NULL;
  4158. }
  4159. if ( pCF != NULL )
  4160. {
  4161. pCF->Release();
  4162. pCF = NULL;
  4163. }
  4164. return hr;
  4165. }
  4166. //
  4167. // Stubs for routine that clients shouldn't be calling anyway.
  4168. //
  4169. HRESULT
  4170. CADMCOMW::KeyExchangePhase1()
  4171. {
  4172. return E_FAIL;
  4173. }
  4174. HRESULT
  4175. CADMCOMW::KeyExchangePhase2()
  4176. {
  4177. return E_FAIL;
  4178. }
  4179. HRESULT STDMETHODCALLTYPE
  4180. CADMCOMW::GetServerGuid( void)
  4181. {
  4182. return E_FAIL;
  4183. }
  4184. HRESULT STDMETHODCALLTYPE
  4185. CADMCOMW::UnmarshalInterface(
  4186. IMSAdminBaseW * *piadmbwInterface)
  4187. {
  4188. AddRef(); // Always return interfaces addref'ed
  4189. *piadmbwInterface = (IMSAdminBaseW *)this;
  4190. return (S_OK);
  4191. }
  4192. BOOL
  4193. CADMCOMW::CheckGetAttributes(
  4194. DWORD dwAttributes)
  4195. {
  4196. DWORD dwReturn = TRUE;
  4197. if ((dwAttributes & METADATA_REFERENCE) ||
  4198. ((dwAttributes & METADATA_PARTIAL_PATH) &&
  4199. !(dwAttributes & METADATA_INHERIT)))
  4200. {
  4201. dwReturn = FALSE;
  4202. }
  4203. return dwReturn;
  4204. }
  4205. VOID
  4206. WaitForServiceStatus(
  4207. SC_HANDLE schDependent,
  4208. DWORD dwDesiredServiceState)
  4209. {
  4210. DWORD dwSleepTotal = 0;
  4211. SERVICE_STATUS ssDependent;
  4212. while (dwSleepTotal < MAX_SLEEP)
  4213. {
  4214. if (QueryServiceStatus(schDependent, &ssDependent))
  4215. {
  4216. if (ssDependent.dwCurrentState == dwDesiredServiceState)
  4217. {
  4218. break;
  4219. }
  4220. else
  4221. {
  4222. //
  4223. // Still pending...
  4224. //
  4225. Sleep(SLEEP_INTERVAL);
  4226. dwSleepTotal += SLEEP_INTERVAL;
  4227. }
  4228. }
  4229. else
  4230. {
  4231. break;
  4232. }
  4233. }
  4234. }
  4235. DWORD
  4236. CADMCOMW::IsReadAccessGranted(
  4237. METADATA_HANDLE hHandle,
  4238. LPWSTR pszPath,
  4239. METADATA_RECORD* pmdRecord)
  4240. /*++
  4241. Routine Description:
  4242. Check if read access to property granted based on ACL visible at point in metabase
  4243. where property is stored ( as opposed as check made by AdminAclAccessCheck which uses
  4244. the ACL visible at path specified during data access )
  4245. Arguments:
  4246. hHandle - DCOM metabase handle
  4247. pszPath - path relative to hHandle
  4248. pmdRecord - metadata info to access property
  4249. Returns:
  4250. ERROR_SUCCESS if access granted, otherwise error code
  4251. --*/
  4252. {
  4253. DWORD dwStatus = ERROR_SUCCESS;
  4254. LPWSTR pszPropPath;
  4255. //
  4256. // If property is not inherited then we already checked the correct ACL
  4257. //
  4258. if ( !(pmdRecord->dwMDAttributes & METADATA_ISINHERITED) )
  4259. {
  4260. return dwStatus;
  4261. }
  4262. // determine from where we got it
  4263. // do AccessCheck
  4264. if ( (dwStatus = FindClosestProp( hHandle,
  4265. pszPath,
  4266. &pszPropPath,
  4267. pmdRecord->dwMDIdentifier,
  4268. pmdRecord->dwMDDataType,
  4269. pmdRecord->dwMDUserType,
  4270. METADATA_SECURE,
  4271. TRUE )) == ERROR_SUCCESS )
  4272. {
  4273. if ( pszPropPath ) // i.e such a property exist
  4274. {
  4275. dwStatus = AdminAclAccessCheck( m_pMdObject,
  4276. (LPVOID)this,
  4277. METADATA_MASTER_ROOT_HANDLE,
  4278. pszPropPath,
  4279. pmdRecord->dwMDIdentifier,
  4280. METADATA_PERMISSION_READ,
  4281. &g_ohMasterRootHandle ) ?
  4282. ERROR_SUCCESS :
  4283. GetLastError();
  4284. LocalFree( pszPropPath );
  4285. }
  4286. else
  4287. {
  4288. dwStatus = MD_ERROR_DATA_NOT_FOUND;
  4289. //
  4290. // Should not happen unless handle is master root :
  4291. // if we are here then we succeeded accessing data and as we have a read handle
  4292. // nobody should be able to delete it
  4293. // if master root handle we don't have such protection, so property could
  4294. // have been deleted.
  4295. //
  4296. DBG_ASSERT ( METADATA_MASTER_ROOT_HANDLE == hHandle );
  4297. }
  4298. }
  4299. return dwStatus;
  4300. }
  4301. DWORD
  4302. CADMCOMW::FindClosestProp(
  4303. METADATA_HANDLE hHandle,
  4304. LPWSTR pszRelPath,
  4305. LPWSTR* ppszPropPath,
  4306. DWORD dwPropId,
  4307. DWORD dwDataType,
  4308. DWORD dwUserType,
  4309. DWORD dwAttr,
  4310. BOOL fSkipCurrentNode)
  4311. /*++
  4312. Routine Description:
  4313. Find the closest path where the specified property exist ( in the direction of
  4314. the root ) in metabase
  4315. Arguments:
  4316. hHandle - DCOM metabase handle
  4317. pszRelPath - path relative to hHandle
  4318. ppszPropPath - updated with path to property or NULL if property not found
  4319. dwPropId - property ID
  4320. dwDataType - property data type
  4321. dwUserType - property user type
  4322. dwAttr - property attribute
  4323. fSkipCurrentNode - TRUE to skip current node while scanning for property
  4324. Returns:
  4325. TRUE if success ( including property not found ), otherwise FALSE
  4326. --*/
  4327. {
  4328. DWORD dwReturn;
  4329. LPWSTR pszParentPath;
  4330. METADATA_HANDLE hActualHandle;
  4331. COpenHandle *pohParent;
  4332. HRESULT hRes;
  4333. METADATA_RECORD mdRecord;
  4334. DWORD dwRequiredLen;
  4335. LPWSTR pszPath;
  4336. BOOL fFound;
  4337. DWORD dwRelPathLen;
  4338. DWORD dwParentPathLen;
  4339. DWORD dwTotalSize;
  4340. dwReturn = Lookup( hHandle,
  4341. &hActualHandle,
  4342. &pohParent);
  4343. if ( dwReturn != ERROR_SUCCESS )
  4344. {
  4345. return dwReturn;
  4346. }
  4347. pszParentPath = pohParent->GetPath();
  4348. if (pszRelPath == NULL)
  4349. {
  4350. pszRelPath = L"";
  4351. }
  4352. DBG_ASSERT(pszParentPath != NULL);
  4353. DBG_ASSERT((*pszParentPath == (WCHAR)'\0') ||
  4354. ISPATHDELIMW(*pszParentPath));
  4355. //
  4356. // Strip front slash now, add it in later
  4357. //
  4358. if (ISPATHDELIMW(*pszRelPath))
  4359. {
  4360. pszRelPath++;
  4361. }
  4362. dwRelPathLen = (DWORD)wcslen(pszRelPath);
  4363. dwParentPathLen = (DWORD)wcslen(pszParentPath);
  4364. DBG_ASSERT((dwParentPathLen == 0) ||
  4365. (!ISPATHDELIMW(pszParentPath[dwParentPathLen -1])));
  4366. //
  4367. // Get rid of trailing slash for good
  4368. //
  4369. if ((dwRelPathLen > 0) && (ISPATHDELIMW(pszRelPath[dwRelPathLen -1])))
  4370. {
  4371. dwRelPathLen--;
  4372. }
  4373. //
  4374. // Include space for mid slash if Relpath exists
  4375. // Include space for termination
  4376. //
  4377. dwTotalSize =
  4378. (dwRelPathLen + dwParentPathLen + 1 + ((dwRelPathLen > 0) ? 1 : 0)) * sizeof(WCHAR);
  4379. *ppszPropPath = pszPath = (LPWSTR)LocalAlloc(LMEM_FIXED, dwTotalSize);
  4380. if (pszPath == NULL)
  4381. {
  4382. dwReturn = GetLastError();
  4383. }
  4384. else
  4385. {
  4386. //
  4387. // OK to always copy the first part
  4388. //
  4389. memcpy(pszPath,
  4390. pszParentPath,
  4391. dwParentPathLen * sizeof(WCHAR));
  4392. //
  4393. // Don't need slash if there is no RelPath
  4394. //
  4395. if (dwRelPathLen > 0)
  4396. {
  4397. pszPath[dwParentPathLen] = (WCHAR)'/';
  4398. memcpy(pszPath + dwParentPathLen + 1,
  4399. pszRelPath,
  4400. dwRelPathLen * sizeof(WCHAR));
  4401. }
  4402. pszPath[(dwTotalSize / sizeof(WCHAR)) - 1] = (WCHAR)'\0';
  4403. //
  4404. // Now convert \ to / for string compares
  4405. //
  4406. LPWSTR pszPathIndex = pszPath;
  4407. while ((pszPathIndex = wcschr(pszPathIndex, (WCHAR)'\\')) != NULL)
  4408. {
  4409. *pszPathIndex = (WCHAR)'/';
  4410. }
  4411. // scan for property
  4412. pszPathIndex = pszPath + wcslen(pszPath);
  4413. for ( ; ; )
  4414. {
  4415. if ( !fSkipCurrentNode )
  4416. {
  4417. // check prop exist
  4418. mdRecord.dwMDIdentifier = dwPropId;
  4419. mdRecord.dwMDAttributes = dwAttr;
  4420. mdRecord.dwMDUserType = dwUserType;
  4421. mdRecord.dwMDDataType = dwDataType;
  4422. mdRecord.dwMDDataLen = 0;
  4423. mdRecord.pbMDData = NULL;
  4424. mdRecord.dwMDDataTag = NULL;
  4425. hRes = m_pMdObject->ComMDGetMetaDataW( METADATA_MASTER_ROOT_HANDLE,
  4426. pszPath,
  4427. &mdRecord,
  4428. &dwRequiredLen );
  4429. if ( hRes == RETURNCODETOHRESULT(ERROR_INSUFFICIENT_BUFFER) )
  4430. {
  4431. break;
  4432. }
  4433. }
  4434. // scan backward for delimiter
  4435. fFound = FALSE;
  4436. if ( pszPathIndex > pszPath )
  4437. {
  4438. do
  4439. {
  4440. if ( *--pszPathIndex == L'/' )
  4441. {
  4442. *pszPathIndex = L'\0';
  4443. fFound = TRUE;
  4444. break;
  4445. }
  4446. } while ( pszPathIndex > pszPath );
  4447. }
  4448. if ( !fFound )
  4449. {
  4450. // Property not found, return OK status with NULL string
  4451. *ppszPropPath = NULL;
  4452. LocalFree( pszPath );
  4453. break;
  4454. }
  4455. fSkipCurrentNode = FALSE;
  4456. }
  4457. }
  4458. pohParent->Release( this );
  4459. return dwReturn;
  4460. }
  4461. BOOL
  4462. MakeParentPath(
  4463. LPWSTR pszPath)
  4464. /*++
  4465. Routine Description:
  4466. Make the path points to parent
  4467. Arguments:
  4468. pszPath - path to adjust
  4469. Returns:
  4470. TRUE if success, otherwise FALSE ( no parent )
  4471. --*/
  4472. {
  4473. LPWSTR pszPathIndex = pszPath + wcslen( pszPath );
  4474. BOOL fFound = FALSE;
  4475. while ( pszPathIndex > pszPath )
  4476. {
  4477. if ( *--pszPathIndex == L'/' )
  4478. {
  4479. *pszPathIndex = L'\0';
  4480. fFound = TRUE;
  4481. break;
  4482. }
  4483. }
  4484. return fFound;
  4485. }
  4486. HRESULT
  4487. CADMCOMW::InitializeCallerWatch(VOID)
  4488. /*++
  4489. Routine Description:
  4490. Sets up watching the caller process.
  4491. Arguments:
  4492. none
  4493. Returns:
  4494. HRESULT.
  4495. --*/
  4496. {
  4497. // Locals
  4498. HRESULT hr = S_OK;
  4499. RPC_STATUS RpcStatus = RPC_S_OK;
  4500. HANDLE hProcessCaller = NULL;
  4501. HANDLE hWaitCaller = NULL;
  4502. HANDLE hToken = NULL;
  4503. IServerSecurity *pServerSecurity = NULL;
  4504. unsigned int fClientLocal = 0;
  4505. DWORD dwProcessId = 0;
  4506. BOOL fRet;
  4507. // If already initialized
  4508. if ( IsCallerWatchInitialized() )
  4509. {
  4510. // Just exit
  4511. goto exit;
  4512. }
  4513. // Get the COM context for the call
  4514. hr = CoGetCallContext( IID_IServerSecurity, (VOID**)&pServerSecurity );
  4515. if ( FAILED( hr ) )
  4516. {
  4517. // Succeess if there is no call context (inproc call).
  4518. if ( hr == RPC_E_CALL_COMPLETE )
  4519. {
  4520. // This is not a failure
  4521. hr = S_OK;
  4522. // The caller is our process
  4523. m_dwProcessIdCaller = sm_dwProcessIdThis;
  4524. }
  4525. if ( FAILED( hr ) )
  4526. {
  4527. DBGPRINTF(( DBG_CONTEXT,
  4528. "CoGetCallContext() failed in InitializeCallerWatch hr=0x%08x.\n",
  4529. hr ));
  4530. }
  4531. // Bail out
  4532. goto exit;
  4533. }
  4534. // Check whether the client is on the same machine
  4535. RpcStatus = I_RpcBindingIsClientLocal( NULL, &fClientLocal );
  4536. // Not a RPC call?
  4537. if ( ( RpcStatus == RPC_S_NO_CALL_ACTIVE ) ||
  4538. ( RpcStatus == RPC_S_INVALID_BINDING ) )
  4539. {
  4540. // The caller is our process
  4541. m_dwProcessIdCaller = sm_dwProcessIdThis;
  4542. goto exit;
  4543. }
  4544. // Remote client?
  4545. if ( ( RpcStatus == RPC_S_OK ) &&
  4546. ( fClientLocal == 0 ) )
  4547. {
  4548. // There is no way to watch the caller
  4549. m_dwProcessIdCaller = (DWORD)-1;
  4550. goto exit;
  4551. }
  4552. // Failed?
  4553. if ( ( RpcStatus != RPC_S_OK ) &&
  4554. ( RpcStatus != RPC_S_CANNOT_SUPPORT ) )
  4555. {
  4556. hr = HRESULT_FROM_WIN32( RpcStatus );
  4557. DBGPRINTF(( DBG_CONTEXT,
  4558. "I_RpcBindingIsClientLocal() failed in InitializeCallerWatch hr=0x%08x.\n",
  4559. hr ));
  4560. goto exit;
  4561. }
  4562. // Try to get the caller pid
  4563. RpcStatus = I_RpcBindingInqLocalClientPID( NULL, &dwProcessId );
  4564. // Not a RPC call?
  4565. if ( ( RpcStatus == RPC_S_NO_CALL_ACTIVE ) ||
  4566. ( RpcStatus == RPC_S_INVALID_BINDING ) )
  4567. {
  4568. // The caller is our process
  4569. m_dwProcessIdCaller = sm_dwProcessIdThis;
  4570. goto exit;
  4571. }
  4572. // Failed?
  4573. if ( RpcStatus != RPC_S_OK )
  4574. {
  4575. hr = HRESULT_FROM_WIN32( RpcStatus );
  4576. DBGPRINTF(( DBG_CONTEXT,
  4577. "I_RpcBindingInqLocalClientPID() failed in InitializeCallerWatch hr=0x%08x.\n",
  4578. hr ));
  4579. goto exit;
  4580. }
  4581. // If the caller is RpcSs
  4582. if ( dwProcessId == sm_dwProcessIdRpcSs )
  4583. {
  4584. // wait for the next call to come
  4585. goto exit;
  4586. }
  4587. // If the caller is in our process
  4588. if ( dwProcessId == sm_dwProcessIdThis )
  4589. {
  4590. // Save the caller pid
  4591. m_dwProcessIdCaller = sm_dwProcessIdThis;
  4592. // Not need to watch outself
  4593. goto exit;
  4594. }
  4595. // Try to get the thread impersonation token
  4596. fRet = OpenThreadToken( GetCurrentThread(),
  4597. TOKEN_IMPERSONATE | TOKEN_QUERY,
  4598. TRUE,
  4599. &hToken );
  4600. DBG_ASSERT( !fRet || hToken );
  4601. // Check whether the thread was impersonated
  4602. if ( fRet && ( hToken != NULL ) )
  4603. {
  4604. // Revet to LocalSystem
  4605. fRet = RevertToSelf();
  4606. if ( !fRet )
  4607. {
  4608. hr = HRESULT_FROM_WIN32( GetLastError() );
  4609. DBGPRINTF(( DBG_CONTEXT,
  4610. "RevertToSelf() failed in InitializeCallerWatch hr=0x%08x.\n",
  4611. hr ));
  4612. // Since RevertToSelf failed do not try to impersonate
  4613. CloseHandle( hToken );
  4614. hToken = NULL;
  4615. goto exit;
  4616. }
  4617. }
  4618. // Open the process
  4619. hProcessCaller = OpenProcess( SYNCHRONIZE,
  4620. FALSE,
  4621. dwProcessId );
  4622. if ( hProcessCaller == NULL )
  4623. {
  4624. hr = HRESULT_FROM_WIN32( GetLastError() );
  4625. DBGPRINTF(( DBG_CONTEXT,
  4626. "OpenProcess() failed in InitializeCallerWatch hr=0x%08x.\n",
  4627. hr ));
  4628. goto exit;
  4629. }
  4630. // Register wait for the process to end
  4631. fRet = RegisterWaitForSingleObject( &hWaitCaller,
  4632. hProcessCaller,
  4633. CallerWatchWaitOrTimerCallback,
  4634. this,
  4635. INFINITE,
  4636. WT_EXECUTEONLYONCE);
  4637. if ( !fRet )
  4638. {
  4639. hr = HRESULT_FROM_WIN32( GetLastError() );
  4640. DBGPRINTF(( DBG_CONTEXT,
  4641. "RegisterWaitForSingleObject() failed in InitializeCallerWatch hr=0x%08x.\n",
  4642. hr ));
  4643. goto exit;
  4644. }
  4645. DBG_ASSERT( hWaitCaller != NULL );
  4646. // Save the handles in the object
  4647. if ( NULL == InterlockedCompareExchangePointer( &m_hProcessCaller,
  4648. hProcessCaller,
  4649. NULL ) )
  4650. {
  4651. m_hWaitCaller = hWaitCaller;
  4652. m_dwProcessIdCaller = dwProcessId;
  4653. hProcessCaller = NULL;
  4654. hWaitCaller = NULL;
  4655. }
  4656. DBG_ASSERT( m_dwProcessIdCaller == dwProcessId );
  4657. exit:
  4658. // Cleanup
  4659. if ( pServerSecurity )
  4660. {
  4661. pServerSecurity->Release();
  4662. pServerSecurity = NULL;
  4663. }
  4664. if ( hWaitCaller != NULL)
  4665. {
  4666. UnregisterWaitEx( hWaitCaller, INVALID_HANDLE_VALUE );
  4667. hWaitCaller = NULL;
  4668. }
  4669. if ( hProcessCaller != NULL )
  4670. {
  4671. CloseHandle( hProcessCaller );
  4672. hProcessCaller = NULL;
  4673. }
  4674. if ( hToken )
  4675. {
  4676. fRet = ImpersonateLoggedOnUser( hToken );
  4677. if ( !fRet )
  4678. {
  4679. hr = HRESULT_FROM_WIN32( GetLastError() );
  4680. DBGPRINTF(( DBG_CONTEXT,
  4681. "ImpersonateLoggedOnUser() failed in InitializeCallerWatch hr=0x%08x.\n",
  4682. hr ));
  4683. }
  4684. CloseHandle( hToken );
  4685. hToken = NULL;
  4686. }
  4687. DBG_ASSERT( SUCCEEDED( hr ) );
  4688. // Done
  4689. return hr;
  4690. }
  4691. HRESULT
  4692. CADMCOMW::ShutdownCallerWatch(VOID)
  4693. /*++
  4694. Routine Description:
  4695. Shuts down watching the caller process.
  4696. Arguments:
  4697. none
  4698. Returns:
  4699. HRESULT.
  4700. --*/
  4701. {
  4702. // Locals
  4703. HRESULT hr = S_OK;
  4704. BOOL fRet;
  4705. HANDLE hWaitCaller = NULL;
  4706. HANDLE hProcessCaller = NULL;
  4707. DWORD dwOldThreadId;
  4708. DWORD dwThreadId = GetCurrentThreadId();
  4709. // Set the thread id
  4710. dwOldThreadId = InterlockedCompareExchange( (LONG*)&m_dwThreadIdDisconnect,
  4711. (LONG)dwThreadId,
  4712. 0 );
  4713. // Get the wait object
  4714. hWaitCaller = InterlockedExchangePointer( &m_hWaitCaller, NULL );
  4715. // If not initialized/already closed
  4716. if ( hWaitCaller == NULL )
  4717. {
  4718. // Nothing
  4719. goto exit;
  4720. }
  4721. // Get the process
  4722. hProcessCaller = InterlockedExchangePointer( &m_hProcessCaller, NULL );
  4723. // If we are in the same thread as the callback function
  4724. // we cannot wait for it to finish
  4725. if ( dwOldThreadId == dwThreadId )
  4726. {
  4727. // Delete the registered wait for the caller process
  4728. // NULL passed as completion event causes
  4729. // UnregisterWaitEx to return w/o blocking
  4730. fRet = UnregisterWaitEx( hWaitCaller, NULL );
  4731. // The call fails with ERROR_IO_PENDING if the callback function
  4732. // is still running (which is expected, because it called us indirectly),
  4733. // but any other error is failure
  4734. if ( !fRet && ( GetLastError() == ERROR_IO_PENDING ) )
  4735. {
  4736. // This is not a failure
  4737. fRet = TRUE;
  4738. SetLastError( ERROR_SUCCESS );
  4739. }
  4740. }
  4741. else
  4742. {
  4743. // Delete the registered wait for the caller process
  4744. // INVALID_HANDLE_VALUE passed as completion event causes
  4745. // UnregisterWaitEx not to return until the callback function returns
  4746. fRet = UnregisterWaitEx( hWaitCaller, INVALID_HANDLE_VALUE );
  4747. }
  4748. hWaitCaller = NULL;
  4749. if ( !fRet )
  4750. {
  4751. hr = HRESULT_FROM_WIN32( GetLastError() );
  4752. DBGPRINTF(( DBG_CONTEXT,
  4753. "UnregisterWaitEx() failed in ShutdownCallerWatch hr=0x%08x.\n",
  4754. hr ));
  4755. goto exit;
  4756. }
  4757. exit:
  4758. if ( hProcessCaller )
  4759. {
  4760. // Close the process handle
  4761. CloseHandle( hProcessCaller );
  4762. hProcessCaller = NULL;
  4763. }
  4764. if ( dwOldThreadId == 0 )
  4765. {
  4766. // Restore the thread id
  4767. dwOldThreadId = InterlockedCompareExchange( (LONG*)&m_dwThreadIdDisconnect,
  4768. 0,
  4769. (LONG)dwThreadId );
  4770. DBG_ASSERT( dwOldThreadId == dwThreadId );
  4771. }
  4772. DBG_ASSERT( SUCCEEDED( hr ) );
  4773. // Done
  4774. return hr;
  4775. }
  4776. HRESULT
  4777. CADMCOMW::DisconnectOrphaned(VOID)
  4778. /*++
  4779. Routine Description:
  4780. Calls CoDisconnectObject on the object and the connection point.
  4781. Arguments:
  4782. none
  4783. Returns:
  4784. HRESULT.
  4785. --*/
  4786. {
  4787. // Locals
  4788. HRESULT hr = S_OK;
  4789. DWORD dwOldThreadId = (DWORD)-1;
  4790. DWORD dwThreadId = GetCurrentThreadId();
  4791. DWORD cRef = 0;
  4792. // If already terminated
  4793. if ( m_bTerminated )
  4794. {
  4795. // Do nothing
  4796. goto exit;
  4797. }
  4798. // Set the thread id
  4799. dwOldThreadId = InterlockedCompareExchange( (LONG*)&m_dwThreadIdDisconnect,
  4800. (LONG)dwThreadId,
  4801. 0 );
  4802. if ( dwOldThreadId != 0 )
  4803. {
  4804. goto exit;
  4805. }
  4806. // AddRef, to prevent the object being destroyed by one of the CoDisconnect calls
  4807. AddRef();
  4808. // Disconnect the object
  4809. CoDisconnectObject( static_cast<IUnknown*>( this ), 0 );
  4810. // Disconnect the connection point
  4811. CoDisconnectObject( static_cast<IConnectionPoint*>( &m_ConnectionPoint ), 0 );
  4812. // Stop getting and firing notifications.
  4813. // This is a forcible termination so remove all pending notifications
  4814. StopNotifications( TRUE );
  4815. // Release (which may delete the object)
  4816. cRef = Release();
  4817. exit:
  4818. if ( ( cRef > 1 ) && ( dwOldThreadId == 0 ) )
  4819. {
  4820. // Set the thread id
  4821. dwOldThreadId = InterlockedCompareExchange( (LONG*)&m_dwThreadIdDisconnect,
  4822. 0,
  4823. (LONG)dwThreadId );
  4824. DBG_ASSERT( dwOldThreadId == dwThreadId );
  4825. }
  4826. DBG_ASSERT( SUCCEEDED( hr ) );
  4827. // Done
  4828. return hr;
  4829. }
  4830. VOID
  4831. CALLBACK
  4832. CADMCOMW::CallerWatchWaitOrTimerCallback(
  4833. PVOID lpParameter, // thread data
  4834. BOOLEAN TimerOrWaitFired) // reason
  4835. /*++
  4836. Routine Description:
  4837. Passed as a callback to RegisterWaitForSingleObject.
  4838. Called when the caller process terminates.
  4839. CoDisconnects the object to force COM to release it before the 10 min timeout.
  4840. Arguments:
  4841. lpParameter - the callback context passed to RegisterWaitForSingleObject.
  4842. Must be the CADMCOMW object used by the process waiting on.
  4843. TimerOrWaitFired - The reason to call the callback. Since we are waiting
  4844. on the handle for INFINITE time must be always FALSE.
  4845. Returns:
  4846. VOID.
  4847. --*/
  4848. {
  4849. // Locals
  4850. HRESULT hr = S_OK;
  4851. CADMCOMW *pThis;
  4852. BOOL fUninitCom = FALSE;
  4853. DBG_ASSERT( lpParameter != NULL );
  4854. DBG_ASSERT( TimerOrWaitFired == FALSE );
  4855. // Check
  4856. if ( ( lpParameter == NULL ) || ( TimerOrWaitFired != FALSE ) )
  4857. {
  4858. hr = E_INVALIDARG;
  4859. DBGPRINTF(( DBG_CONTEXT,
  4860. "Invadil args passed to CallerWatchWaitOrTimerCallback.\n",
  4861. hr ));
  4862. goto exit;
  4863. }
  4864. // Initialize COM
  4865. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  4866. // If succeeded
  4867. if ( SUCCEEDED( hr ) )
  4868. {
  4869. // Remember to uninit
  4870. fUninitCom = TRUE;
  4871. }
  4872. // If already initialized w/ different model
  4873. if ( hr == RPC_E_CHANGED_MODE )
  4874. {
  4875. // Ok it is thread is apartment threaded, but this means that
  4876. // COM is already initialized and there is no need to uninitialize it.
  4877. hr = S_OK;
  4878. }
  4879. DBG_ASSERT( SUCCEEDED( hr ) );
  4880. // If really failed
  4881. if ( FAILED( hr ) )
  4882. {
  4883. DBGPRINTF(( DBG_CONTEXT,
  4884. "CoInitializeEx() failed in CallerWatchWaitOrTimerCallback hr=0x%08x.\n",
  4885. hr ));
  4886. // Ouch! Nothing we can do. The object will have to wait the timeout.
  4887. goto exit;
  4888. }
  4889. // Get the object
  4890. pThis = (CADMCOMW*)lpParameter;
  4891. // Disconnect it
  4892. hr = pThis->DisconnectOrphaned();
  4893. DBG_ASSERT( SUCCEEDED( hr ) );
  4894. if ( FAILED( hr ) )
  4895. {
  4896. DBGPRINTF(( DBG_CONTEXT,
  4897. "DisconnectOrphaned() failed in CallerWatchWaitOrTimerCallback hr=0x%08x.\n",
  4898. hr ));
  4899. goto exit;
  4900. }
  4901. exit:
  4902. DBG_ASSERT( SUCCEEDED( hr ) );
  4903. // Cleanup
  4904. if ( fUninitCom )
  4905. {
  4906. // Uninitialize COM
  4907. CoUninitialize();
  4908. }
  4909. }
  4910. HRESULT
  4911. CADMCOMW::GetPids(VOID)
  4912. /*++
  4913. Routine Description:
  4914. Gets the pid of this process (inetinfo.exe) and saves it to
  4915. sm_dwProcessIdThis.
  4916. Gets the pid of the svchost process running RpcSs and saves it to
  4917. sm_dwProcessIdRpcSs.
  4918. Arguments:
  4919. None
  4920. Returns:
  4921. HRESULT.
  4922. --*/
  4923. {
  4924. // Locals
  4925. HRESULT hr = S_OK;
  4926. BOOL fRet;
  4927. SC_HANDLE schSCM = NULL;
  4928. SC_HANDLE schRpcSs = NULL;
  4929. SERVICE_STATUS_PROCESS ServiceStatusProcessRcpSs = {0};
  4930. DWORD cbRequired = 0;
  4931. // Save the current processid
  4932. sm_dwProcessIdThis = GetCurrentProcessId();
  4933. DBG_ASSERT( sm_dwProcessIdThis != 0 );
  4934. // If already initialized don't play w/ SCM again
  4935. if ( sm_dwProcessIdRpcSs != 0 )
  4936. {
  4937. goto exit;
  4938. }
  4939. // Open SCM
  4940. schSCM = OpenSCManager( NULL,
  4941. NULL,
  4942. SC_MANAGER_ENUMERATE_SERVICE );
  4943. if (schSCM == NULL)
  4944. {
  4945. hr = HRESULT_FROM_WIN32( GetLastError() );
  4946. DBGPRINTF(( DBG_CONTEXT,
  4947. "OpenSCManager() failed in GetPids hr=0x%08x.\n",
  4948. hr ));
  4949. goto exit;
  4950. }
  4951. // Open RpcSs
  4952. schRpcSs = OpenServiceA( schSCM,
  4953. "RpcSs",
  4954. SERVICE_QUERY_STATUS);
  4955. if ( schRpcSs == NULL )
  4956. {
  4957. hr = HRESULT_FROM_WIN32( GetLastError() );
  4958. DBGPRINTF(( DBG_CONTEXT,
  4959. "OpenService() failed in GetPids hr=0x%08x.\n",
  4960. hr ));
  4961. goto exit;
  4962. }
  4963. // Query the status of RpcSs to get the pid
  4964. fRet = QueryServiceStatusEx( schRpcSs,
  4965. SC_STATUS_PROCESS_INFO,
  4966. (BYTE*)&ServiceStatusProcessRcpSs,
  4967. sizeof(ServiceStatusProcessRcpSs),
  4968. &cbRequired );
  4969. if ( !fRet )
  4970. {
  4971. DBG_ASSERT( GetLastError() != ERROR_INSUFFICIENT_BUFFER );
  4972. hr = HRESULT_FROM_WIN32( GetLastError() );
  4973. DBGPRINTF(( DBG_CONTEXT,
  4974. "QueryServiceStatusEx() failed in GetPids hr=0x%08x.\n",
  4975. hr ));
  4976. goto exit;
  4977. }
  4978. // Save the pid
  4979. sm_dwProcessIdRpcSs = ServiceStatusProcessRcpSs.dwProcessId;
  4980. DBG_ASSERT( sm_dwProcessIdRpcSs != 0 );
  4981. exit:
  4982. // Cleanup
  4983. if ( schRpcSs != NULL )
  4984. {
  4985. CloseServiceHandle( schRpcSs );
  4986. schRpcSs = NULL;
  4987. }
  4988. if ( schSCM != NULL )
  4989. {
  4990. CloseServiceHandle( schSCM );
  4991. schSCM = NULL;
  4992. }
  4993. DBG_ASSERT( SUCCEEDED( hr ) );
  4994. return hr;
  4995. }
  4996. HRESULT
  4997. MakePathCanonicalizationProof(
  4998. LPCWSTR pwszName,
  4999. BOOL fResolve,
  5000. STRAU *pstrPath)
  5001. /*++
  5002. Routine Description:
  5003. The function tries make a file name proof to all canonicalization problems.
  5004. If fResolve is FALSE:
  5005. This functions adds a prefix to the string,
  5006. which is "\\?\UNC\" for a UNC path, and "\\?\" for other paths.
  5007. This prefix tells Windows not to parse the path.
  5008. If fResolve is TRUE:
  5009. This function constructs a file name as above, opens the file and gets
  5010. the real name from the handle.
  5011. Stolen from iisutil.dll, because coadmin links only with iisrtl
  5012. Arguments:
  5013. IN pszName - The path to be converted
  5014. IN fResolve - Whether the caller can live with the name just prefixed or needs the real name.
  5015. OUT pstrPath - Output path created
  5016. Return Values:
  5017. HRESULT
  5018. --*/
  5019. {
  5020. HRESULT hr = S_OK;
  5021. DWORD dwError;
  5022. BOOL fRet;
  5023. NTSTATUS Status = STATUS_SUCCESS;
  5024. IO_STATUS_BLOCK IoStatusBlock;
  5025. HANDLE hFile = NULL;
  5026. BUFFER Buff;
  5027. FILE_NAME_INFORMATION *pFileNameInfo = NULL;
  5028. DWORD dwSize;
  5029. DWORD dwReqSize;
  5030. WCHAR wszPrefix[4];
  5031. WCHAR wchT;
  5032. // Check args
  5033. if ( ( pwszName == NULL ) || ( pstrPath == NULL ) )
  5034. {
  5035. hr = E_INVALIDARG;
  5036. goto exit;
  5037. }
  5038. pstrPath->Reset();
  5039. if ( pwszName[ 0 ] == L'\\' && pwszName[ 1 ] == L'\\' )
  5040. {
  5041. // If the path is already canonicalized, just return
  5042. if ( ( pwszName[ 2 ] == '?' || pwszName[ 2 ] == '.' ) &&
  5043. pwszName[ 3 ] == '\\' )
  5044. {
  5045. // Prepend "\\?\"
  5046. // If the path was in DOS form ("\\.\"),
  5047. // we need to change it to Win32 from ("\\?\")
  5048. fRet = pstrPath->Append( L"\\\\?\\" );
  5049. if ( !fRet )
  5050. {
  5051. hr = E_OUTOFMEMORY;
  5052. goto exit;
  5053. }
  5054. // Copy the path into the string
  5055. fRet = pstrPath->Append( (const LPWSTR)(pwszName+4) );
  5056. if ( !fRet )
  5057. {
  5058. hr = E_OUTOFMEMORY;
  5059. goto exit;
  5060. }
  5061. // Just return the copy
  5062. goto exit;
  5063. }
  5064. if ( fResolve )
  5065. {
  5066. wszPrefix[0] = L'\\';
  5067. wszPrefix[1] = L'\0';
  5068. }
  5069. // Skip the "\\"
  5070. pwszName += 2;
  5071. // Prepend "\\?\UNC\"
  5072. fRet = pstrPath->Append( L"\\\\?\\UNC\\" );
  5073. if ( !fRet )
  5074. {
  5075. hr = E_OUTOFMEMORY;
  5076. goto exit;
  5077. }
  5078. }
  5079. else
  5080. {
  5081. if ( fResolve )
  5082. {
  5083. wchT = pwszName[0];
  5084. if ( ( wchT >= L'A' ) && ( wchT <= L'Z' ) )
  5085. {
  5086. wchT = wchT - L'A' + L'a';
  5087. }
  5088. if ( ( wchT < L'a' ) || ( wchT > L'z' ) )
  5089. {
  5090. hr = E_INVALIDARG;
  5091. goto exit;
  5092. }
  5093. if ( pwszName[1] != L':' )
  5094. {
  5095. hr = E_INVALIDARG;
  5096. goto exit;
  5097. }
  5098. if ( pwszName[2] != L'\\' )
  5099. {
  5100. hr = E_INVALIDARG;
  5101. goto exit;
  5102. }
  5103. wszPrefix[0] = pwszName[0];
  5104. wszPrefix[1] = pwszName[1];
  5105. wszPrefix[2] = L'\0';
  5106. }
  5107. // Prepend "\\?\"
  5108. fRet = pstrPath->Append( L"\\\\?\\" );
  5109. if ( !fRet )
  5110. {
  5111. hr = E_OUTOFMEMORY;
  5112. goto exit;
  5113. }
  5114. }
  5115. // Add the path
  5116. fRet = pstrPath->Append( (const LPWSTR)pwszName );
  5117. if ( !fRet )
  5118. {
  5119. hr = E_OUTOFMEMORY;
  5120. goto exit;
  5121. }
  5122. // Don't use the original filename anymore
  5123. pwszName = NULL;
  5124. // If the caller can work with the anti-canonicalized file name
  5125. if ( !fResolve )
  5126. {
  5127. // We are done, return
  5128. goto exit;
  5129. }
  5130. // Well have to do it the hard way
  5131. hFile = CreateFileW( pstrPath->QueryStrW(),
  5132. GENERIC_READ,
  5133. FILE_SHARE_READ,
  5134. NULL,
  5135. OPEN_EXISTING,
  5136. FILE_ATTRIBUTE_NORMAL,
  5137. NULL );
  5138. if ( ( hFile == NULL ) || ( hFile == INVALID_HANDLE_VALUE ) )
  5139. {
  5140. dwError = GetLastError();
  5141. hr = HRESULT_FROM_WIN32( dwError );
  5142. goto exit;
  5143. }
  5144. // Assume the size of the name should approximate the same
  5145. dwSize = sizeof( FILE_NAME_INFORMATION ) + pstrPath->QueryCBW()+ sizeof( WCHAR );
  5146. dwSize = ( dwSize + 0x0000000Ful ) & ~0x0000000Ful;
  5147. // Set the size
  5148. fRet = Buff.Resize( dwSize );
  5149. if ( !fRet )
  5150. {
  5151. hr = E_OUTOFMEMORY;
  5152. goto exit;
  5153. }
  5154. pFileNameInfo = (FILE_NAME_INFORMATION*)Buff.QueryPtr();
  5155. DBG_ASSERT( pFileNameInfo );
  5156. // Get the name from the handle
  5157. Status = NtQueryInformationFile( hFile,
  5158. &IoStatusBlock,
  5159. pFileNameInfo,
  5160. dwSize,
  5161. FileNameInformation );
  5162. // If the buffer is not big enough
  5163. if ( ( Status == STATUS_BUFFER_OVERFLOW ) ||
  5164. ( Status == STATUS_BUFFER_TOO_SMALL ) )
  5165. {
  5166. // Calculate the new size
  5167. dwReqSize = sizeof(FILE_NAME_INFORMATION) + pFileNameInfo->FileNameLength + sizeof( WCHAR );
  5168. DBG_ASSERT( dwReqSize > dwSize );
  5169. dwSize = ( dwReqSize + 0x0000000Ful ) & ~0x0000000Ful;
  5170. fRet = Buff.Resize( dwSize );
  5171. if ( !fRet )
  5172. {
  5173. hr = E_OUTOFMEMORY;
  5174. goto exit;
  5175. }
  5176. pFileNameInfo = (FILE_NAME_INFORMATION*)Buff.QueryPtr();
  5177. DBG_ASSERT( pFileNameInfo );
  5178. // Retry getting the name from the handle
  5179. Status = NtQueryInformationFile( hFile,
  5180. &IoStatusBlock,
  5181. pFileNameInfo,
  5182. dwSize,
  5183. FileNameInformation );
  5184. }
  5185. if ( !NT_SUCCESS( Status ) )
  5186. {
  5187. dwError = RtlNtStatusToDosError( Status );
  5188. DBG_ASSERT( dwError != ERROR_SUCCESS );
  5189. if ( dwError != ERROR_MR_MID_NOT_FOUND )
  5190. {
  5191. hr = HRESULT_FROM_WIN32( dwError );
  5192. }
  5193. else
  5194. {
  5195. hr = HRESULT_FROM_NT( Status );
  5196. DBG_ASSERT ( FAILED( hr ) );
  5197. }
  5198. goto exit;
  5199. }
  5200. pstrPath->Reset();
  5201. // Set the prefix
  5202. fRet = pstrPath->Copy( wszPrefix );
  5203. if ( !fRet )
  5204. {
  5205. hr = E_OUTOFMEMORY;
  5206. goto exit;
  5207. }
  5208. // Append the name
  5209. fRet = pstrPath->Append( pFileNameInfo->FileName, pFileNameInfo->FileNameLength/sizeof( WCHAR ) );
  5210. if ( !fRet )
  5211. {
  5212. hr = E_OUTOFMEMORY;
  5213. goto exit;
  5214. }
  5215. exit:
  5216. if ( ( hFile != NULL ) && ( hFile != INVALID_HANDLE_VALUE ) )
  5217. {
  5218. CloseHandle(hFile);
  5219. hFile = NULL;
  5220. }
  5221. if ( FAILED( hr ) )
  5222. {
  5223. pstrPath->Reset();
  5224. }
  5225. return hr;
  5226. }