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.

875 lines
22 KiB

  1. /*===================================================================
  2. Microsoft IIS
  3. Microsoft Confidential.
  4. Copyright 1996-1997 Microsoft Corporation. All Rights Reserved.
  5. Component: Server object
  6. File: NTSec.cxx
  7. Owner: AndrewS
  8. This file contains code related to NT security on WinSta's and Desktops
  9. ===================================================================*/
  10. #include <windows.h>
  11. #include <aclapi.h>
  12. #include <dbgutil.h>
  13. #include <apiutil.h>
  14. #include <loadadm.hxx>
  15. #include <ole2.h>
  16. #include <inetsvcs.h>
  17. #include "ntsec.h"
  18. // Globals
  19. HWINSTA g_hWinSta = NULL;
  20. HDESK g_hDesktop = NULL;
  21. HWINSTA g_hWinStaPrev = NULL;
  22. HDESK g_hDesktopPrev = NULL;
  23. HRESULT AllocateAndCreateWellKnownSid(
  24. WELL_KNOWN_SID_TYPE SidType,
  25. PSID *ppSid);
  26. VOID
  27. FreeWellKnownSid(
  28. PSID* ppSid
  29. );
  30. HRESULT
  31. AllocateAndCreateWellKnownAcl(
  32. DWORD nSidCount,
  33. WELL_KNOWN_SID_TYPE SidType[],
  34. ACCESS_MASK AccessMask[],
  35. BOOL fAccessAllowedAcl,
  36. PACL* ppAcl,
  37. DWORD* pcbAcl
  38. );
  39. VOID
  40. FreeWellKnownAcl(
  41. PACL* ppAcl
  42. );
  43. /*===================================================================
  44. InitDesktopWinsta
  45. Create a desktop and a winstation for IIS to use
  46. Parameters:
  47. Returns:
  48. HRESULT S_OK on success
  49. Side effects
  50. Sets global variables
  51. Sets the process WindowStation and thread Desktop to the IIS
  52. ===================================================================*/
  53. HRESULT
  54. InitDesktopWinsta(VOID)
  55. {
  56. HRESULT hr = S_OK;
  57. DWORD dwErr;
  58. HWINSTA hWinSta = NULL;
  59. HDESK hDesktop = NULL;
  60. HWINSTA hWinStaPrev = NULL;
  61. HDESK hDesktopPrev = NULL;
  62. SECURITY_ATTRIBUTES Sa;
  63. SECURITY_DESCRIPTOR Sd;
  64. PACL pWinstaAcl = NULL;
  65. PACL pDesktopAcl = NULL;
  66. DWORD cbAcl;
  67. WELL_KNOWN_SID_TYPE SidType[2];
  68. ACCESS_MASK AccessMask[2];
  69. SidType[0] = WinBuiltinAdministratorsSid;
  70. AccessMask[0] = WINSTA_ALL;
  71. SidType[1] = WinWorldSid;
  72. AccessMask[1] = WINSTA_DESIRED;
  73. hr = AllocateAndCreateWellKnownAcl( 2,
  74. SidType,
  75. AccessMask,
  76. TRUE,
  77. &pWinstaAcl,
  78. &cbAcl );
  79. if ( FAILED(hr) )
  80. {
  81. goto exit;
  82. }
  83. if ( !InitializeSecurityDescriptor( &Sd, SECURITY_DESCRIPTOR_REVISION ) )
  84. {
  85. hr = HRESULT_FROM_WIN32( GetLastError() );
  86. goto exit;
  87. }
  88. if ( !SetSecurityDescriptorDacl( &Sd, TRUE, pWinstaAcl, FALSE ) )
  89. {
  90. hr = HRESULT_FROM_WIN32( GetLastError() );
  91. goto exit;
  92. }
  93. Sa.nLength = sizeof(Sa);
  94. Sa.lpSecurityDescriptor = &Sd;
  95. Sa.bInheritHandle = FALSE;
  96. // Save our old desktop so we can restore it later
  97. hDesktopPrev = GetThreadDesktop( GetCurrentThreadId() );
  98. if ( hDesktopPrev == NULL )
  99. {
  100. dwErr = GetLastError();
  101. hr = HRESULT_FROM_WIN32( dwErr );
  102. goto exit;
  103. }
  104. // Save our old window station so we can restore it later
  105. hWinStaPrev = GetProcessWindowStation();
  106. if ( hWinStaPrev == NULL )
  107. {
  108. dwErr = GetLastError();
  109. hr = HRESULT_FROM_WIN32( dwErr );
  110. goto exit;
  111. }
  112. // Create a winsta for IIS to use
  113. hWinSta = CreateWindowStation( SZ_IIS_WINSTA, 0, WINSTA_ALL, &Sa );
  114. if ( hWinSta == NULL )
  115. {
  116. dwErr = GetLastError();
  117. hr = HRESULT_FROM_WIN32( dwErr );
  118. goto exit;
  119. }
  120. // Set this as IIS's window station
  121. if ( !SetProcessWindowStation( hWinSta ) )
  122. {
  123. dwErr = GetLastError();
  124. hr = HRESULT_FROM_WIN32( dwErr );
  125. goto exit;
  126. }
  127. SidType[0] = WinBuiltinAdministratorsSid;
  128. AccessMask[0] = DESKTOP_ALL;
  129. SidType[1] = WinWorldSid;
  130. AccessMask[1] = DESKTOP_DESIRED;
  131. hr = AllocateAndCreateWellKnownAcl( 2,
  132. SidType,
  133. AccessMask,
  134. TRUE,
  135. &pDesktopAcl,
  136. &cbAcl );
  137. if ( FAILED(hr) )
  138. {
  139. goto exit;
  140. }
  141. if ( !InitializeSecurityDescriptor( &Sd, SECURITY_DESCRIPTOR_REVISION ) )
  142. {
  143. hr = HRESULT_FROM_WIN32( GetLastError() );
  144. goto exit;
  145. }
  146. if ( !SetSecurityDescriptorDacl( &Sd, TRUE, pDesktopAcl, FALSE ) )
  147. {
  148. hr = HRESULT_FROM_WIN32( GetLastError() );
  149. goto exit;
  150. }
  151. Sa.nLength = sizeof(Sa);
  152. Sa.lpSecurityDescriptor = &Sd;
  153. Sa.bInheritHandle = FALSE;
  154. // Create a desktop for IIS to use
  155. hDesktop = CreateDesktop( SZ_IIS_DESKTOP, NULL, NULL, 0, DESKTOP_ALL, &Sa );
  156. if ( hDesktop == NULL )
  157. {
  158. dwErr = GetLastError();
  159. hr = HRESULT_FROM_WIN32( dwErr );
  160. goto exit;
  161. }
  162. // Set the desktop
  163. if ( !SetThreadDesktop( hDesktop ) )
  164. {
  165. dwErr = GetLastError();
  166. hr = HRESULT_FROM_WIN32( dwErr );
  167. goto exit;
  168. }
  169. // store these handles in the globals
  170. g_hWinSta = hWinSta;
  171. g_hDesktop = hDesktop;
  172. g_hWinStaPrev = hWinStaPrev;
  173. g_hDesktopPrev = hDesktopPrev;
  174. hWinSta = NULL;
  175. hDesktop = NULL;
  176. hWinStaPrev = NULL;
  177. hDesktopPrev = NULL;
  178. exit:
  179. if ( FAILED( hr ) )
  180. {
  181. DBG_ASSERT( g_hWinSta == NULL );
  182. DBG_ASSERT( g_hDesktop == NULL );
  183. DBG_ASSERT( g_hWinStaPrev == NULL );
  184. DBG_ASSERT( g_hDesktopPrev == NULL );
  185. if ( hWinStaPrev != NULL )
  186. {
  187. SetProcessWindowStation( hWinStaPrev );
  188. }
  189. if ( hDesktopPrev != NULL )
  190. {
  191. SetThreadDesktop( hDesktopPrev );
  192. }
  193. }
  194. else
  195. {
  196. DBG_ASSERT( g_hWinSta != NULL );
  197. DBG_ASSERT( g_hDesktop != NULL );
  198. DBG_ASSERT( g_hWinStaPrev != NULL );
  199. DBG_ASSERT( g_hDesktopPrev != NULL );
  200. DBG_ASSERT( hWinSta == NULL );
  201. DBG_ASSERT( hDesktop == NULL );
  202. DBG_ASSERT( hWinStaPrev == NULL );
  203. DBG_ASSERT( hDesktopPrev == NULL );
  204. }
  205. FreeWellKnownAcl( &pWinstaAcl );
  206. FreeWellKnownAcl( &pDesktopAcl );
  207. if ( hDesktop != NULL )
  208. {
  209. CloseDesktop( hDesktop );
  210. hDesktop = NULL;
  211. }
  212. if ( hWinSta != NULL )
  213. {
  214. CloseWindowStation( hWinSta );
  215. hWinSta = NULL;
  216. }
  217. if ( hDesktopPrev!= NULL )
  218. {
  219. CloseDesktop( hDesktopPrev );
  220. hDesktopPrev = NULL;
  221. }
  222. if ( hWinStaPrev != NULL )
  223. {
  224. CloseWindowStation( hWinStaPrev );
  225. hWinStaPrev = NULL;
  226. }
  227. return hr;
  228. }
  229. /*===================================================================
  230. RevertToServiceDesktopWinsta
  231. Set the process WindowStation and the thread Desktop to the default
  232. service WindowStation\Desktop.
  233. To be called after COM is initialized and cached the IIS WindowStation\Desktop
  234. Parameters:
  235. Returns:
  236. HRESULT S_OK on success
  237. E_* on failure
  238. Side effects
  239. Reverst back the process WindowStation and thread Desktop
  240. ===================================================================*/
  241. HRESULT
  242. RevertToServiceDesktopWinsta(VOID)
  243. {
  244. HRESULT hr = S_OK;
  245. DWORD dwErr;
  246. // This functions should be called only if InitDesktopWinsta succeeded
  247. DBG_ASSERT( g_hWinStaPrev != NULL );
  248. DBG_ASSERT( g_hDesktopPrev != NULL );
  249. if ( ( g_hWinStaPrev == NULL ) || ( g_hDesktopPrev == NULL ) )
  250. {
  251. hr = E_FAIL;
  252. goto exit;
  253. }
  254. // Set the old window station
  255. if ( !SetProcessWindowStation( g_hWinStaPrev ) )
  256. {
  257. dwErr = GetLastError();
  258. hr = HRESULT_FROM_WIN32( dwErr );
  259. goto exit;
  260. }
  261. // Set the old desktop
  262. if ( !SetThreadDesktop( g_hDesktopPrev ) )
  263. {
  264. dwErr = GetLastError();
  265. hr = HRESULT_FROM_WIN32( dwErr );
  266. goto exit;
  267. }
  268. exit:
  269. return hr;
  270. }
  271. /*===================================================================
  272. ShutdownDesktopWinsta
  273. Closes the IIS window station and desktop
  274. Parameters:
  275. Returns:
  276. HRESULT S_OK on success
  277. E_* on failure
  278. In all cases will try to restore the window station and desktop
  279. and will close and zero out the global handles
  280. Side effects
  281. Sets global variables
  282. ===================================================================*/
  283. HRESULT
  284. ShutdownDesktopWinsta(VOID)
  285. {
  286. HRESULT hr = S_OK;
  287. DWORD dwErr;
  288. HWINSTA hWinSta = NULL;
  289. HDESK hDesktop = NULL;
  290. HWINSTA hWinStaPrev = NULL;
  291. HDESK hDesktopPrev = NULL;
  292. // get these handles from the globals
  293. hWinSta = g_hWinSta;
  294. hDesktop = g_hDesktop;
  295. hWinStaPrev = g_hWinStaPrev;
  296. hDesktopPrev = g_hDesktopPrev;
  297. g_hWinSta = NULL;
  298. g_hDesktop = NULL;
  299. g_hWinStaPrev = NULL;
  300. g_hDesktopPrev = NULL;
  301. // Set the old window station
  302. if ( hWinStaPrev != NULL )
  303. {
  304. if ( !SetProcessWindowStation( hWinStaPrev ) )
  305. {
  306. // If not failed already save the failure
  307. if ( SUCCEEDED( hr ) )
  308. {
  309. dwErr = GetLastError();
  310. hr = HRESULT_FROM_WIN32( dwErr );
  311. }
  312. // Continue cleanup even on failure
  313. }
  314. }
  315. else
  316. {
  317. // If not failed already save the failure
  318. if ( SUCCEEDED( hr ) )
  319. {
  320. hr = E_FAIL;
  321. }
  322. // Continue cleanup even on failure
  323. }
  324. // Set the old desktop
  325. if ( hDesktopPrev!= NULL )
  326. {
  327. if ( !SetThreadDesktop( hDesktopPrev ) )
  328. {
  329. // If not failed already save the failure
  330. if ( SUCCEEDED( hr ) )
  331. {
  332. dwErr = GetLastError();
  333. hr = HRESULT_FROM_WIN32( dwErr );
  334. }
  335. // Continue cleanup even on failure
  336. }
  337. }
  338. else
  339. {
  340. // If not failed already save the failure
  341. if ( SUCCEEDED( hr ) )
  342. {
  343. hr = E_FAIL;
  344. }
  345. // Continue cleanup even on failure
  346. }
  347. if ( hDesktopPrev!= NULL )
  348. {
  349. CloseDesktop( hDesktopPrev );
  350. hDesktopPrev = NULL;
  351. }
  352. if ( hWinStaPrev != NULL )
  353. {
  354. CloseWindowStation( hWinStaPrev );
  355. hWinStaPrev = NULL;
  356. }
  357. if ( hDesktop != NULL )
  358. {
  359. CloseDesktop( hDesktop );
  360. hDesktop = NULL;
  361. }
  362. else
  363. {
  364. // If not failed already save the failure
  365. if ( SUCCEEDED( hr ) )
  366. {
  367. hr = E_UNEXPECTED;
  368. }
  369. // Continue cleanup even on failure
  370. }
  371. if ( hWinSta != NULL )
  372. {
  373. CloseWindowStation( hWinSta );
  374. hWinSta = NULL;
  375. }
  376. else
  377. {
  378. // If not failed already save the failure
  379. if ( SUCCEEDED( hr ) )
  380. {
  381. hr = E_UNEXPECTED;
  382. }
  383. // Continue cleanup even on failure
  384. }
  385. DBG_ASSERT( g_hWinSta == NULL );
  386. DBG_ASSERT( g_hDesktop == NULL );
  387. DBG_ASSERT( g_hWinStaPrev == NULL );
  388. DBG_ASSERT( g_hDesktopPrev == NULL );
  389. DBG_ASSERT( hWinSta == NULL );
  390. DBG_ASSERT( hDesktop == NULL );
  391. DBG_ASSERT( hWinStaPrev == NULL );
  392. DBG_ASSERT( hDesktopPrev == NULL );
  393. return hr;
  394. }
  395. /*===================================================================
  396. InitComSecurity
  397. Setup for and call CoInitializeSecurity. This will avoid problems with
  398. DCOM security on sites that have no default security.
  399. Parameters:
  400. None
  401. Returns:
  402. HRESULT
  403. Debug -- DBG_ASSERTs on error and returns error code
  404. Side effects:
  405. Sets desktop
  406. ===================================================================*/
  407. HRESULT
  408. InitComSecurity(VOID)
  409. {
  410. HRESULT hr = NOERROR;
  411. DWORD dwErr;
  412. BOOL fRet;
  413. SECURITY_DESCRIPTOR SecurityDesc = {0};
  414. EXPLICIT_ACCESS ea = {0};
  415. ACL *pAcl = NULL;
  416. PSID pSidAdmins = NULL;
  417. PSID pSidAuthUser = NULL;
  418. // Initialize the security descriptor
  419. fRet = InitializeSecurityDescriptor( &SecurityDesc, SECURITY_DESCRIPTOR_REVISION );
  420. if ( !fRet )
  421. {
  422. dwErr = GetLastError();
  423. hr = HRESULT_FROM_WIN32( dwErr );
  424. goto exit;
  425. }
  426. // Create SID for AuthenticatedUsers
  427. hr = AllocateAndCreateWellKnownSid( WinAuthenticatedUserSid, &pSidAuthUser );
  428. if ( FAILED( hr ) )
  429. {
  430. goto exit;
  431. }
  432. DBG_ASSERT( pSidAuthUser != NULL );
  433. // Create SID for Administrators
  434. hr = AllocateAndCreateWellKnownSid( WinBuiltinAdministratorsSid, &pSidAdmins );
  435. if ( FAILED( hr ) )
  436. {
  437. goto exit;
  438. }
  439. DBG_ASSERT( pSidAdmins != NULL );
  440. // Setup AuthenticatedUsers for COM access.
  441. ea.grfAccessPermissions = COM_RIGHTS_EXECUTE;
  442. ea.grfAccessMode = SET_ACCESS;
  443. ea.grfInheritance = NO_INHERITANCE;
  444. ea.Trustee.pMultipleTrustee = NULL;
  445. ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
  446. ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
  447. ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
  448. ea.Trustee.ptstrName = (LPSTR)pSidAuthUser;
  449. // Create new ACL with this ACE.
  450. dwErr = SetEntriesInAcl( 1, &ea, NULL, &pAcl );
  451. if ( dwErr != ERROR_SUCCESS )
  452. {
  453. hr = HRESULT_FROM_WIN32( dwErr );
  454. goto exit;
  455. }
  456. DBG_ASSERT( pAcl != NULL );
  457. // Set the security descriptor owner to Administrators
  458. fRet = SetSecurityDescriptorOwner( &SecurityDesc, pSidAdmins, FALSE);
  459. if ( !fRet )
  460. {
  461. dwErr = GetLastError();
  462. hr = HRESULT_FROM_WIN32( dwErr );
  463. goto exit;
  464. }
  465. // Set the security descriptor group to Administrators
  466. fRet = SetSecurityDescriptorGroup( &SecurityDesc, pSidAdmins, FALSE);
  467. if ( !fRet )
  468. {
  469. dwErr = GetLastError();
  470. hr = HRESULT_FROM_WIN32( dwErr );
  471. goto exit;
  472. }
  473. // Set the ACL to the security descriptor.
  474. fRet = SetSecurityDescriptorDacl( &SecurityDesc, TRUE, pAcl, FALSE );
  475. if ( !fRet )
  476. {
  477. dwErr = GetLastError();
  478. hr = HRESULT_FROM_WIN32( dwErr );
  479. goto exit;
  480. }
  481. hr = CoInitializeSecurity( &SecurityDesc,
  482. -1,
  483. NULL,
  484. NULL,
  485. RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
  486. RPC_C_IMP_LEVEL_IDENTIFY,
  487. NULL,
  488. EOAC_DYNAMIC_CLOAKING | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL,
  489. NULL );
  490. if( FAILED( hr ) )
  491. {
  492. // This may fire if CoInitializeSecurity fails. So it is probably
  493. // overactive we would have let the CoInitializeSecurity call fail
  494. // in the past, before some PREFIX changes.
  495. DBG_ASSERT( SUCCEEDED( hr ) );
  496. DBGERROR(( DBG_CONTEXT,
  497. "CoInitializeSecurity failed running with default "
  498. "DCOM security settings, hr=%8x\n",
  499. hr ));
  500. }
  501. exit:
  502. if ( pSidAdmins != NULL )
  503. {
  504. LocalFree( pSidAdmins );
  505. pSidAdmins = NULL;
  506. }
  507. if ( pSidAuthUser != NULL )
  508. {
  509. LocalFree( pSidAuthUser );
  510. pSidAuthUser = NULL;
  511. }
  512. if ( pAcl != NULL )
  513. {
  514. LocalFree( pAcl );
  515. pAcl = NULL;
  516. }
  517. return (hr);
  518. }
  519. /***************************************************************************++
  520. Routine Description:
  521. Figures out how much memory is needed and allocates the memory
  522. then requests the well known sid to be copied into the memory. If
  523. all goes well then the SID is returned, if anything fails the
  524. SID is not returned.
  525. The allocated memory must be freed by the caller with LocalFree
  526. Arguments:
  527. WELL_KNOWN_SID_TYPE SidType = Enum value for the SID being requested.
  528. PSID* ppSid = Ptr to the pSid that is returned.
  529. Return Value:
  530. HRESULT.
  531. --***************************************************************************/
  532. HRESULT
  533. AllocateAndCreateWellKnownSid(
  534. WELL_KNOWN_SID_TYPE SidType,
  535. PSID *ppSid)
  536. {
  537. HRESULT hr = S_OK;
  538. DWORD dwErr;
  539. BOOL fRet;
  540. PSID pSid = NULL;
  541. DWORD cbSid = SECURITY_MAX_SID_SIZE;
  542. DBG_ASSERT ( ( ppSid != NULL ) && ( *ppSid == NULL ) );
  543. // Check args
  544. if ( ( ppSid == NULL ) || ( *ppSid != NULL ) )
  545. {
  546. hr = E_INVALIDARG;
  547. goto exit;
  548. }
  549. // At this point we know the size of the sid to allocate.
  550. pSid = (PSID)LocalAlloc( LPTR, cbSid );
  551. if ( pSid == NULL )
  552. {
  553. hr = E_OUTOFMEMORY;
  554. goto exit;
  555. }
  556. // Ok now we can get the SID
  557. fRet = CreateWellKnownSid( SidType, NULL, pSid, &cbSid );
  558. if ( !fRet )
  559. {
  560. dwErr = GetLastError();
  561. hr = HRESULT_FROM_WIN32( dwErr );
  562. goto exit;
  563. }
  564. // Return
  565. *ppSid = pSid;
  566. // Don't free
  567. pSid = NULL;
  568. exit:
  569. // Cleanup
  570. FreeWellKnownSid( &pSid );
  571. return hr;
  572. }
  573. /***************************************************************************++
  574. Routine Description:
  575. Frees memory that was allocated by the
  576. AllocateAndCreateWellKnownSid function.
  577. Arguments:
  578. PSID* ppSid = Ptr to the pointer to be freed and set to NULL.
  579. Return Value:
  580. VOID.
  581. --***************************************************************************/
  582. VOID
  583. FreeWellKnownSid(
  584. PSID* ppSid
  585. )
  586. {
  587. DBG_ASSERT ( ppSid );
  588. if ( *ppSid != NULL )
  589. {
  590. LocalFree ( *ppSid );
  591. *ppSid = NULL;
  592. }
  593. }
  594. /***************************************************************************++
  595. Routine Description:
  596. Routine will create an acl for a well known sid and return it.
  597. It allocates all the memory so you don't have to. But you do have to
  598. call FreeWellKnownAcl to free the memory.
  599. It also returns the size of memory allocated.
  600. Arguments:
  601. WELL_KNOWN_SID_TYPE SidType = Enum value for the SID being requested.
  602. BOOL fAccessAllowedAcl = Is this an allow or deny acl.
  603. PACL* ppAcl = the acl beign returned
  604. DWORD* pcbAcl = count of bytes in the acl being returned
  605. ACCESS_MASK AccessMask = the access mask that is being allowed or denied
  606. Return Value:
  607. DWORD - Win32 Status Code.
  608. Note: This code was writen to provide ACL's for COM interfaces but
  609. is not in use yet. However, it may be useful when fix the acl'ing
  610. for the IISRESET interface as well as the WAS interface so I am leaving
  611. it in.
  612. --***************************************************************************/
  613. HRESULT
  614. AllocateAndCreateWellKnownAcl(
  615. DWORD nSidCount,
  616. WELL_KNOWN_SID_TYPE SidType[],
  617. ACCESS_MASK AccessMask[],
  618. BOOL fAccessAllowedAcl,
  619. PACL* ppAcl,
  620. DWORD* pcbAcl
  621. )
  622. {
  623. HRESULT hr = S_OK;
  624. PSID pSid = NULL;
  625. DWORD dwSizeOfAcl = sizeof( ACL );
  626. PACL pAcl = NULL;
  627. DBG_ASSERT ( ppAcl != NULL && *ppAcl == NULL );
  628. DBG_ASSERT ( pcbAcl != NULL );
  629. if ( ppAcl == NULL ||
  630. *ppAcl != NULL ||
  631. pcbAcl == NULL )
  632. {
  633. return E_INVALIDARG;
  634. }
  635. *pcbAcl = 0;
  636. //
  637. // Figure out the side of the ACL to create.
  638. //
  639. // It all ready has the size of the ACl from above.
  640. // add in the size of the ace.
  641. if ( fAccessAllowedAcl )
  642. {
  643. ACCESS_ALLOWED_ACE a;
  644. dwSizeOfAcl = dwSizeOfAcl + nSidCount * (SECURITY_MAX_SID_SIZE + sizeof(a) - sizeof(a.SidStart));
  645. }
  646. else
  647. {
  648. ACCESS_DENIED_ACE d;
  649. dwSizeOfAcl = dwSizeOfAcl + nSidCount * (SECURITY_MAX_SID_SIZE + sizeof(d) - sizeof(d.SidStart));
  650. }
  651. // Now create enough space for all.
  652. pAcl = (PACL)LocalAlloc(LPTR, dwSizeOfAcl);
  653. if ( pAcl == NULL )
  654. {
  655. hr = E_OUTOFMEMORY;
  656. goto exit;
  657. }
  658. // Now initalize the ACL.
  659. if ( !InitializeAcl ( pAcl, dwSizeOfAcl, ACL_REVISION ) )
  660. {
  661. hr = HRESULT_FROM_WIN32( GetLastError() );
  662. goto exit;
  663. }
  664. for (DWORD i=0; i<nSidCount; i++)
  665. {
  666. //
  667. // Create the sid
  668. //
  669. hr = AllocateAndCreateWellKnownSid ( SidType[i], &pSid );
  670. if ( FAILED(hr) )
  671. {
  672. goto exit;
  673. }
  674. // Now add an acl of the appropriate type.
  675. if ( fAccessAllowedAcl )
  676. {
  677. if ( !AddAccessAllowedAce( pAcl, ACL_REVISION,
  678. AccessMask[i], pSid ) )
  679. {
  680. hr = HRESULT_FROM_WIN32( GetLastError() );
  681. goto exit;
  682. }
  683. }
  684. else
  685. {
  686. if ( !AddAccessDeniedAce( pAcl, ACL_REVISION,
  687. AccessMask[i], pSid ) )
  688. {
  689. hr = HRESULT_FROM_WIN32( GetLastError() );
  690. goto exit;
  691. }
  692. }
  693. FreeWellKnownSid( &pSid );
  694. }
  695. // if we make it here then we have succeeded in creating the
  696. // acl, and we will be returning it out.
  697. *ppAcl = pAcl;
  698. *pcbAcl = dwSizeOfAcl;
  699. exit:
  700. //
  701. // No matter what, we need to free the original sid that
  702. // was created for us.
  703. //
  704. FreeWellKnownSid( &pSid );
  705. //
  706. // If we are not returning the acl out
  707. // then we need to free any memory we created.
  708. //
  709. if ( *ppAcl == NULL )
  710. {
  711. FreeWellKnownAcl ( &pAcl );
  712. }
  713. return hr;
  714. }
  715. /***************************************************************************++
  716. Routine Description:
  717. Frees memory that was allocated by the
  718. AllocateAndCreateWellKnownAcl function.
  719. Arguments:
  720. PACL* ppAcl = Ptr to the pointer to be freed and set to NULL.
  721. Return Value:
  722. VOID.
  723. --***************************************************************************/
  724. VOID
  725. FreeWellKnownAcl(
  726. PACL* ppAcl
  727. )
  728. {
  729. DBG_ASSERT ( ppAcl );
  730. if ( *ppAcl != NULL )
  731. {
  732. LocalFree ( *ppAcl );
  733. *ppAcl = NULL;
  734. }
  735. }