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.

2017 lines
44 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Acledit.c
  5. Abstract:
  6. This Module implements the Acl rtl editing functions that are defined in
  7. ntseapi.h
  8. Author:
  9. Gary Kimura (GaryKi) 9-Nov-1989
  10. Environment:
  11. Pure Runtime Library Routine
  12. Revision History:
  13. --*/
  14. #include "oleds.hxx"
  15. #pragma hdrstop
  16. #include "seopaque.h"
  17. //
  18. // This is used to determine if we are going to call our private
  19. // security API's (ADSIRtlFucntions) or if we should use the standard
  20. // Win32 API's. By default we will assume we are running on Win2k+
  21. // Win9x is not an issue for this as there is no sec api support.
  22. //
  23. BOOL g_fPlatformNotNT4 = TRUE;
  24. BOOL g_fPlatformDetermined = FALSE;
  25. //
  26. // Helper routine that updates the g_fPlatformNotNt4 variable
  27. // to the correct value.
  28. //
  29. void
  30. UpdatePlatformInfo()
  31. {
  32. DWORD dwError;
  33. OSVERSIONINFO osVerInfo;
  34. //
  35. // Needed for the GetVersionEx call.
  36. //
  37. osVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  38. if (!GetVersionEx(&osVerInfo)) {
  39. //
  40. // Call failed, so we will default to Win2k
  41. //
  42. g_fPlatformNotNT4 = TRUE;
  43. }
  44. else {
  45. //
  46. // !(is this NT4).
  47. //
  48. g_fPlatformNotNT4 =
  49. ! ((osVerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
  50. && (osVerInfo.dwMajorVersion == 4));
  51. }
  52. g_fPlatformDetermined = TRUE;
  53. return;
  54. }
  55. ULONG
  56. BaseSetLastNTError(
  57. IN NTSTATUS Status
  58. );
  59. //
  60. // Define the local macros and procedure for this module
  61. //
  62. //
  63. // Return a pointer to the first Ace in an Acl (even if the Acl is empty).
  64. //
  65. // PACE_HEADER
  66. // FirstAce (
  67. // IN PACL Acl
  68. // );
  69. //
  70. #define FirstAce(Acl) ((PVOID)((PUCHAR)(Acl) + sizeof(ACL)))
  71. //
  72. // Return a pointer to the next Ace in a sequence (even if the input
  73. // Ace is the one in the sequence).
  74. //
  75. // PACE_HEADER
  76. // NextAce (
  77. // IN PACE_HEADER Ace
  78. // );
  79. //
  80. #define NextAce(Ace) ((PVOID)((PUCHAR)(Ace) + ((PACE_HEADER)(Ace))->AceSize))
  81. #define LongAligned( ptr ) (LongAlign(ptr) == ((PVOID)(ptr)))
  82. #define WordAligned( ptr ) (WordAlign(ptr) == ((PVOID)(ptr)))
  83. //++
  84. //
  85. // ULONG
  86. // SeLengthSid(
  87. // IN PSID Sid
  88. // );
  89. //
  90. // Routine Description:
  91. //
  92. // This routine computes the length of a SID.
  93. //
  94. // Arguments:
  95. //
  96. // Sid - Points to the SID whose length is to be returned.
  97. //
  98. // Return Value:
  99. //
  100. // The length, in bytes of the SID.
  101. //
  102. //--
  103. #define SeLengthSid( Sid ) \
  104. (8 + (4 * ((SID *)Sid)->SubAuthorityCount))
  105. VOID
  106. ADSIRtlpAddData (
  107. IN PVOID From,
  108. IN ULONG FromSize,
  109. IN PVOID To,
  110. IN ULONG ToSize
  111. );
  112. VOID
  113. ADSIRtlpDeleteData (
  114. IN PVOID Data,
  115. IN ULONG RemoveSize,
  116. IN ULONG TotalSize
  117. );
  118. NTSTATUS
  119. ADSIRtlCreateAcl (
  120. IN PACL Acl,
  121. IN ULONG AclLength,
  122. IN ULONG AclRevision
  123. )
  124. /*++
  125. Routine Description:
  126. This routine initializes an ACL data structure. After initialization
  127. it is an ACL with no ACE (i.e., a deny all access type ACL)
  128. Arguments:
  129. Acl - Supplies the buffer containing the ACL being initialized
  130. AclLength - Supplies the length of the ace buffer in bytes
  131. AclRevision - Supplies the revision for this Acl
  132. Return Value:
  133. NTSTATUS - STATUS_SUCCESS if successful
  134. STATUS_BUFFER_TOO_SMALL if the AclLength is too small,
  135. STATUS_INVALID_PARAMETER if the revision is out of range
  136. --*/
  137. {
  138. //
  139. // Check to see the size of the buffer is large enough to hold at
  140. // least the ACL header
  141. //
  142. if (AclLength < sizeof(ACL)) {
  143. //
  144. // Buffer to small even for the ACL header
  145. //
  146. return STATUS_BUFFER_TOO_SMALL;
  147. }
  148. //
  149. // Check to see if the revision is currently valid. Later versions
  150. // of this procedure might accept more revision levels
  151. //
  152. if (AclRevision < MIN_ACL_REVISION || AclRevision > MAX_ACL_REVISION) {
  153. //
  154. // Revision not current
  155. //
  156. return STATUS_INVALID_PARAMETER;
  157. }
  158. if ( AclLength > MAXUSHORT ) {
  159. return STATUS_INVALID_PARAMETER;
  160. }
  161. //
  162. // Initialize the ACL
  163. //
  164. Acl->AclRevision = (UCHAR)AclRevision; // Used to hardwire ACL_REVISION2 here
  165. Acl->Sbz1 = 0;
  166. Acl->AclSize = (USHORT) (AclLength & 0xfffc);
  167. Acl->AceCount = 0;
  168. Acl->Sbz2 = 0;
  169. //
  170. // And return to our caller
  171. //
  172. return STATUS_SUCCESS;
  173. }
  174. BOOLEAN
  175. ADSIRtlValidAcl (
  176. IN PACL Acl
  177. )
  178. /*++
  179. Routine Description:
  180. This procedure validates an ACL.
  181. This involves validating the revision level of the ACL and ensuring
  182. that the number of ACEs specified in the AceCount fit in the space
  183. specified by the AclSize field of the ACL header.
  184. Arguments:
  185. Acl - Pointer to the ACL structure to validate.
  186. Return Value:
  187. BOOLEAN - TRUE if the structure of Acl is valid.
  188. --*/
  189. {
  190. PACE_HEADER Ace;
  191. PISID Sid;
  192. PISID Sid2;
  193. ULONG i;
  194. UCHAR AclRevision = ACL_REVISION2;
  195. //
  196. // Check the ACL revision level
  197. //
  198. if (!ValidAclRevision(Acl)) {
  199. return(FALSE);
  200. }
  201. if (!LongAligned(Acl->AclSize)) {
  202. return(FALSE);
  203. }
  204. //
  205. // Validate all of the ACEs.
  206. //
  207. Ace = (PACE_HEADER)((PVOID)((PUCHAR)(Acl) + sizeof(ACL)));
  208. for (i = 0; i < Acl->AceCount; i++) {
  209. //
  210. // Check to make sure we haven't overrun the Acl buffer
  211. // with our ace pointer. Make sure the ACE_HEADER is in
  212. // the ACL also.
  213. //
  214. if ((PUCHAR)Ace + sizeof(ACE_HEADER) >= ((PUCHAR)Acl + Acl->AclSize)) {
  215. return(FALSE);
  216. }
  217. if (!WordAligned(&Ace->AceSize)) {
  218. return(FALSE);
  219. }
  220. if ((PUCHAR)Ace + Ace->AceSize > ((PUCHAR)Acl + Acl->AclSize)) {
  221. return(FALSE);
  222. }
  223. //
  224. // It is now safe to reference fields in the ACE header.
  225. //
  226. //
  227. // The ACE header fits into the ACL, if this is a known type of ACE,
  228. // make sure the SID is within the bounds of the ACE
  229. //
  230. if (IsKnownAceType(Ace)) {
  231. if (!LongAligned(Ace->AceSize)) {
  232. return(FALSE);
  233. }
  234. if (Ace->AceSize < sizeof(KNOWN_ACE) - sizeof(ULONG) + sizeof(SID)) {
  235. return(FALSE);
  236. }
  237. //
  238. // It's now safe to reference the parts of the SID structure, though
  239. // not the SID itself.
  240. //
  241. Sid = (PISID) & (((PKNOWN_ACE)Ace)->SidStart);
  242. if (Sid->Revision != SID_REVISION) {
  243. return(FALSE);
  244. }
  245. if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  246. return(FALSE);
  247. }
  248. //
  249. // SeLengthSid computes the size of the SID based on the subauthority count,
  250. // so it is safe to use even though we don't know that the body of the SID
  251. // is safe to reference.
  252. //
  253. if (Ace->AceSize < sizeof(KNOWN_ACE) - sizeof(ULONG) + SeLengthSid( Sid )) {
  254. return(FALSE);
  255. }
  256. //
  257. // If it's a compound ACE, then perform roughly the same set of tests, but
  258. // check the validity of both SIDs.
  259. //
  260. } else if (IsCompoundAceType(Ace)) {
  261. //
  262. // Compound ACEs became valid in revision 3
  263. //
  264. if ( Acl->AclRevision < ACL_REVISION3 ) {
  265. return FALSE;
  266. }
  267. if (!LongAligned(Ace->AceSize)) {
  268. return(FALSE);
  269. }
  270. if (Ace->AceSize < sizeof(KNOWN_COMPOUND_ACE) - sizeof(ULONG) + sizeof(SID)) {
  271. return(FALSE);
  272. }
  273. //
  274. // The only currently defined Compound ACE is an Impersonation ACE.
  275. //
  276. if (((PKNOWN_COMPOUND_ACE)Ace)->CompoundAceType != COMPOUND_ACE_IMPERSONATION) {
  277. return(FALSE);
  278. }
  279. //
  280. // Examine the first SID and make sure it's structurally valid,
  281. // and it lies within the boundaries of the ACE.
  282. //
  283. Sid = (PISID) & (((PKNOWN_COMPOUND_ACE)Ace)->SidStart);
  284. if (Sid->Revision != SID_REVISION) {
  285. return(FALSE);
  286. }
  287. if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  288. return(FALSE);
  289. }
  290. //
  291. // Compound ACEs contain two SIDs. Make sure this ACE is large enough to contain
  292. // not only the first SID, but the body of the 2nd.
  293. //
  294. if (Ace->AceSize < sizeof(KNOWN_COMPOUND_ACE) - sizeof(ULONG) + SeLengthSid( Sid ) + sizeof(SID)) {
  295. return(FALSE);
  296. }
  297. //
  298. // It is safe to reference the interior of the 2nd SID.
  299. //
  300. Sid2 = (PISID) ((PUCHAR)Sid + SeLengthSid( Sid ));
  301. if (Sid2->Revision != SID_REVISION) {
  302. return(FALSE);
  303. }
  304. if (Sid2->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  305. return(FALSE);
  306. }
  307. if (Ace->AceSize < sizeof(KNOWN_COMPOUND_ACE) - sizeof(ULONG) + SeLengthSid( Sid ) + SeLengthSid( Sid2 )) {
  308. return(FALSE);
  309. }
  310. //
  311. // If it's an object ACE, then perform roughly the same set of tests.
  312. //
  313. } else if (IsObjectAceType(Ace)) {
  314. ULONG GuidSize=0;
  315. //
  316. // Object ACEs became valid in revision 4
  317. //
  318. if ( Acl->AclRevision < ACL_REVISION4 ) {
  319. return FALSE;
  320. }
  321. if (!LongAligned(Ace->AceSize)) {
  322. return(FALSE);
  323. }
  324. //
  325. // Ensure there is room for the ACE header.
  326. //
  327. if (Ace->AceSize < sizeof(KNOWN_OBJECT_ACE) - sizeof(ULONG)) {
  328. return(FALSE);
  329. }
  330. //
  331. // Ensure there is room for the GUIDs and SID header
  332. //
  333. if ( RtlObjectAceObjectTypePresent( Ace ) ) {
  334. GuidSize += sizeof(GUID);
  335. }
  336. if ( RtlObjectAceInheritedObjectTypePresent( Ace ) ) {
  337. GuidSize += sizeof(GUID);
  338. }
  339. if (Ace->AceSize < sizeof(KNOWN_OBJECT_ACE) - sizeof(ULONG) + GuidSize + sizeof(SID)) {
  340. return(FALSE);
  341. }
  342. //
  343. // It's now safe to reference the parts of the SID structure, though
  344. // not the SID itself.
  345. //
  346. Sid = (PISID) RtlObjectAceSid( Ace );
  347. if (Sid->Revision != SID_REVISION) {
  348. return(FALSE);
  349. }
  350. if (Sid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  351. return(FALSE);
  352. }
  353. if (Ace->AceSize < sizeof(KNOWN_OBJECT_ACE) - sizeof(ULONG) + GuidSize + SeLengthSid( Sid ) ) {
  354. return(FALSE);
  355. }
  356. }
  357. //
  358. // And move Ace to the next ace position
  359. //
  360. Ace = (PACE_HEADER)((PVOID)((PUCHAR)(Ace) + ((PACE_HEADER)(Ace))->AceSize));
  361. }
  362. return(TRUE);
  363. }
  364. NTSTATUS
  365. ADSIRtlQueryInformationAcl (
  366. IN PACL Acl,
  367. OUT PVOID AclInformation,
  368. IN ULONG AclInformationLength,
  369. IN ACL_INFORMATION_CLASS AclInformationClass
  370. )
  371. /*++
  372. Routine Description:
  373. This routine returns to the caller information about an ACL. The requested
  374. information can be AclRevisionInformation, or AclSizeInformation.
  375. Arguments:
  376. Acl - Supplies the Acl being examined
  377. AclInformation - Supplies the buffer to receive the information being
  378. requested
  379. AclInformationLength - Supplies the length of the AclInformation buffer
  380. in bytes
  381. AclInformationClass - Supplies the type of information being requested
  382. Return Value:
  383. NTSTATUS - STATUS_SUCCESS if successful and an appropriate error
  384. status otherwise
  385. --*/
  386. {
  387. PACL_REVISION_INFORMATION RevisionInfo;
  388. PACL_SIZE_INFORMATION SizeInfo;
  389. PVOID FirstFree;
  390. NTSTATUS Status;
  391. //
  392. // Check the ACL revision level
  393. //
  394. if (!ValidAclRevision( Acl )) {
  395. return STATUS_INVALID_PARAMETER;
  396. }
  397. //
  398. // Case on the information class being requested
  399. //
  400. switch (AclInformationClass) {
  401. case AclRevisionInformation:
  402. //
  403. // Make sure the buffer size is correct
  404. //
  405. if (AclInformationLength < sizeof(ACL_REVISION_INFORMATION)) {
  406. return STATUS_BUFFER_TOO_SMALL;
  407. }
  408. //
  409. // Get the Acl revision and return
  410. //
  411. RevisionInfo = (PACL_REVISION_INFORMATION)AclInformation;
  412. RevisionInfo->AclRevision = Acl->AclRevision;
  413. break;
  414. case AclSizeInformation:
  415. //
  416. // Make sure the buffer size is correct
  417. //
  418. if (AclInformationLength < sizeof(ACL_SIZE_INFORMATION)) {
  419. return STATUS_BUFFER_TOO_SMALL;
  420. }
  421. //
  422. // Locate the first free spot in the Acl
  423. //
  424. if (!RtlFirstFreeAce( Acl, &FirstFree )) {
  425. //
  426. // The input Acl is ill-formed
  427. //
  428. return STATUS_INVALID_PARAMETER;
  429. }
  430. //
  431. // Given a pointer to the first free spot we can now easily compute
  432. // the number of free bytes and used bytes in the Acl.
  433. //
  434. SizeInfo = (PACL_SIZE_INFORMATION)AclInformation;
  435. SizeInfo->AceCount = Acl->AceCount;
  436. if (FirstFree == NULL) {
  437. //
  438. // With a null first free we don't have any free space in the Acl
  439. //
  440. SizeInfo->AclBytesInUse = Acl->AclSize;
  441. SizeInfo->AclBytesFree = 0;
  442. } else {
  443. //
  444. // The first free is not null so we have some free room left in
  445. // the acl
  446. //
  447. SizeInfo->AclBytesInUse = (ULONG)((PUCHAR)FirstFree - (PUCHAR)Acl);
  448. SizeInfo->AclBytesFree = Acl->AclSize - SizeInfo->AclBytesInUse;
  449. }
  450. break;
  451. default:
  452. return STATUS_INVALID_INFO_CLASS;
  453. }
  454. //
  455. // and return to our caller
  456. //
  457. return STATUS_SUCCESS;
  458. }
  459. NTSTATUS
  460. ADSIRtlSetInformationAcl (
  461. IN PACL Acl,
  462. IN PVOID AclInformation,
  463. IN ULONG AclInformationLength,
  464. IN ACL_INFORMATION_CLASS AclInformationClass
  465. )
  466. /*++
  467. Routine Description:
  468. This routine sets the state of an ACL. For now only the revision
  469. level can be set and for now only a revision level of 1 is accepted
  470. so this procedure is rather simple
  471. Arguments:
  472. Acl - Supplies the Acl being altered
  473. AclInformation - Supplies the buffer containing the information being
  474. set
  475. AclInformationLength - Supplies the length of the Acl information buffer
  476. AclInformationClass - Supplies the type of information begin set
  477. Return Value:
  478. NTSTATUS - STATUS_SUCCESS if successful and an appropriate error
  479. status otherwise
  480. --*/
  481. {
  482. PACL_REVISION_INFORMATION RevisionInfo;
  483. //
  484. // Check the ACL revision level
  485. //
  486. if (!ValidAclRevision( Acl )) {
  487. return STATUS_INVALID_PARAMETER;
  488. }
  489. //
  490. // Case on the information class being requested
  491. //
  492. switch (AclInformationClass) {
  493. case AclRevisionInformation:
  494. //
  495. // Make sure the buffer size is correct
  496. //
  497. if (AclInformationLength < sizeof(ACL_REVISION_INFORMATION)) {
  498. return STATUS_BUFFER_TOO_SMALL;
  499. }
  500. //
  501. // Get the Acl requested ACL revision level
  502. //
  503. RevisionInfo = (PACL_REVISION_INFORMATION)AclInformation;
  504. //
  505. // Don't let them lower the revision of an ACL.
  506. //
  507. if (RevisionInfo->AclRevision < Acl->AclRevision ) {
  508. return STATUS_INVALID_PARAMETER;
  509. }
  510. //
  511. // Assign the new revision.
  512. //
  513. Acl->AclRevision = (UCHAR)RevisionInfo->AclRevision;
  514. break;
  515. default:
  516. return STATUS_INVALID_INFO_CLASS;
  517. }
  518. //
  519. // and return to our caller
  520. //
  521. return STATUS_SUCCESS;
  522. }
  523. NTSTATUS
  524. ADSIRtlAddAce (
  525. IN OUT PACL Acl,
  526. IN ULONG AceRevision,
  527. IN ULONG StartingAceIndex,
  528. IN PVOID AceList,
  529. IN ULONG AceListLength
  530. )
  531. /*++
  532. Routine Description:
  533. This routine adds a string of ACEs to an ACL.
  534. Arguments:
  535. Acl - Supplies the Acl being modified
  536. AceRevision - Supplies the Acl/Ace revision of the ACE being added
  537. StartingAceIndex - Supplies the ACE index which will be the index of
  538. the first ace inserted in the acl. 0 for the beginning of the list
  539. and MAXULONG for the end of the list.
  540. AceList - Supplies the list of Aces to be added to the Acl
  541. AceListLength - Supplies the size, in bytes, of the AceList buffer
  542. Return Value:
  543. NTSTATUS - STATUS_SUCCESS if successful, and an appropriate error
  544. status otherwise
  545. --*/
  546. {
  547. PVOID FirstFree;
  548. PACE_HEADER Ace;
  549. ULONG NewAceCount;
  550. PVOID AcePosition;
  551. ULONG i;
  552. UCHAR NewRevision;
  553. //
  554. // Check the ACL structure
  555. //
  556. if (!ADSIRtlValidAcl(Acl)) {
  557. return STATUS_INVALID_PARAMETER;
  558. }
  559. //
  560. // Locate the first free ace and check to see that the Acl is
  561. // well formed.
  562. //
  563. if (!RtlFirstFreeAce( Acl, &FirstFree )) {
  564. return STATUS_INVALID_PARAMETER;
  565. }
  566. //
  567. // If the AceRevision is greater than the ACL revision, then we want to
  568. // increase the ACL revision to be the same as the new ACE revision.
  569. // We can do this because our previously defined ACE types ( 0 -> 3 ) have
  570. // not changed structure nor been discontinued in the new revision. So
  571. // we can bump the revision and the older types will not be misinterpreted.
  572. //
  573. // Compute what the final revision of the ACL is going to be, and save it
  574. // for later so we can update it once we know we're going to succeed.
  575. //
  576. NewRevision = (UCHAR)AceRevision > Acl->AclRevision ? (UCHAR)AceRevision : Acl->AclRevision;
  577. //
  578. // Check that the AceList is well formed, we do this by simply zooming
  579. // down the Ace list until we're equal to or have exceeded the ace list
  580. // length. If we are equal to the length then we're well formed otherwise
  581. // we're ill-formed. We'll also calculate how many Ace's there are
  582. // in the AceList
  583. //
  584. // In addition, now we have to make sure that we haven't been handed an
  585. // ACE type that is inappropriate for the AceRevision that was passed
  586. // in.
  587. //
  588. for (Ace = (PACE_HEADER)AceList, NewAceCount = 0;
  589. Ace < (PACE_HEADER)((PUCHAR)AceList + AceListLength);
  590. Ace = (PACE_HEADER)NextAce( Ace ), NewAceCount++) {
  591. //
  592. // Ensure the ACL revision allows this ACE type.
  593. //
  594. if ( Ace->AceType <= ACCESS_MAX_MS_V2_ACE_TYPE ) {
  595. // V2 ACE are always valid.
  596. } else if ( Ace->AceType <= ACCESS_MAX_MS_V3_ACE_TYPE ) {
  597. if ( AceRevision < ACL_REVISION3 ) {
  598. return STATUS_INVALID_PARAMETER;
  599. }
  600. } else if ( Ace->AceType <= ACCESS_MAX_MS_V4_ACE_TYPE ) {
  601. if ( AceRevision < ACL_REVISION4 ) {
  602. return STATUS_INVALID_PARAMETER;
  603. }
  604. }
  605. }
  606. //
  607. // Check to see if we've exceeded the ace list length
  608. //
  609. if (Ace > (PACE_HEADER)((PUCHAR)AceList + AceListLength)) {
  610. return STATUS_INVALID_PARAMETER;
  611. }
  612. //
  613. // Check to see if there is enough room in the Acl to store the additional
  614. // Ace list
  615. //
  616. if (FirstFree == NULL ||
  617. (PUCHAR)FirstFree + AceListLength > (PUCHAR)Acl + Acl->AclSize) {
  618. return STATUS_BUFFER_TOO_SMALL;
  619. }
  620. //
  621. // All of the input has checked okay, we now need to locate the position
  622. // where to insert the new ace list. We won't check the acl for
  623. // validity because we did earlier when got the first free ace position.
  624. //
  625. AcePosition = FirstAce( Acl );
  626. for (i = 0; i < StartingAceIndex && i < Acl->AceCount; i++) {
  627. AcePosition = NextAce( AcePosition );
  628. }
  629. //
  630. // Now Ace points to where we want to insert the ace list, We do the
  631. // insertion by adding ace list to the acl and shoving over the remainder
  632. // of the list down the acl. We know this will work because we earlier
  633. // check to make sure the new acl list will fit in the acl size
  634. //
  635. ADSIRtlpAddData( AceList, AceListLength,
  636. AcePosition, (ULONG)((PUCHAR)FirstFree - (PUCHAR)AcePosition));
  637. //
  638. // Update the Acl Header
  639. //
  640. Acl->AceCount = (USHORT)(Acl->AceCount + NewAceCount);
  641. Acl->AclRevision = NewRevision;
  642. //
  643. // And return to our caller
  644. //
  645. return STATUS_SUCCESS;
  646. }
  647. NTSTATUS
  648. ADSIRtlDeleteAce (
  649. IN OUT PACL Acl,
  650. IN ULONG AceIndex
  651. )
  652. /*++
  653. Routine Description:
  654. This routine deletes one ACE from an ACL.
  655. Arguments:
  656. Acl - Supplies the Acl being modified
  657. AceIndex - Supplies the index of the Ace to delete.
  658. Return Value:
  659. NTSTATUS - STATUS_SUCCESS if successful and an appropriate error
  660. status otherwise
  661. --*/
  662. {
  663. PVOID FirstFree;
  664. PACE_HEADER Ace;
  665. ULONG i;
  666. //
  667. // Check the ACL structure
  668. //
  669. if (!ADSIRtlValidAcl(Acl)) {
  670. return STATUS_INVALID_PARAMETER;
  671. }
  672. //
  673. // Make sure the AceIndex is within proper range, it's ulong so we know
  674. // it can't be negative
  675. //
  676. if (AceIndex >= Acl->AceCount) {
  677. return STATUS_INVALID_PARAMETER;
  678. }
  679. //
  680. // Locate the first free spot, this will tell us how much data
  681. // we'll need to colapse. If the results is false then the acl is
  682. // ill-formed
  683. //
  684. if (!RtlFirstFreeAce( Acl, &FirstFree )) {
  685. return STATUS_INVALID_PARAMETER;
  686. }
  687. //
  688. // Now locate the ace that we're going to delete. This loop
  689. // doesn't need to check the acl for being well formed.
  690. //
  691. Ace = (PACE_HEADER)FirstAce( Acl );
  692. for (i = 0; i < AceIndex; i++) {
  693. Ace = (PACE_HEADER)NextAce( Ace );
  694. }
  695. //
  696. // We've found the ace to delete to simply copy over the rest of
  697. // the acl over this ace. The delete data procedure also deletes
  698. // rest of the string that it's moving over so we don't have to
  699. //
  700. ADSIRtlpDeleteData( Ace, Ace->AceSize, (ULONG)((PUCHAR)FirstFree - (PUCHAR)Ace));
  701. //
  702. // Update the Acl header
  703. //
  704. Acl->AceCount--;
  705. //
  706. // And return to our caller
  707. //
  708. return STATUS_SUCCESS;
  709. }
  710. NTSTATUS
  711. ADSIRtlGetAce (
  712. IN PACL Acl,
  713. ULONG AceIndex,
  714. OUT PVOID *Ace
  715. )
  716. /*++
  717. Routine Description:
  718. This routine returns a pointer to an ACE in an ACl referenced by
  719. ACE index
  720. Arguments:
  721. Acl - Supplies the ACL being queried
  722. AceIndex - Supplies the Ace index to locate
  723. Ace - Receives the address of the ACE within the ACL
  724. Return Value:
  725. NTSTATUS - STATUS_SUCCESS if successful and an appropriate error
  726. status otherwise
  727. --*/
  728. {
  729. ULONG i;
  730. if (!g_fPlatformDetermined) {
  731. UpdatePlatformInfo();
  732. }
  733. //
  734. // Call WinAPI if this is Win2k.
  735. //
  736. if (g_fPlatformNotNT4) {
  737. return GetAce(Acl, AceIndex, Ace);
  738. }
  739. //
  740. // Check the ACL revision level
  741. //
  742. if (!ValidAclRevision(Acl)) {
  743. return STATUS_INVALID_PARAMETER;
  744. }
  745. //
  746. // Check the AceIndex against the Ace count of the Acl, it's ulong so
  747. // we know it can't be negative
  748. //
  749. if (AceIndex >= Acl->AceCount) {
  750. return STATUS_INVALID_PARAMETER;
  751. }
  752. //
  753. // To find the Ace requested by zooming down the Ace List.
  754. //
  755. *Ace = FirstAce( Acl );
  756. for (i = 0; i < AceIndex; i++) {
  757. //
  758. // Check to make sure we haven't overrun the Acl buffer
  759. // with our ace pointer. If we have then our input is bogus
  760. //
  761. if (*Ace >= (PVOID)((PUCHAR)Acl + Acl->AclSize)) {
  762. return STATUS_INVALID_PARAMETER;
  763. }
  764. //
  765. // And move Ace to the next ace position
  766. //
  767. *Ace = NextAce( *Ace );
  768. }
  769. //
  770. // Now Ace points to the Ace we're after, but make sure we aren't
  771. // beyond the Acl.
  772. //
  773. if (*Ace >= (PVOID)((PUCHAR)Acl + Acl->AclSize)) {
  774. return STATUS_INVALID_PARAMETER;
  775. }
  776. //
  777. // The Ace is still within the Acl so return success to our caller
  778. //
  779. return STATUS_SUCCESS;
  780. }
  781. BOOL
  782. ADSIIsValidAcl (
  783. PACL pAcl
  784. )
  785. /*++
  786. Routine Description:
  787. This procedure validates an ACL.
  788. This involves validating the revision level of the ACL and ensuring
  789. that the number of ACEs specified in the AceCount fit in the space
  790. specified by the AclSize field of the ACL header.
  791. Arguments:
  792. pAcl - Pointer to the ACL structure to validate.
  793. Return Value:
  794. BOOLEAN - TRUE if the structure of Acl is valid.
  795. --*/
  796. {
  797. if (!g_fPlatformDetermined) {
  798. UpdatePlatformInfo();
  799. }
  800. //
  801. // Call WinAPI if this is Win2k.
  802. //
  803. if (g_fPlatformNotNT4) {
  804. return IsValidAcl(pAcl);
  805. }
  806. return (BOOL) ADSIRtlValidAcl (
  807. pAcl
  808. );
  809. }
  810. BOOL
  811. ADSIInitializeAcl (
  812. PACL pAcl,
  813. DWORD nAclLength,
  814. DWORD dwAclRevision
  815. )
  816. /*++
  817. Routine Description:
  818. InitializeAcl creates a new ACL in the caller supplied memory
  819. buffer. The ACL contains zero ACEs; therefore, it is an empty ACL
  820. as opposed to a nonexistent ACL. That is, if the ACL is now set
  821. to an object it will implicitly deny access to everyone.
  822. Arguments:
  823. pAcl - Supplies the buffer containing the ACL being initialized
  824. nAclLength - Supplies the length of the ace buffer in bytes
  825. dwAclRevision - Supplies the revision for this Acl
  826. Return Value:
  827. Returns TRUE for success, FALSE for failure. Extended error status
  828. is available using GetLastError.
  829. --*/
  830. {
  831. NTSTATUS Status;
  832. if (!g_fPlatformDetermined) {
  833. UpdatePlatformInfo();
  834. }
  835. //
  836. // Call WinAPI if this is Win2k.
  837. //
  838. if (g_fPlatformNotNT4) {
  839. return InitializeAcl(pAcl, nAclLength, dwAclRevision);
  840. }
  841. Status = ADSIRtlCreateAcl (
  842. pAcl,
  843. nAclLength,
  844. dwAclRevision
  845. );
  846. if ( !NT_SUCCESS(Status) ) {
  847. BaseSetLastNTError(Status);
  848. return FALSE;
  849. }
  850. return TRUE;
  851. }
  852. BOOL
  853. ADSIGetAclInformation (
  854. PACL pAcl,
  855. PVOID pAclInformation,
  856. DWORD nAclInformationLength,
  857. ACL_INFORMATION_CLASS dwAclInformationClass
  858. )
  859. /*++
  860. Routine Description:
  861. This routine returns to the caller information about an ACL. The requested
  862. information can be AclRevisionInformation, or AclSizeInformation.
  863. Arguments:
  864. pAcl - Supplies the Acl being examined
  865. pAclInformation - Supplies the buffer to receive the information
  866. being requested
  867. nAclInformationLength - Supplies the length of the AclInformation
  868. buffer in bytes
  869. dwAclInformationClass - Supplies the type of information being
  870. requested
  871. Return Value:
  872. Returns TRUE for success, FALSE for failure. Extended error status
  873. is available using GetLastError.
  874. --*/
  875. {
  876. NTSTATUS Status;
  877. if (!g_fPlatformDetermined) {
  878. UpdatePlatformInfo();
  879. }
  880. //
  881. // Call WinAPI if this is Win2k.
  882. //
  883. if (g_fPlatformNotNT4) {
  884. return GetAclInformation(
  885. pAcl,
  886. pAclInformation,
  887. nAclInformationLength,
  888. dwAclInformationClass
  889. );
  890. }
  891. Status = ADSIRtlQueryInformationAcl (
  892. pAcl,
  893. pAclInformation,
  894. nAclInformationLength,
  895. dwAclInformationClass
  896. );
  897. if ( !NT_SUCCESS(Status) ) {
  898. BaseSetLastNTError(Status);
  899. return FALSE;
  900. }
  901. return TRUE;
  902. }
  903. BOOL
  904. ADSISetAclInformation (
  905. PACL pAcl,
  906. PVOID pAclInformation,
  907. DWORD nAclInformationLength,
  908. ACL_INFORMATION_CLASS dwAclInformationClass
  909. )
  910. /*++
  911. Routine Description:
  912. This routine sets the state of an ACL. For now only the revision
  913. level can be set and for now only a revision level of 1 is accepted
  914. so this procedure is rather simple
  915. Arguments:
  916. pAcl - Supplies the Acl being altered
  917. pAclInformation - Supplies the buffer containing the information
  918. being set
  919. nAclInformationLength - Supplies the length of the Acl information
  920. buffer
  921. dwAclInformationClass - Supplies the type of information begin set
  922. Return Value:
  923. Returns TRUE for success, FALSE for failure. Extended error status
  924. is available using GetLastError.
  925. --*/
  926. {
  927. NTSTATUS Status;
  928. if (!g_fPlatformDetermined) {
  929. UpdatePlatformInfo();
  930. }
  931. //
  932. // Call WinAPI if this is Win2k.
  933. //
  934. if (g_fPlatformNotNT4) {
  935. return SetAclInformation(
  936. pAcl,
  937. pAclInformation,
  938. nAclInformationLength,
  939. dwAclInformationClass
  940. );
  941. }
  942. Status = ADSIRtlSetInformationAcl (
  943. pAcl,
  944. pAclInformation,
  945. nAclInformationLength,
  946. dwAclInformationClass
  947. );
  948. if ( !NT_SUCCESS(Status) ) {
  949. BaseSetLastNTError(Status);
  950. return FALSE;
  951. }
  952. return TRUE;
  953. }
  954. BOOL
  955. ADSIAddAce (
  956. PACL pAcl,
  957. DWORD dwAceRevision,
  958. DWORD dwStartingAceIndex,
  959. PVOID pAceList,
  960. DWORD nAceListLength
  961. )
  962. /*++
  963. Routine Description:
  964. This routine adds a string of ACEs to an ACL.
  965. Arguments:
  966. pAcl - Supplies the Acl being modified
  967. dwAceRevision - Supplies the Acl/Ace revision of the ACE being
  968. added
  969. dwStartingAceIndex - Supplies the ACE index which will be the
  970. index of the first ace inserted in the acl. 0 for the
  971. beginning of the list and MAXULONG for the end of the list.
  972. pAceList - Supplies the list of Aces to be added to the Acl
  973. nAceListLength - Supplies the size, in bytes, of the AceList
  974. buffer
  975. Return Value:
  976. Returns TRUE for success, FALSE for failure. Extended error status
  977. is available using GetLastError.
  978. --*/
  979. {
  980. NTSTATUS Status;
  981. if (!g_fPlatformDetermined) {
  982. UpdatePlatformInfo();
  983. }
  984. //
  985. // Call WinAPI if this is Win2k.
  986. //
  987. if (g_fPlatformNotNT4) {
  988. return AddAce(
  989. pAcl,
  990. dwAceRevision,
  991. dwStartingAceIndex,
  992. pAceList,
  993. nAceListLength
  994. );
  995. }
  996. Status = ADSIRtlAddAce (
  997. pAcl,
  998. dwAceRevision,
  999. dwStartingAceIndex,
  1000. pAceList,
  1001. nAceListLength
  1002. );
  1003. if ( !NT_SUCCESS(Status) ) {
  1004. BaseSetLastNTError(Status);
  1005. return FALSE;
  1006. }
  1007. return TRUE;
  1008. }
  1009. BOOL
  1010. ADSIDeleteAce (
  1011. PACL pAcl,
  1012. DWORD dwAceIndex
  1013. )
  1014. /*++
  1015. Routine Description:
  1016. This routine deletes one ACE from an ACL.
  1017. Arguments:
  1018. pAcl - Supplies the Acl being modified
  1019. dwAceIndex - Supplies the index of the Ace to delete.
  1020. Return Value:
  1021. Returns TRUE for success, FALSE for failure. Extended error status
  1022. is available using GetLastError.
  1023. --*/
  1024. {
  1025. NTSTATUS Status;
  1026. if (!g_fPlatformDetermined) {
  1027. UpdatePlatformInfo();
  1028. }
  1029. //
  1030. // Call WinAPI if this is Win2k.
  1031. //
  1032. if (g_fPlatformNotNT4) {
  1033. return DeleteAce(pAcl, dwAceIndex);
  1034. }
  1035. Status = ADSIRtlDeleteAce (
  1036. pAcl,
  1037. dwAceIndex
  1038. );
  1039. if ( !NT_SUCCESS(Status) ) {
  1040. BaseSetLastNTError(Status);
  1041. return FALSE;
  1042. }
  1043. return TRUE;
  1044. }
  1045. BOOL
  1046. ADSIGetAce (
  1047. PACL pAcl,
  1048. DWORD dwAceIndex,
  1049. PVOID *pAce
  1050. )
  1051. /*++
  1052. Routine Description:
  1053. This routine returns a pointer to an ACE in an ACl referenced by
  1054. ACE index
  1055. Arguments:
  1056. pAcl - Supplies the ACL being queried
  1057. dwAceIndex - Supplies the Ace index to locate
  1058. pAce - Receives the address of the ACE within the ACL
  1059. Return Value:
  1060. Returns TRUE for success, FALSE for failure. Extended error status
  1061. is available using GetLastError.
  1062. --*/
  1063. {
  1064. NTSTATUS Status;
  1065. Status = ADSIRtlGetAce (
  1066. pAcl,
  1067. dwAceIndex,
  1068. pAce
  1069. );
  1070. if ( !NT_SUCCESS(Status) ) {
  1071. BaseSetLastNTError(Status);
  1072. return FALSE;
  1073. }
  1074. return TRUE;
  1075. }
  1076. //
  1077. // Internal support routine
  1078. //
  1079. VOID
  1080. ADSIRtlpAddData (
  1081. IN PVOID From,
  1082. IN ULONG FromSize,
  1083. IN PVOID To,
  1084. IN ULONG ToSize
  1085. )
  1086. /*++
  1087. Routine Description:
  1088. This routine copies data to a string of bytes. It does this by moving
  1089. over data in the to string so that the from string will fit. It also
  1090. assumes that the checks that the data will fit in memory have already
  1091. been done. Pictorally the results are as follows.
  1092. Before:
  1093. From -> ffffffffff
  1094. To -> tttttttttttttttt
  1095. After:
  1096. From -> ffffffffff
  1097. To -> fffffffffftttttttttttttttt
  1098. Arguments:
  1099. From - Supplies a pointer to the source buffer
  1100. FromSize - Supplies the size of the from buffer in bytes
  1101. To - Supplies a pointer to the destination buffer
  1102. ToSize - Supplies the size of the to buffer in bytes
  1103. Return Value:
  1104. None
  1105. --*/
  1106. {
  1107. LONG i;
  1108. //
  1109. // Shift over the To buffer enough to fit in the From buffer
  1110. //
  1111. for (i = ToSize - 1; i >= 0; i--) {
  1112. ((PUCHAR)To)[i+FromSize] = ((PUCHAR)To)[i];
  1113. }
  1114. //
  1115. // Now copy over the From buffer
  1116. //
  1117. for (i = 0; (ULONG)i < FromSize; i += 1) {
  1118. ((PUCHAR)To)[i] = ((PUCHAR)From)[i];
  1119. }
  1120. //
  1121. // and return to our caller
  1122. //
  1123. return;
  1124. }
  1125. //
  1126. // Internal support routine
  1127. //
  1128. VOID
  1129. ADSIRtlpDeleteData (
  1130. IN PVOID Data,
  1131. IN ULONG RemoveSize,
  1132. IN ULONG TotalSize
  1133. )
  1134. /*++
  1135. Routine Description:
  1136. This routine deletes a string of bytes from the front of a data buffer
  1137. and compresses the data. It also zeros out the part of the string
  1138. that is no longer in use. Pictorially the results are as follows
  1139. Before:
  1140. Data = DDDDDddddd
  1141. RemoveSize = 5
  1142. TotalSize = 10
  1143. After:
  1144. Data = ddddd00000
  1145. Arguments:
  1146. Data - Supplies a pointer to the data being altered
  1147. RemoveSize - Supplies the number of bytes to delete from the front
  1148. of the data buffer
  1149. TotalSize - Supplies the total number of bytes in the data buffer
  1150. before the delete operation
  1151. Return Value:
  1152. None
  1153. --*/
  1154. {
  1155. ULONG i;
  1156. //
  1157. // Shift over the buffer to remove the amount
  1158. //
  1159. for (i = RemoveSize; i < TotalSize; i++) {
  1160. ((PUCHAR)Data)[i-RemoveSize] = ((PUCHAR)Data)[i];
  1161. }
  1162. //
  1163. // Now as a safety precaution we'll zero out the rest of the string
  1164. //
  1165. for (i = TotalSize - RemoveSize; i < TotalSize; i++) {
  1166. ((PUCHAR)Data)[i] = 0;
  1167. }
  1168. //
  1169. // And return to our caller
  1170. //
  1171. return;
  1172. }
  1173. ULONG
  1174. BaseSetLastNTError(
  1175. IN NTSTATUS Status
  1176. )
  1177. /*++
  1178. Routine Description:
  1179. This API sets the "last error value" and the "last error string"
  1180. based on the value of Status. For status codes that don't have
  1181. a corresponding error string, the string is set to null.
  1182. Arguments:
  1183. Status - Supplies the status value to store as the last error value.
  1184. Return Value:
  1185. The corresponding Win32 error code that was stored in the
  1186. "last error value" thread variable.
  1187. --*/
  1188. {
  1189. ULONG dwErrorCode;
  1190. dwErrorCode = RtlNtStatusToDosError( Status );
  1191. SetLastError( dwErrorCode );
  1192. return( dwErrorCode );
  1193. }
  1194. NTSTATUS
  1195. ADSIRtlGetControlSecurityDescriptor (
  1196. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1197. OUT PSECURITY_DESCRIPTOR_CONTROL Control,
  1198. OUT PULONG Revision
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. This procedure retrieves the control information from a security descriptor.
  1203. Arguments:
  1204. SecurityDescriptor - Supplies the security descriptor.
  1205. Control - Receives the control information.
  1206. Revision - Receives the revision of the security descriptor.
  1207. This value will always be returned, even if an error
  1208. is returned by this routine.
  1209. Return Value:
  1210. STATUS_SUCCESS - Indicates the call completed successfully.
  1211. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  1212. descriptor is not known to the routine. It may be a newer
  1213. revision than the routine knows about.
  1214. --*/
  1215. {
  1216. //
  1217. // Always return the revision value - even if this isn't a valid
  1218. // security descriptor
  1219. //
  1220. *Revision = ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision;
  1221. if ( ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision
  1222. != SECURITY_DESCRIPTOR_REVISION ) {
  1223. return STATUS_UNKNOWN_REVISION;
  1224. }
  1225. *Control = ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Control;
  1226. return STATUS_SUCCESS;
  1227. }
  1228. NTSTATUS
  1229. ADSIRtlSetControlSecurityDescriptor (
  1230. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1231. IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
  1232. IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet
  1233. )
  1234. /*++
  1235. Routine Description:
  1236. This procedure sets the control information in a security descriptor.
  1237. For instance,
  1238. SetSecurityDescriptorControl( &SecDesc,
  1239. SE_DACL_PROTECTED,
  1240. SE_DACL_PROTECTED );
  1241. marks the DACL on the security descriptor as protected. And
  1242. SetSecurityDescriptorControl( &SecDesc,
  1243. SE_DACL_PROTECTED,
  1244. 0 );
  1245. marks the DACL as not protected.
  1246. Arguments:
  1247. pSecurityDescriptor - Supplies the security descriptor.
  1248. ControlBitsOfInterest - A mask of the control bits being changed, set,
  1249. or reset by this call. The mask is the logical OR of one or more of
  1250. the following flags:
  1251. SE_DACL_UNTRUSTED
  1252. SE_SERVER_SECURITY
  1253. SE_DACL_AUTO_INHERIT_REQ
  1254. SE_SACL_AUTO_INHERIT_REQ
  1255. SE_DACL_AUTO_INHERITED
  1256. SE_SACL_AUTO_INHERITED
  1257. SE_DACL_PROTECTED
  1258. SE_SACL_PROTECTED
  1259. ControlBitsToSet - A mask indicating what the bits specified by ControlBitsOfInterest
  1260. should be set to.
  1261. Return Value:
  1262. Returns TRUE for success, FALSE for failure. Extended error status
  1263. is available using GetLastError.
  1264. --*/
  1265. {
  1266. #define SE_VALID_CONTROL_BITS ( SE_DACL_UNTRUSTED | \
  1267. SE_SERVER_SECURITY | \
  1268. SE_DACL_AUTO_INHERIT_REQ | \
  1269. SE_SACL_AUTO_INHERIT_REQ | \
  1270. SE_DACL_AUTO_INHERITED | \
  1271. SE_SACL_AUTO_INHERITED | \
  1272. SE_DACL_PROTECTED | \
  1273. SE_SACL_PROTECTED )
  1274. //
  1275. // Ensure the caller passed valid bits.
  1276. //
  1277. if ( (ControlBitsOfInterest & ~SE_VALID_CONTROL_BITS) != 0 ||
  1278. (ControlBitsToSet & ~ControlBitsOfInterest) != 0 ) {
  1279. return STATUS_INVALID_PARAMETER;
  1280. }
  1281. ((SECURITY_DESCRIPTOR *)pSecurityDescriptor)->Control &= ~ControlBitsOfInterest;
  1282. ((SECURITY_DESCRIPTOR *)pSecurityDescriptor)->Control |= ControlBitsToSet;
  1283. return STATUS_SUCCESS;
  1284. }
  1285. BOOL
  1286. ADSIGetControlSecurityDescriptor (
  1287. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1288. OUT PSECURITY_DESCRIPTOR_CONTROL Control,
  1289. OUT PULONG Revision
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. This procedure retrieves the control information from a security descriptor.
  1294. Arguments:
  1295. SecurityDescriptor - Supplies the security descriptor.
  1296. Control - Receives the control information.
  1297. Revision - Receives the revision of the security descriptor.
  1298. This value will always be returned, even if an error
  1299. is returned by this routine.
  1300. Return Value:
  1301. STATUS_SUCCESS - Indicates the call completed successfully.
  1302. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  1303. descriptor is not known to the routine. It may be a newer
  1304. revision than the routine knows about.
  1305. --*/
  1306. {
  1307. NTSTATUS Status;
  1308. Status = ADSIRtlGetControlSecurityDescriptor (
  1309. SecurityDescriptor,
  1310. Control,
  1311. Revision
  1312. );
  1313. if ( !NT_SUCCESS(Status) ) {
  1314. BaseSetLastNTError(Status);
  1315. return FALSE;
  1316. }
  1317. return TRUE;
  1318. }
  1319. BOOL
  1320. ADSISetControlSecurityDescriptor (
  1321. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1322. IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
  1323. IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet
  1324. )
  1325. /*++
  1326. Routine Description:
  1327. This procedure sets the control information in a security descriptor.
  1328. For instance,
  1329. SetSecurityDescriptorControl( &SecDesc,
  1330. SE_DACL_PROTECTED,
  1331. SE_DACL_PROTECTED );
  1332. marks the DACL on the security descriptor as protected. And
  1333. SetSecurityDescriptorControl( &SecDesc,
  1334. SE_DACL_PROTECTED,
  1335. 0 );
  1336. marks the DACL as not protected.
  1337. Arguments:
  1338. pSecurityDescriptor - Supplies the security descriptor.
  1339. ControlBitsOfInterest - A mask of the control bits being changed, set,
  1340. or reset by this call. The mask is the logical OR of one or more of
  1341. the following flags:
  1342. SE_DACL_UNTRUSTED
  1343. SE_SERVER_SECURITY
  1344. SE_DACL_AUTO_INHERIT_REQ
  1345. SE_SACL_AUTO_INHERIT_REQ
  1346. SE_DACL_AUTO_INHERITED
  1347. SE_SACL_AUTO_INHERITED
  1348. SE_DACL_PROTECTED
  1349. SE_SACL_PROTECTED
  1350. ControlBitsToSet - A mask indicating what the bits specified by ControlBitsOfInterest
  1351. should be set to.
  1352. Return Value:
  1353. Returns TRUE for success, FALSE for failure. Extended error status
  1354. is available using GetLastError.
  1355. --*/
  1356. {
  1357. NTSTATUS Status;
  1358. if (!g_fPlatformDetermined) {
  1359. UpdatePlatformInfo();
  1360. }
  1361. //
  1362. // Call WinAPI if this is Win2k.
  1363. //
  1364. if (g_fPlatformNotNT4) {
  1365. //
  1366. // In this case we should be able to load
  1367. // the function from advapi32 and should not
  1368. // use our private api.
  1369. //
  1370. SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
  1371. return FALSE;
  1372. }
  1373. Status = ADSIRtlSetControlSecurityDescriptor (
  1374. pSecurityDescriptor,
  1375. ControlBitsOfInterest,
  1376. ControlBitsToSet
  1377. );
  1378. if ( !NT_SUCCESS(Status) ) {
  1379. BaseSetLastNTError(Status);
  1380. return FALSE;
  1381. }
  1382. return TRUE;
  1383. }