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.

1862 lines
40 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name :
  4. admacl.cxx
  5. Abstract:
  6. This module defines Admin API Access Check API
  7. Author:
  8. Philippe Choquier 02-Dec-1996
  9. --*/
  10. #include "precomp.hxx"
  11. #include <imd.h>
  12. #include <iadm.h>
  13. #include <mb.hxx>
  14. #include "admacl.hxx"
  15. #include "coiadm.hxx"
  16. #ifndef ARRAYSIZE
  17. #define ARRAYSIZE(_a) (sizeof((_a))/sizeof(*(_a)))
  18. #endif
  19. //
  20. // Globals
  21. //
  22. CInitAdmacl g_cinitadmacl;
  23. CAdminAclCache g_AclCache;
  24. CInitAdmacl::CInitAdmacl()
  25. {
  26. DBG_REQUIRE(SUCCEEDED(g_AclCache.Init()));
  27. }
  28. CInitAdmacl::~CInitAdmacl()
  29. {
  30. DBG_ASSERT(g_AclCache.IsEmpty()==S_OK);
  31. }
  32. //
  33. // Generic mapping for Application access check
  34. GENERIC_MAPPING g_FileGenericMapping =
  35. {
  36. FILE_READ_DATA,
  37. FILE_WRITE_DATA,
  38. FILE_EXECUTE,
  39. FILE_ALL_ACCESS
  40. };
  41. BOOL
  42. AdminAclNotifyClose(
  43. LPVOID pvAdmin,
  44. METADATA_HANDLE hAdminHandle
  45. )
  46. /*++
  47. Routine Description:
  48. Notify admin acl access check module of close request
  49. Arguments:
  50. pvAdmin - admin context
  51. hAdminHandle - handle to metadata
  52. Returns:
  53. TRUE on success, FALSE on failure
  54. --*/
  55. {
  56. g_AclCache.Remove(pvAdmin, hAdminHandle);
  57. return TRUE;
  58. }
  59. void
  60. AdminAclDisableAclCache()
  61. {
  62. g_AclCache.Disable();
  63. }
  64. void
  65. AdminAclEnableAclCache()
  66. {
  67. g_AclCache.Enable();
  68. }
  69. BOOL
  70. AdminAclFlushCache(
  71. )
  72. /*++
  73. Routine Description:
  74. Flush cache
  75. Arguments:
  76. None
  77. Returns:
  78. TRUE on success, FALSE on failure
  79. --*/
  80. {
  81. g_AclCache.Flush();
  82. return TRUE;
  83. }
  84. BOOL
  85. AdminAclNotifySetOrDeleteProp(
  86. METADATA_HANDLE ,
  87. DWORD dwId
  88. )
  89. /*++
  90. Routine Description:
  91. Notify admin acl access check module of update to metabase
  92. Arguments:
  93. hAdminHandle - handle to metadata
  94. dwId - property ID set or deleted
  95. Returns:
  96. TRUE on success, FALSE on failure
  97. --*/
  98. {
  99. // flush cache for all ACLs
  100. if ( dwId == MD_ADMIN_ACL )
  101. {
  102. g_AclCache.Flush();
  103. }
  104. return TRUE;
  105. }
  106. static HRESULT
  107. _GetThreadToken(
  108. HANDLE *phThreadToken)
  109. /*++
  110. Routine Description:
  111. Returns handle to the thread impersonation token.
  112. The caller must close the handle.
  113. Arguments:
  114. phThreadToken - Out, a handle to the thread token
  115. Returns:
  116. S_OK on success, E_* on failure
  117. --*/
  118. {
  119. // Locals
  120. HRESULT hr=S_OK;
  121. HANDLE hThread;
  122. HANDLE hToken=NULL;
  123. IServerSecurity* pServerSecurity=NULL;
  124. // Check args
  125. if (phThreadToken)
  126. {
  127. // Initialize to NULL
  128. *phThreadToken=NULL;
  129. }
  130. else
  131. {
  132. hr=E_INVALIDARG;
  133. goto exit;
  134. }
  135. // Get the pseudo handle to the current thread
  136. hThread=GetCurrentThread();
  137. //
  138. // test if already impersonated ( inprocess call w/o marshalling )
  139. // If not call DCOM to retrieve security context & impersonate, then
  140. // extract access token.
  141. //
  142. if (!OpenThreadToken(hThread, TOKEN_EXECUTE|TOKEN_QUERY, TRUE, &hToken))
  143. {
  144. // this thread is not impersonating -> process token
  145. // Get the DCOM server security object
  146. hr=CoGetCallContext(IID_IServerSecurity, (VOID**)&pServerSecurity);
  147. if (FAILED(hr))
  148. {
  149. goto exit;
  150. }
  151. // Impersonate the caller
  152. hr=pServerSecurity->ImpersonateClient();
  153. if (FAILED(hr))
  154. {
  155. goto exit;
  156. }
  157. // Try again to get the token
  158. if (!OpenThreadToken(hThread, TOKEN_EXECUTE|TOKEN_QUERY, TRUE, &hToken))
  159. {
  160. hr=HRESULT_FROM_WIN32(GetLastError());
  161. goto exit;
  162. }
  163. }
  164. // Return the token
  165. *phThreadToken=hToken;
  166. hToken=NULL;
  167. exit:
  168. // Cleanup
  169. if (pServerSecurity)
  170. {
  171. if (pServerSecurity->IsImpersonating())
  172. {
  173. // better here, since
  174. // COM otherwise is reclaiming the
  175. // thread token too late.
  176. pServerSecurity->RevertToSelf();
  177. }
  178. pServerSecurity->Release();
  179. }
  180. if (hToken)
  181. {
  182. CloseHandle(hToken);
  183. }
  184. // Done
  185. return (hr);
  186. }
  187. BOOL
  188. AdminAclAccessCheck(
  189. IMDCOM* pMDCom,
  190. LPVOID pvAdmin,
  191. METADATA_HANDLE hAdminHandle,
  192. LPCWSTR pszRelPath,
  193. DWORD dwId, // check for MD_ADMIN_ACL, must have special right to write them
  194. // can be 0 for non ID based access ( enum, create )
  195. // or -1 for GetAll
  196. DWORD dwAccess, // METADATA_PERMISSION_*
  197. COpenHandle* pohHandle,
  198. LPBOOL pfEnableSecureAccess
  199. )
  200. /*++
  201. Routine Description:
  202. Perform access check based on path, ID and access type
  203. Arguments:
  204. hAdminHandle - Open handle
  205. pszRelPath - path to object ( relative to open path )
  206. dwId - property ID
  207. dwAccess - access type, as defined by metabase header
  208. pfEnableSecureAccess - update with TRUE if read access to secure properties granted
  209. Returns:
  210. TRUE on success, FALSE on failure
  211. --*/
  212. {
  213. CAdminAcl* pAdminAclCurrent = NULL;
  214. BOOL bReturn = TRUE;
  215. HANDLE hAccTok = NULL;
  216. LPBYTE pAcl = NULL;
  217. DWORD dwRef;
  218. BOOL fIsAnyAcl;
  219. BOOL bAddToCache = FALSE;
  220. DWORD dwAcc;
  221. DWORD dwGrantedAccess;
  222. BYTE PrivSet[400];
  223. DWORD cbPrivilegeSet = sizeof(PrivSet);
  224. BOOL fAccessGranted;
  225. if ( pfEnableSecureAccess )
  226. {
  227. *pfEnableSecureAccess = TRUE;
  228. }
  229. if ( pszRelPath == NULL )
  230. {
  231. pszRelPath = L"";
  232. }
  233. // Get the token
  234. _GetThreadToken(&hAccTok);
  235. // can be non null only if obtained from thread
  236. if (hAccTok==NULL)
  237. {
  238. //
  239. // For now, assume failure to get IServerSecurity means we are
  240. // in the SYSTEM context, so grant access.
  241. //
  242. bReturn = TRUE;
  243. goto exit;
  244. }
  245. // find match : look for exact path match
  246. // keep at most N entry, reset at top of list when accessed
  247. // Investigate: if in <NSE> : cut-off point just before <nse>
  248. g_AclCache.Find(pvAdmin, hAdminHandle, pszRelPath, &pAdminAclCurrent);
  249. //
  250. // BUGBUG This checking only checks path and handle, not DCOM instance
  251. // So there could be incorrect matches.
  252. //
  253. if( pAdminAclCurrent == NULL )
  254. {
  255. pAdminAclCurrent = new CAdminAcl;
  256. if ( pAdminAclCurrent==NULL )
  257. {
  258. //
  259. // failed to create new cache entry
  260. //
  261. bReturn = FALSE;
  262. goto exit;
  263. }
  264. // read ACL
  265. if ( !pohHandle->GetAcl( pMDCom, pszRelPath, &pAcl, &dwRef ) )
  266. {
  267. pAcl = NULL;
  268. dwRef = NULL;
  269. }
  270. //
  271. // BUGBUG should normalize the path so /x and x don't generate
  272. // 2 entries
  273. //
  274. //
  275. // If path is too long,
  276. // Go ahead and check the ACL, but don't put in cache
  277. //
  278. bReturn = pAdminAclCurrent->Init( pMDCom,
  279. pvAdmin,
  280. hAdminHandle,
  281. pszRelPath,
  282. pAcl,
  283. dwRef,
  284. &bAddToCache );
  285. //
  286. // Currently no possible failures
  287. //
  288. DBG_ASSERT(bReturn);
  289. if ( !bReturn )
  290. {
  291. goto exit;
  292. }
  293. if (bAddToCache)
  294. {
  295. g_AclCache.Add(pAdminAclCurrent);
  296. }
  297. }
  298. DBG_ASSERT(pAdminAclCurrent);
  299. //
  300. // Access check
  301. //
  302. pAcl = pAdminAclCurrent->GetAcl();
  303. if (pAcl==NULL)
  304. {
  305. //
  306. // No ACL : access check succeed
  307. //
  308. bReturn = TRUE;
  309. goto exit;
  310. }
  311. //
  312. // Protected properties require EXECUTE access rights instead of WRITE
  313. //
  314. if ( dwAccess & METADATA_PERMISSION_WRITE )
  315. {
  316. if ( dwId == MD_ADMIN_ACL ||
  317. dwId == MD_VPROP_ADMIN_ACL_RAW_BINARY ||
  318. dwId == MD_APPPOOL_ORPHAN_ACTION_EXE ||
  319. dwId == MD_APPPOOL_ORPHAN_ACTION_PARAMS ||
  320. dwId == MD_APPPOOL_AUTO_SHUTDOWN_EXE ||
  321. dwId == MD_APPPOOL_AUTO_SHUTDOWN_PARAMS ||
  322. dwId == MD_APPPOOL_IDENTITY_TYPE ||
  323. dwId == MD_APP_APPPOOL_ID ||
  324. dwId == MD_APP_ISOLATED ||
  325. dwId == MD_VR_PATH ||
  326. dwId == MD_ACCESS_PERM ||
  327. dwId == MD_VR_USERNAME ||
  328. dwId == MD_VR_PASSWORD ||
  329. dwId == MD_ANONYMOUS_USER_NAME ||
  330. dwId == MD_ANONYMOUS_PWD ||
  331. dwId == MD_LOGSQL_USER_NAME ||
  332. dwId == MD_LOGSQL_PASSWORD ||
  333. dwId == MD_WAM_USER_NAME ||
  334. dwId == MD_WAM_PWD ||
  335. dwId == MD_AD_CONNECTIONS_USERNAME ||
  336. dwId == MD_AD_CONNECTIONS_PASSWORD ||
  337. dwId == MD_MAX_BANDWIDTH ||
  338. dwId == MD_MAX_BANDWIDTH_BLOCKED ||
  339. dwId == MD_ISM_ACCESS_CHECK ||
  340. dwId == MD_FILTER_LOAD_ORDER ||
  341. dwId == MD_FILTER_ENABLED ||
  342. dwId == MD_FILTER_IMAGE_PATH ||
  343. dwId == MD_SECURE_BINDINGS ||
  344. dwId == MD_SERVER_BINDINGS ||
  345. dwId == MD_ASP_ENABLECLIENTDEBUG ||
  346. dwId == MD_ASP_ENABLESERVERDEBUG ||
  347. dwId == MD_ASP_ENABLEPARENTPATHS ||
  348. dwId == MD_ASP_ERRORSTONTLOG ||
  349. dwId == MD_ASP_KEEPSESSIONIDSECURE ||
  350. dwId == MD_ASP_LOGERRORREQUESTS ||
  351. dwId == MD_ASP_DISKTEMPLATECACHEDIRECTORY ||
  352. dwId == 36948 || // RouteUserName
  353. dwId == 36949 || // RoutePassword
  354. dwId == 36958 || // SmtpDsPassword
  355. dwId == 41191 || // Pop3DsPassword
  356. dwId == 45461 || // FeedAccountName
  357. dwId == 45462 || // FeedPassword
  358. dwId == 49384 ) // ImapDsPassword
  359. {
  360. dwAcc = MD_ACR_RESTRICTED_WRITE;
  361. }
  362. else
  363. {
  364. dwAcc = MD_ACR_WRITE;
  365. }
  366. }
  367. else // ! only METADATA_PERMISSION_WRITE
  368. {
  369. if ( dwId == AAC_ENUM_KEYS )
  370. {
  371. dwAcc = MD_ACR_ENUM_KEYS;
  372. }
  373. else
  374. {
  375. // assume read access
  376. dwAcc = MD_ACR_READ;
  377. }
  378. }
  379. //
  380. // If copy or delete key, check if ACL exists in subtree
  381. // if yes required MD_ACR_RESTRICTED_WRITE
  382. //
  383. if ( dwAcc == MD_ACR_WRITE &&
  384. (dwId == AAC_COPYKEY || dwId == AAC_DELETEKEY) )
  385. {
  386. if ( pohHandle->CheckSubAcls( pMDCom, pszRelPath, &fIsAnyAcl ) &&
  387. fIsAnyAcl )
  388. {
  389. dwAcc = MD_ACR_RESTRICTED_WRITE;
  390. }
  391. }
  392. CheckAgain:
  393. if ( !AccessCheck( pAcl,
  394. hAccTok,
  395. dwAcc,
  396. &g_FileGenericMapping,
  397. (PRIVILEGE_SET *) PrivSet,
  398. &cbPrivilegeSet,
  399. &dwGrantedAccess,
  400. &fAccessGranted ) ||
  401. !fAccessGranted )
  402. {
  403. if ( dwAcc != MD_ACR_WRITE_DAC && (dwId == MD_ADMIN_ACL) )
  404. {
  405. dwAcc = MD_ACR_WRITE_DAC;
  406. goto CheckAgain;
  407. }
  408. //
  409. // If read access denied, retry with restricted read right
  410. // only if not called from GetAll()
  411. //
  412. if ( dwAcc == MD_ACR_READ &&
  413. pfEnableSecureAccess )
  414. {
  415. dwAcc = MD_ACR_UNSECURE_PROPS_READ;
  416. *pfEnableSecureAccess = FALSE;
  417. goto CheckAgain;
  418. }
  419. SetLastError( ERROR_ACCESS_DENIED );
  420. bReturn = FALSE;
  421. }
  422. exit:
  423. // Cleanup
  424. if (pAdminAclCurrent)
  425. {
  426. pAdminAclCurrent->Release();
  427. }
  428. if (hAccTok)
  429. {
  430. CloseHandle( hAccTok );
  431. }
  432. return bReturn;
  433. }
  434. CAdminAcl::~CAdminAcl(
  435. )
  436. /*++
  437. Routine Description:
  438. Destructor for Admin Acl cache entry
  439. Arguments:
  440. None
  441. Returns:
  442. Nothing
  443. --*/
  444. {
  445. if ( m_pMDCom )
  446. {
  447. if ( m_dwAclRef )
  448. {
  449. m_pMDCom->ComMDReleaseReferenceData( m_dwAclRef );
  450. }
  451. m_pMDCom->Release();
  452. }
  453. m_dwSignature = ADMINACL_FREED_SIGN;
  454. }
  455. DWORD
  456. CAdminAcl::AddRef()
  457. /*++
  458. Routine Description:
  459. Interlocked increments the reference count.
  460. Arguments:
  461. None
  462. Returns:
  463. The new reference count.
  464. --*/
  465. {
  466. return ((DWORD)InterlockedIncrement((LONG*)&m_cRef));
  467. }
  468. DWORD
  469. CAdminAcl::Release()
  470. /*++
  471. Routine Description:
  472. Interlocked decrements the reference count.
  473. When the reference count reaches 0 deletes the object.
  474. Arguments:
  475. None
  476. Returns:
  477. The new reference count.
  478. --*/
  479. {
  480. DWORD cRef;
  481. cRef=(DWORD)InterlockedDecrement((LONG*)&m_cRef);
  482. if (cRef==0)
  483. {
  484. delete this;
  485. }
  486. return (cRef);
  487. }
  488. BOOL
  489. CAdminAcl::Init(
  490. IMDCOM* pMDCom,
  491. LPVOID pvAdmin,
  492. METADATA_HANDLE hAdminHandle,
  493. LPCWSTR pszPath,
  494. LPBYTE pAcl,
  495. DWORD dwAclRef,
  496. PBOOL pbIsPathCorrect
  497. )
  498. /*++
  499. Routine Description:
  500. Initialize an Admin Acl cache entry
  501. Arguments:
  502. hAdminHandle - metadata handle
  503. pszPath - path to object ( absolute )
  504. pAcl - ptr to ACL for this path ( may be NULL )
  505. dwAclRef - access by reference ID
  506. Returns:
  507. Nothing
  508. --*/
  509. {
  510. m_hAdminHandle = hAdminHandle;
  511. m_pvAdmin = pvAdmin;
  512. *pbIsPathCorrect = TRUE;
  513. if (pszPath != NULL)
  514. {
  515. if ( wcslen( pszPath ) < (sizeof(m_wchPath) / sizeof(WCHAR)) )
  516. {
  517. wcscpy( m_wchPath, pszPath );
  518. }
  519. else
  520. {
  521. m_wchPath[0] = (WCHAR)'\0';
  522. *pbIsPathCorrect = FALSE;
  523. }
  524. }
  525. else
  526. {
  527. m_wchPath[0] = (WCHAR)'\0';
  528. }
  529. m_pAcl = pAcl;
  530. m_dwAclRef = dwAclRef;
  531. m_pMDCom = pMDCom;
  532. pMDCom->AddRef();
  533. m_dwSignature = ADMINACL_INIT_SIGN;
  534. return TRUE;
  535. }
  536. HRESULT
  537. COpenHandle::Init(
  538. METADATA_HANDLE hAdminHandle,
  539. LPCWSTR pszRelPath,
  540. LPCWSTR pszParentPath
  541. )
  542. /*++
  543. Routine Description:
  544. Initialize an open context cache entry
  545. Arguments:
  546. pvAdmin - admin context
  547. hAdminHandle - metadata handle
  548. pszRelPath - path to object ( absolute )
  549. Returns:
  550. Nothing
  551. --*/
  552. {
  553. HRESULT hresReturn = ERROR_SUCCESS;
  554. LPWSTR pszRelPathIndex = (LPWSTR)pszRelPath;
  555. m_hAdminHandle = hAdminHandle;
  556. m_lRefCount = 1;
  557. if (pszRelPath == NULL)
  558. {
  559. pszRelPathIndex = L"";
  560. }
  561. DBG_ASSERT(pszParentPath != NULL);
  562. DBG_ASSERT((*pszParentPath == (WCHAR)'\0') ||
  563. ISPATHDELIMW(*pszParentPath));
  564. //
  565. // Strip front slash now, add it in later
  566. //
  567. if (ISPATHDELIMW(*pszRelPathIndex))
  568. {
  569. pszRelPathIndex++;
  570. }
  571. DWORD dwRelPathLen = (DWORD)wcslen(pszRelPathIndex);
  572. DWORD dwParentPathLen = (DWORD)wcslen(pszParentPath);
  573. DBG_ASSERT((dwParentPathLen == 0) ||
  574. (!ISPATHDELIMW(pszParentPath[dwParentPathLen -1])));
  575. //
  576. // Get rid of trailing slash for good
  577. //
  578. if ((dwRelPathLen > 0) && (ISPATHDELIMW(pszRelPathIndex[dwRelPathLen -1])))
  579. {
  580. dwRelPathLen--;
  581. }
  582. //
  583. // Include space for mid slash if Relpath exists
  584. // Include space for termination
  585. //
  586. DWORD dwTotalSize =
  587. (dwRelPathLen + dwParentPathLen + 1 + ((dwRelPathLen > 0) ? 1 : 0)) * sizeof(WCHAR);
  588. m_pszPath = (LPWSTR)LocalAlloc(LMEM_FIXED, dwTotalSize);
  589. if (m_pszPath == NULL)
  590. {
  591. hresReturn = RETURNCODETOHRESULT(GetLastError());
  592. }
  593. else
  594. {
  595. //
  596. // OK to always copy the first part
  597. //
  598. memcpy(m_pszPath,
  599. pszParentPath,
  600. dwParentPathLen * sizeof(WCHAR));
  601. //
  602. // Don't need slash if there is no RelPath
  603. //
  604. if (dwRelPathLen > 0)
  605. {
  606. m_pszPath[dwParentPathLen] = (WCHAR)'/';
  607. memcpy(m_pszPath + dwParentPathLen + 1,
  608. pszRelPathIndex,
  609. dwRelPathLen * sizeof(WCHAR));
  610. }
  611. m_pszPath[(dwTotalSize / sizeof(WCHAR)) - 1] = (WCHAR)'\0';
  612. //
  613. // Now convert \ to / for string compares
  614. //
  615. LPWSTR pszPathIndex = m_pszPath;
  616. while ((pszPathIndex = wcschr(pszPathIndex, (WCHAR)'\\')) != NULL)
  617. {
  618. *pszPathIndex = (WCHAR)'/';
  619. }
  620. }
  621. return hresReturn;
  622. }
  623. // Whistler 53924
  624. /*++
  625. function backstrchr
  626. returns the last occurrence of a charcter or NULL if not found
  627. --*/
  628. WCHAR * backstrchr(WCHAR * pString,WCHAR ThisChar)
  629. {
  630. WCHAR *pCurrentPos = NULL;
  631. while(*pString)
  632. {
  633. if (*pString == ThisChar)
  634. {
  635. pCurrentPos = pString;
  636. }
  637. pString++;
  638. };
  639. return pCurrentPos;
  640. }
  641. BOOL
  642. COpenHandle::GetAcl(
  643. IMDCOM* pMDCom,
  644. LPCWSTR pszRelPath,
  645. LPBYTE* pAcl,
  646. LPDWORD pdwRef
  647. )
  648. /*++
  649. Routine Description:
  650. Retrieve Acl
  651. Arguments:
  652. pszPath - path to object
  653. ppAcl - updated with ptr to ACL if success
  654. pdwRef - updated with ref to ACL if success
  655. Returns:
  656. TRUE if success, otherwise FALSE
  657. --*/
  658. {
  659. METADATA_RECORD mdRecord = { 0 };
  660. HRESULT hRes;
  661. DWORD dwRequiredLen;
  662. BOOL bReturn = TRUE;
  663. LPWSTR pszFullPath;
  664. LPWSTR pszRelPathIndex = (LPWSTR)pszRelPath;
  665. if (pszRelPathIndex == NULL)
  666. {
  667. pszRelPathIndex = L"";
  668. }
  669. DBG_ASSERT(m_pszPath != NULL);
  670. DBG_ASSERT((*m_pszPath == (WCHAR)'\0') ||
  671. ISPATHDELIMW(*m_pszPath));
  672. //
  673. // Strip front slash now, add it in later
  674. //
  675. if (ISPATHDELIMW(*pszRelPathIndex))
  676. {
  677. pszRelPathIndex++;
  678. }
  679. DWORD dwPathLen = (DWORD)wcslen(m_pszPath);
  680. DWORD dwRelPathLen = (DWORD)wcslen(pszRelPathIndex);
  681. DBG_ASSERT((dwPathLen == 0) ||
  682. (!ISPATHDELIMW(m_pszPath[dwPathLen -1])));
  683. //
  684. // Get rid of trailing slash for good
  685. //
  686. if ((dwRelPathLen > 0) && (ISPATHDELIMW(pszRelPathIndex[dwRelPathLen -1])))
  687. {
  688. dwRelPathLen--;
  689. }
  690. //
  691. // Include space for mid slash and termination
  692. //
  693. DWORD dwTotalSize = (dwPathLen + dwRelPathLen + 1 + ((dwRelPathLen > 0) ? 1 : 0)) * sizeof(WCHAR);
  694. pszFullPath = (LPWSTR)LocalAlloc(LMEM_FIXED, dwTotalSize);
  695. if (pszFullPath == NULL)
  696. {
  697. bReturn = FALSE;
  698. }
  699. else
  700. {
  701. memcpy(pszFullPath,
  702. m_pszPath,
  703. dwPathLen * sizeof(WCHAR));
  704. //
  705. // Don't need slash if there is no RelPath
  706. //
  707. if (dwRelPathLen > 0)
  708. {
  709. pszFullPath[dwPathLen] = (WCHAR)'/';
  710. memcpy(pszFullPath + dwPathLen + 1,
  711. pszRelPathIndex,
  712. dwRelPathLen * sizeof(WCHAR));
  713. }
  714. pszFullPath[(dwTotalSize - sizeof(WCHAR)) / sizeof(WCHAR)] = (WCHAR)'\0';
  715. //
  716. // Now convert \ to / for string compares
  717. // m_pszPath was already converted, so start at relpath
  718. //
  719. LPWSTR pszPathIndex = pszFullPath + (dwPathLen);
  720. while ((pszPathIndex = wcschr(pszPathIndex, (WCHAR)'\\')) != NULL)
  721. {
  722. *pszPathIndex = (WCHAR)'/';
  723. }
  724. //
  725. // Use /schema ACL if path = /schema/...
  726. //
  727. if (_wcsnicmp(pszFullPath,
  728. IIS_MD_ADSI_SCHEMA_PATH_W L"/",
  729. ((sizeof(IIS_MD_ADSI_SCHEMA_PATH_W L"/") / sizeof(WCHAR)) - 1)) == 0)
  730. {
  731. pszFullPath[(sizeof(IIS_MD_ADSI_SCHEMA_PATH_W) / sizeof(WCHAR)) -1] = (WCHAR)'\0';
  732. }
  733. mdRecord.dwMDIdentifier = MD_ADMIN_ACL;
  734. mdRecord.dwMDAttributes = METADATA_INHERIT | METADATA_PARTIAL_PATH | METADATA_REFERENCE;
  735. mdRecord.dwMDUserType = IIS_MD_UT_SERVER;
  736. mdRecord.dwMDDataType = BINARY_METADATA;
  737. mdRecord.dwMDDataLen = 0;
  738. mdRecord.pbMDData = NULL;
  739. mdRecord.dwMDDataTag = NULL;
  740. hRes = pMDCom->ComMDGetMetaDataW( METADATA_MASTER_ROOT_HANDLE,
  741. pszFullPath,
  742. &mdRecord,
  743. &dwRequiredLen );
  744. // Whistler 53924
  745. if(HRESULTTOWIN32(hRes) == ERROR_INSUFFICIENT_BUFFER)
  746. {
  747. WCHAR * pLastSlash = NULL;
  748. while ((pLastSlash = backstrchr(pszFullPath,L'/')) != NULL)
  749. {
  750. *pLastSlash = L'\0';
  751. pLastSlash = NULL;
  752. mdRecord.dwMDDataLen = 0;
  753. mdRecord.pbMDData = NULL;
  754. mdRecord.dwMDDataTag = NULL;
  755. hRes = pMDCom->ComMDGetMetaDataW( METADATA_MASTER_ROOT_HANDLE,
  756. pszFullPath,
  757. &mdRecord,
  758. &dwRequiredLen );
  759. if (SUCCEEDED(hRes)) break;
  760. }
  761. }
  762. if ( FAILED( hRes ) || !mdRecord.dwMDDataTag )
  763. {
  764. bReturn = FALSE;
  765. }
  766. LocalFree( pszFullPath );
  767. }
  768. if ( bReturn )
  769. {
  770. *pAcl = mdRecord.pbMDData;
  771. *pdwRef = mdRecord.dwMDDataTag;
  772. }
  773. return bReturn;
  774. }
  775. BOOL
  776. COpenHandle::CheckSubAcls(
  777. IMDCOM* pMDCom,
  778. LPCWSTR pszRelPath,
  779. LPBOOL pfIsAnyAcl
  780. )
  781. /*++
  782. Routine Description:
  783. Check if Acls exist in subtree
  784. Arguments:
  785. pszRelPath - path to object
  786. pfIsAnyAcl - updated with TRUE if sub-acls exists, otherwise FALSE
  787. Returns:
  788. TRUE if success, otherwise FALSE
  789. --*/
  790. {
  791. HRESULT hRes;
  792. DWORD dwRequiredLen;
  793. BOOL bReturn = TRUE;
  794. LPWSTR pszFullPath;
  795. *pfIsAnyAcl = FALSE;
  796. LPWSTR pszRelPathIndex = (LPWSTR)pszRelPath;
  797. if (pszRelPathIndex == NULL)
  798. {
  799. pszRelPathIndex = L"";
  800. }
  801. DBG_ASSERT(m_pszPath != NULL);
  802. DBG_ASSERT((*m_pszPath == (WCHAR)'\0') ||
  803. ISPATHDELIMW(*m_pszPath));
  804. //
  805. // Strip front slash now, add it in later
  806. //
  807. if (ISPATHDELIMW(*pszRelPathIndex))
  808. {
  809. pszRelPathIndex++;
  810. }
  811. DWORD dwPathLen = (DWORD)wcslen(m_pszPath);
  812. DWORD dwRelPathLen = (DWORD)wcslen(pszRelPathIndex);
  813. DBG_ASSERT((dwPathLen == 0) ||
  814. (!ISPATHDELIMW(m_pszPath[dwPathLen -1])));
  815. //
  816. // Get rid of trailing slash for good
  817. //
  818. if ((dwRelPathLen > 0) && (ISPATHDELIMW(pszRelPathIndex[dwRelPathLen -1])))
  819. {
  820. dwRelPathLen--;
  821. }
  822. //
  823. // Include space for mid slash and termination
  824. //
  825. DWORD dwTotalSize = (dwPathLen + dwRelPathLen + 1 + ((dwRelPathLen > 0) ? 1 : 0)) * sizeof(WCHAR);
  826. pszFullPath = (LPWSTR)LocalAlloc(LMEM_FIXED, dwTotalSize);
  827. if (pszFullPath == NULL)
  828. {
  829. bReturn = FALSE;
  830. }
  831. else
  832. {
  833. memcpy(pszFullPath,
  834. m_pszPath,
  835. dwPathLen * sizeof(WCHAR));
  836. //
  837. // Don't need slash if there is no RelPath
  838. //
  839. if (dwRelPathLen > 0)
  840. {
  841. pszFullPath[dwPathLen] = (WCHAR)'/';
  842. memcpy(pszFullPath + dwPathLen + 1,
  843. pszRelPathIndex,
  844. dwRelPathLen * sizeof(WCHAR));
  845. }
  846. pszFullPath[(dwTotalSize - sizeof(WCHAR)) / sizeof(WCHAR)] = (WCHAR)'\0';
  847. hRes = pMDCom->ComMDGetMetaDataPathsW(METADATA_MASTER_ROOT_HANDLE,
  848. pszFullPath,
  849. MD_ADMIN_ACL,
  850. BINARY_METADATA,
  851. 0,
  852. NULL,
  853. &dwRequiredLen );
  854. LocalFree( pszFullPath );
  855. if ( FAILED( hRes ) )
  856. {
  857. if ( hRes == RETURNCODETOHRESULT( ERROR_INSUFFICIENT_BUFFER ) )
  858. {
  859. bReturn = TRUE;
  860. *pfIsAnyAcl = TRUE;
  861. }
  862. else
  863. {
  864. bReturn = FALSE;
  865. }
  866. }
  867. }
  868. return bReturn;
  869. }
  870. VOID
  871. COpenHandle::Release(PVOID pvAdmin)
  872. {
  873. if (InterlockedDecrement(&m_lRefCount) == 0)
  874. {
  875. //
  876. //
  877. //
  878. AdminAclNotifyClose(pvAdmin, m_hAdminHandle);
  879. ((CADMCOMW *)pvAdmin)->DeleteNode(m_hAdminHandle);
  880. }
  881. }
  882. CAdminAclCache::CAdminAclCache()
  883. /*++
  884. Routine Description:
  885. C++ constructor. Initializes all members to 0.
  886. Arguments:
  887. None
  888. Returns:
  889. n/a
  890. --*/
  891. {
  892. m_fEnabled=1;
  893. m_cAdminAclCache=0;
  894. memset(m_rgpAdminAclCache, 0, sizeof(m_rgpAdminAclCache));
  895. }
  896. CAdminAclCache::~CAdminAclCache()
  897. /*++
  898. Routine Description:
  899. C++ destructor. Deletes everthing in the cache.
  900. Arguments:
  901. None
  902. Returns:
  903. n/a
  904. --*/
  905. {
  906. Flush();
  907. }
  908. STDMETHODIMP
  909. CAdminAclCache::Init()
  910. /*++
  911. Routine Description:
  912. Initializes the cache. Right now there is nothing to do.
  913. Arguments:
  914. None
  915. Returns:
  916. S_OK on success. E_* failure.
  917. --*/
  918. {
  919. // Locals
  920. HRESULT hr=S_OK;
  921. //exit:
  922. // Done
  923. return (hr);
  924. }
  925. STDMETHODIMP
  926. CAdminAclCache::IsEnabled()
  927. /*++
  928. Routine Description:
  929. Checks whether the cache is enabled.
  930. Arguments:
  931. None
  932. Returns:
  933. S_OK enabled, S_FALSE disabled
  934. --*/
  935. {
  936. // Locals
  937. HRESULT hr=S_OK;
  938. // Check
  939. if (m_fEnabled<=0)
  940. {
  941. // Return S_FALSE
  942. hr=S_FALSE;
  943. }
  944. //exit:
  945. // Done
  946. return (hr);
  947. }
  948. STDMETHODIMP
  949. CAdminAclCache::IsEmpty()
  950. /*++
  951. Routine Description:
  952. Checks whether the cache is empty.
  953. Arguments:
  954. None
  955. Returns:
  956. S_OK empty, S_FALSE not empty
  957. --*/
  958. {
  959. // Locals
  960. HRESULT hr=S_OK;
  961. // Check
  962. if (m_cAdminAclCache!=0)
  963. {
  964. // Return S_FALSE
  965. hr=S_FALSE;
  966. }
  967. //exit:
  968. // Done
  969. return (hr);
  970. }
  971. STDMETHODIMP
  972. CAdminAclCache::Disable()
  973. /*++
  974. Routine Description:
  975. Disables the cache.
  976. Arguments:
  977. None
  978. Returns:
  979. S_OK
  980. --*/
  981. {
  982. // Locals
  983. HRESULT hr=S_OK;
  984. InterlockedDecrement(&m_fEnabled);
  985. //exit:
  986. // Done
  987. return (hr);
  988. }
  989. STDMETHODIMP
  990. CAdminAclCache::Enable()
  991. /*++
  992. Routine Description:
  993. Enables the cache.
  994. Arguments:
  995. None
  996. Returns:
  997. S_OK
  998. --*/
  999. {
  1000. // Locals
  1001. HRESULT hr=S_OK;
  1002. InterlockedIncrement(&m_fEnabled);
  1003. //exit:
  1004. // Done
  1005. return (hr);
  1006. }
  1007. STDMETHODIMP
  1008. CAdminAclCache::Flush()
  1009. /*++
  1010. Routine Description:
  1011. Removes all times from the cache.
  1012. Arguments:
  1013. None
  1014. Returns:
  1015. S_OK
  1016. --*/
  1017. {
  1018. // Locals
  1019. HRESULT hr=S_OK;
  1020. CAdminAcl *rgpToDelete[ARRAYSIZE(m_rgpAdminAclCache)];
  1021. DWORD cToDelete;
  1022. DWORD i;
  1023. // Lock exlcusive
  1024. m_Lock.WriteLock();
  1025. // Copy to local vars
  1026. cToDelete=m_cAdminAclCache;
  1027. memmove(rgpToDelete,
  1028. m_rgpAdminAclCache,
  1029. cToDelete*sizeof(*rgpToDelete));
  1030. // Wipe out
  1031. InterlockedExchange((LONG*)&m_cAdminAclCache, 0);
  1032. memset(m_rgpAdminAclCache, 0, sizeof(m_rgpAdminAclCache));
  1033. // Unlock
  1034. m_Lock.WriteUnlock();
  1035. // Loop over the cached elements
  1036. for (i=0; i<cToDelete; i++)
  1037. {
  1038. // Release
  1039. rgpToDelete[i]->Release();
  1040. }
  1041. //exit:
  1042. return (hr);
  1043. }
  1044. STDMETHODIMP
  1045. CAdminAclCache::Remove(
  1046. LPVOID pvAdmin,
  1047. METADATA_HANDLE hAdminHandle)
  1048. /*++
  1049. Routine Description:
  1050. Removes all items matching the object and the handle.
  1051. Arguments:
  1052. pvAdmin - the admin context
  1053. hAdminHandle - the metadata handle
  1054. Returns:
  1055. S_OK
  1056. --*/
  1057. {
  1058. // Locals
  1059. HRESULT hr=S_OK;
  1060. CAdminAcl *rgpToDelete[ARRAYSIZE(m_rgpAdminAclCache)];
  1061. DWORD cToDelete;
  1062. DWORD dwRead;
  1063. DWORD dwWrite;
  1064. DWORD i;
  1065. // Try to lock shared
  1066. if (m_Lock.TryReadLock())
  1067. {
  1068. // Loop over the cached elements
  1069. for (i=0; i<m_cAdminAclCache; i++)
  1070. {
  1071. // Match?
  1072. if ((m_rgpAdminAclCache[i]->GetAdminContext()==pvAdmin)&&
  1073. (m_rgpAdminAclCache[i]->GetAdminHandle()==hAdminHandle))
  1074. {
  1075. // Found one
  1076. break;
  1077. }
  1078. }
  1079. // Not found?
  1080. if (i==m_cAdminAclCache)
  1081. {
  1082. // Unlock
  1083. m_Lock.ReadUnlock();
  1084. // Done
  1085. goto exit;
  1086. }
  1087. // Lock exlcusive
  1088. m_Lock.ConvertSharedToExclusive();
  1089. }
  1090. else
  1091. {
  1092. // Lock exlcusive
  1093. m_Lock.WriteLock();
  1094. }
  1095. // In both case we have a write lock now
  1096. // Loop over the cached elements
  1097. for (cToDelete=dwWrite=dwRead=0; dwRead<m_cAdminAclCache; dwRead++)
  1098. {
  1099. // Match?
  1100. if ((m_rgpAdminAclCache[dwRead]->GetAdminContext()==pvAdmin)&&
  1101. (m_rgpAdminAclCache[dwRead]->GetAdminHandle()==hAdminHandle))
  1102. {
  1103. // Copy to the local array
  1104. rgpToDelete[cToDelete++]=m_rgpAdminAclCache[dwRead];
  1105. }
  1106. else
  1107. {
  1108. // If we removed some
  1109. if (dwWrite!=dwRead)
  1110. {
  1111. // Move to the empty place
  1112. m_rgpAdminAclCache[dwWrite]=m_rgpAdminAclCache[dwRead];
  1113. }
  1114. // Advance
  1115. dwWrite++;
  1116. }
  1117. }
  1118. DBG_ASSERT((dwWrite+cToDelete)==m_cAdminAclCache);
  1119. // Set the new size
  1120. InterlockedExchange((LONG*)&m_cAdminAclCache, dwWrite);
  1121. // Unlock
  1122. m_Lock.WriteUnlock();
  1123. // Loop over the elements to be deleted
  1124. for (i=0; i<cToDelete; i++)
  1125. {
  1126. // Release
  1127. rgpToDelete[i]->Release();
  1128. }
  1129. exit:
  1130. return (hr);
  1131. }
  1132. STDMETHODIMP
  1133. CAdminAclCache::Find(
  1134. LPVOID pvAdmin,
  1135. METADATA_HANDLE hAdminHandle,
  1136. LPCWSTR pwszRelPath,
  1137. CAdminAcl **ppAdminAcl)
  1138. /*++
  1139. Routine Description:
  1140. Finds ACL matching the object, the handle and the path.
  1141. Arguments:
  1142. pvAdmin - the admin context
  1143. hAdminHandle - the metadata handle
  1144. pwszRelPath - the path (NULL is treated as empty string)
  1145. ppAdminAcl - out the acl if found. the caller must release it.
  1146. Returns:
  1147. S_OK found, S_FALSE not found. E_* on failure
  1148. --*/
  1149. {
  1150. // Locals
  1151. HRESULT hr=S_OK;
  1152. CAdminAcl *pAdminAcl=NULL;
  1153. DWORD i;
  1154. BOOL fWriteLocked=FALSE;
  1155. // Check args
  1156. if (ppAdminAcl==NULL)
  1157. {
  1158. hr=E_INVALIDARG;
  1159. goto exit;
  1160. }
  1161. else
  1162. {
  1163. // Init
  1164. *ppAdminAcl=NULL;
  1165. }
  1166. // Don't search if the cache is disabled
  1167. hr=IsEnabled();
  1168. if (hr!=S_OK)
  1169. {
  1170. // Not found
  1171. goto exit;
  1172. }
  1173. if (pwszRelPath==NULL)
  1174. {
  1175. // Set to empty
  1176. pwszRelPath=L"";
  1177. }
  1178. // Try to lock shared
  1179. if (!m_Lock.TryReadLock())
  1180. {
  1181. // Report potentially wrong "Not found" instead of waiting for the writes to finish.
  1182. hr=S_FALSE;
  1183. goto exit;
  1184. }
  1185. // Try to find
  1186. hr=_Find(pvAdmin, hAdminHandle, pwszRelPath, &pAdminAcl, &i);
  1187. // If found
  1188. if (hr==S_OK)
  1189. {
  1190. DBG_ASSERT(pAdminAcl&&(i<m_cAdminAclCache));
  1191. // Try to lock exclusive
  1192. if (m_Lock.TryConvertSharedToExclusive())
  1193. {
  1194. // Move to be 1st element
  1195. _MoveFirst(i);
  1196. // Remember to write unlock
  1197. fWriteLocked=TRUE;
  1198. }
  1199. }
  1200. // Write locked?
  1201. if (fWriteLocked)
  1202. {
  1203. // Unlock
  1204. m_Lock.WriteUnlock();
  1205. }
  1206. else
  1207. {
  1208. // Unlock
  1209. m_Lock.ReadUnlock();
  1210. }
  1211. // Return
  1212. *ppAdminAcl=pAdminAcl;
  1213. pAdminAcl=NULL;
  1214. exit:
  1215. // Cleanup
  1216. if (pAdminAcl)
  1217. {
  1218. pAdminAcl->Release();
  1219. }
  1220. // Done
  1221. return (hr);
  1222. }
  1223. STDMETHODIMP
  1224. CAdminAclCache::Add(
  1225. CAdminAcl *pAdminAcl)
  1226. /*++
  1227. Routine Description:
  1228. Adds ACL to the cache.
  1229. Arguments:
  1230. pAdminAcl - the acl.
  1231. Returns:
  1232. S_OK the element was added. S_FALSE the element was not added. E_* failure.
  1233. --*/
  1234. {
  1235. // Locals
  1236. HRESULT hr=S_OK;
  1237. DWORD i;
  1238. CAdminAcl *pTemp=NULL;
  1239. LPVOID pvAdmin;
  1240. METADATA_HANDLE hAdminHandle;
  1241. LPCWSTR pwszRelPath;
  1242. CAdminAcl *pAdminAclToRelease = NULL;
  1243. // Check args
  1244. if (pAdminAcl==NULL)
  1245. {
  1246. hr=E_INVALIDARG;
  1247. goto exit;
  1248. }
  1249. // Don't add anything if the cache is disabled
  1250. hr=IsEnabled();
  1251. if (hr!=S_OK)
  1252. {
  1253. // Not found
  1254. goto exit;
  1255. }
  1256. // Get in locals
  1257. pvAdmin=pAdminAcl->GetAdminContext();
  1258. hAdminHandle=pAdminAcl->GetAdminHandle();
  1259. pwszRelPath=pAdminAcl->GetPath()?pAdminAcl->GetPath():L"";
  1260. // Try to lock exclusive
  1261. if (!m_Lock.TryWriteLock())
  1262. {
  1263. // Couldn't add
  1264. hr=S_FALSE;
  1265. goto exit;
  1266. }
  1267. // TryWriteLock() above succeeded, so here we have a write lock
  1268. // Try to find
  1269. hr=_Find(pvAdmin, hAdminHandle, pwszRelPath, &pTemp, &i);
  1270. // If found
  1271. if (hr==S_OK)
  1272. {
  1273. DBG_ASSERT(i<m_cAdminAclCache);
  1274. // Move to be 1st element
  1275. _MoveFirst(i);
  1276. }
  1277. else
  1278. {
  1279. // Add
  1280. hr=_InsertFirst(pAdminAcl, &pAdminAclToRelease);
  1281. }
  1282. // Unlock
  1283. m_Lock.WriteUnlock();
  1284. exit:
  1285. // Cleanup
  1286. if (pTemp)
  1287. {
  1288. pTemp->Release();
  1289. }
  1290. if ( pAdminAclToRelease )
  1291. {
  1292. pAdminAclToRelease->Release();
  1293. }
  1294. // Done
  1295. return (hr);
  1296. }
  1297. STDMETHODIMP
  1298. CAdminAclCache::_Find(
  1299. LPVOID pvAdmin,
  1300. METADATA_HANDLE hAdminHandle,
  1301. LPCWSTR pwszRelPath,
  1302. CAdminAcl **ppAdminAcl,
  1303. DWORD *pdwIndex)
  1304. /*++
  1305. Routine Description:
  1306. Finds ACL matching the object, the handle and the path.
  1307. The caller must acquire any lock.
  1308. Arguments:
  1309. pvAdmin - the admin context
  1310. hAdminHandle - the metadata handle
  1311. pwszRelPath - the path (NULL is treated as empty string)
  1312. ppAdminAcl - out the acl if found. the caller must release it.
  1313. pdwIndex - out the index of the acl if found.
  1314. Returns:
  1315. S_OK found, S_FALSE not found. E_* on failure
  1316. --*/
  1317. {
  1318. // Locals
  1319. HRESULT hr=S_OK;
  1320. CAdminAcl *pAdminAcl=NULL;
  1321. DWORD i;
  1322. LPCWSTR pwszAclPath;
  1323. // Check args
  1324. if (ppAdminAcl==NULL)
  1325. {
  1326. hr=E_INVALIDARG;
  1327. }
  1328. else
  1329. {
  1330. // Init
  1331. *ppAdminAcl=NULL;
  1332. }
  1333. if (pdwIndex==NULL)
  1334. {
  1335. hr=E_INVALIDARG;
  1336. }
  1337. else
  1338. {
  1339. // Init
  1340. *pdwIndex=0;
  1341. }
  1342. // Invalid args?
  1343. if (FAILED(hr))
  1344. {
  1345. // Bail
  1346. goto exit;
  1347. }
  1348. if (pwszRelPath==NULL)
  1349. {
  1350. // Set to empty
  1351. pwszRelPath=L"";
  1352. }
  1353. // Loop and search
  1354. for (i=0; i<m_cAdminAclCache; i++)
  1355. {
  1356. DBG_ASSERT(m_rgpAdminAclCache[i]);
  1357. pwszAclPath=m_rgpAdminAclCache[i]->GetPath()?
  1358. m_rgpAdminAclCache[i]->GetPath():L"";
  1359. if ((m_rgpAdminAclCache[i]->GetAdminContext()==pvAdmin)&&
  1360. (m_rgpAdminAclCache[i]->GetAdminHandle()==hAdminHandle)&&
  1361. (_wcsicmp(pwszAclPath, pwszRelPath)==0))
  1362. {
  1363. pAdminAcl=m_rgpAdminAclCache[i];
  1364. break;
  1365. }
  1366. }
  1367. // Found one?
  1368. if (pAdminAcl)
  1369. {
  1370. // Addref
  1371. pAdminAcl->AddRef();
  1372. // Return
  1373. *ppAdminAcl=pAdminAcl;
  1374. *pdwIndex=i;
  1375. // Don't free
  1376. pAdminAcl=NULL;
  1377. }
  1378. else
  1379. {
  1380. // Not found
  1381. hr=S_FALSE;
  1382. }
  1383. exit:
  1384. // In all cases here pAdminAcl should be NULL:
  1385. // 1. If we failed, because of invalid arguments it is initialized to NULL
  1386. // 2. If we couldn't find it in the cache it still as initialized to NULL
  1387. // 3. If we found in the cache we moved it to *ppAdminAcl and set it back to NULL
  1388. DBG_ASSERT( pAdminAcl == NULL );
  1389. // Done
  1390. return (hr);
  1391. }
  1392. STDMETHODIMP
  1393. CAdminAclCache::_MoveFirst(
  1394. DWORD i)
  1395. /*++
  1396. Routine Description:
  1397. Moves the i-th element to be 1st (at possition 0).
  1398. The caller must acquire write lock.
  1399. Arguments:
  1400. i - in the index of the acl to move 1st.
  1401. Returns:
  1402. S_OK success. E_* on failure.
  1403. --*/
  1404. {
  1405. // Locals
  1406. HRESULT hr=S_OK;
  1407. CAdminAcl *pAdminAcl=NULL;
  1408. DBG_ASSERT(i<m_cAdminAclCache);
  1409. // Check args
  1410. if (i>=m_cAdminAclCache)
  1411. {
  1412. // Bail
  1413. hr=E_INVALIDARG;
  1414. goto exit;
  1415. }
  1416. // If already 1st
  1417. if (i==0)
  1418. {
  1419. // Nothing to do
  1420. goto exit;
  1421. }
  1422. // Save
  1423. pAdminAcl=m_rgpAdminAclCache[i];
  1424. DBG_ASSERT(pAdminAcl);
  1425. // Move the 1st i elements 1 position right
  1426. memmove(m_rgpAdminAclCache+1,
  1427. m_rgpAdminAclCache,
  1428. i*sizeof(*m_rgpAdminAclCache));
  1429. // Move to 1st place
  1430. m_rgpAdminAclCache[0]=pAdminAcl;
  1431. exit:
  1432. // Done
  1433. return (hr);
  1434. }
  1435. STDMETHODIMP
  1436. CAdminAclCache::_InsertFirst(
  1437. CAdminAcl *pAdminAcl,
  1438. CAdminAcl **ppAdminAclToRelease)
  1439. /*++
  1440. Routine Description:
  1441. Adds ACL as the 1st element of the cache.
  1442. The caller must acquire write lock.
  1443. Arguments:
  1444. pAdminAcl - the acl.
  1445. ppAdminAclToRelease - since the function is called under a write lock
  1446. it should not call directly release on the element that
  1447. is to be deleted from the cache. Instead it will return
  1448. the element to caller to release after unlocking.
  1449. Returns:
  1450. S_OK the element was added. E_* failure.
  1451. --*/
  1452. {
  1453. // Locals
  1454. HRESULT hr=S_OK;
  1455. if ( ppAdminAclToRelease == NULL )
  1456. {
  1457. hr=E_INVALIDARG;
  1458. goto exit;
  1459. }
  1460. else
  1461. {
  1462. // Initialize to NULL
  1463. *ppAdminAclToRelease = NULL;
  1464. }
  1465. // Check args
  1466. if (pAdminAcl==NULL)
  1467. {
  1468. hr=E_INVALIDARG;
  1469. goto exit;
  1470. }
  1471. // If the cache is full
  1472. if (m_cAdminAclCache==ARRAYSIZE(m_rgpAdminAclCache))
  1473. {
  1474. // Delete one element
  1475. InterlockedDecrement((LONG*)&m_cAdminAclCache);
  1476. DBG_ASSERT(m_rgpAdminAclCache[m_cAdminAclCache]);
  1477. // Return the last element to the caller to release
  1478. *ppAdminAclToRelease = m_rgpAdminAclCache[m_cAdminAclCache];
  1479. m_rgpAdminAclCache[m_cAdminAclCache]=NULL;
  1480. }
  1481. // Anything in the cache?
  1482. if (m_cAdminAclCache)
  1483. {
  1484. // Move all elements 1 position right
  1485. memmove(m_rgpAdminAclCache+1,
  1486. m_rgpAdminAclCache,
  1487. m_cAdminAclCache*sizeof(*m_rgpAdminAclCache));
  1488. }
  1489. // Put on 1st place
  1490. m_rgpAdminAclCache[0]=pAdminAcl;
  1491. pAdminAcl->AddRef();
  1492. // Added 1 element
  1493. InterlockedIncrement((LONG*)&m_cAdminAclCache);
  1494. exit:
  1495. // Done
  1496. return (hr);
  1497. }