Source code of Windows XP (NT5)
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.

11590 lines
319 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. sertl.c
  5. Abstract:
  6. This Module implements many security rtl routines defined in ntseapi.h
  7. Author:
  8. Jim Kelly (JimK) 23-Mar-1990
  9. Robert Reichel (RobertRe) 1-Mar-1991
  10. Environment:
  11. Pure Runtime Library Routine
  12. Revision History:
  13. --*/
  14. #include "ntrtlp.h"
  15. #include <winerror.h>
  16. #ifndef BLDR_KERNEL_RUNTIME
  17. #include <stdio.h>
  18. #include "seopaque.h"
  19. #include "sertlp.h"
  20. #ifdef NTOS_KERNEL_RUNTIME
  21. #include <..\se\sep.h>
  22. #else // NTOS_KERNEL_RUNTIME
  23. #include <..\ntdll\ldrp.h>
  24. #endif // NTOS_KERNEL_RUNTIME
  25. #undef RtlEqualLuid
  26. NTSYSAPI
  27. BOOLEAN
  28. NTAPI
  29. RtlEqualLuid (
  30. PLUID Luid1,
  31. PLUID Luid2
  32. );
  33. NTSTATUS
  34. RtlpConvertAclToAutoInherit (
  35. IN PACL ParentAcl OPTIONAL,
  36. IN PACL ChildAcl,
  37. IN GUID *ObjectType OPTIONAL,
  38. IN BOOLEAN IsDirectoryObject,
  39. IN PSID OwnerSid,
  40. IN PSID GroupSid,
  41. IN PGENERIC_MAPPING GenericMapping,
  42. OUT PACL *NewAcl,
  43. OUT PULONG NewGenericControl
  44. );
  45. BOOLEAN
  46. RtlpCopyEffectiveAce (
  47. IN PACE_HEADER OldAce,
  48. IN BOOLEAN AutoInherit,
  49. IN BOOLEAN WillGenerateInheritAce,
  50. IN PSID ClientOwnerSid,
  51. IN PSID ClientGroupSid,
  52. IN PSID ServerOwnerSid OPTIONAL,
  53. IN PSID ServerGroupSid OPTIONAL,
  54. IN PGENERIC_MAPPING GenericMapping,
  55. IN GUID **pNewObjectType OPTIONAL,
  56. IN ULONG GuidCount,
  57. IN OUT PVOID *AcePosition,
  58. OUT PULONG NewAceLength,
  59. OUT PACL NewAcl,
  60. OUT PBOOLEAN ObjectAceInherited OPTIONAL,
  61. OUT PBOOLEAN EffectiveAceMapped,
  62. OUT PBOOLEAN AclOverflowed
  63. );
  64. typedef enum {
  65. CopyInheritedAces,
  66. CopyNonInheritedAces,
  67. CopyAllAces } ACE_TYPE_TO_COPY;
  68. NTSTATUS
  69. RtlpCopyAces(
  70. IN PACL Acl,
  71. IN PGENERIC_MAPPING GenericMapping,
  72. IN ACE_TYPE_TO_COPY AceTypeToCopy,
  73. IN UCHAR AceFlagsToReset,
  74. IN BOOLEAN MapSids,
  75. IN PSID ClientOwnerSid,
  76. IN PSID ClientGroupSid,
  77. IN PSID ServerOwnerSid OPTIONAL,
  78. IN PSID ServerGroupSid OPTIONAL,
  79. IN BOOLEAN IsDirectoryObject,
  80. IN BOOLEAN RetainInheritedAceBit,
  81. OUT PULONG NewAclSizeParam,
  82. OUT PACL NewAcl
  83. );
  84. NTSTATUS
  85. RtlpGenerateInheritedAce (
  86. IN PACE_HEADER OldAce,
  87. IN BOOLEAN IsDirectoryObject,
  88. IN BOOLEAN AutoInherit,
  89. IN PSID ClientOwnerSid,
  90. IN PSID ClientGroupSid,
  91. IN PSID ServerOwnerSid OPTIONAL,
  92. IN PSID ServerGroupSid OPTIONAL,
  93. IN PGENERIC_MAPPING GenericMapping,
  94. IN GUID **pNewObjectType OPTIONAL,
  95. IN ULONG GuidCount,
  96. OUT PULONG NewAceLength,
  97. OUT PACL NewAcl,
  98. OUT PULONG NewAceExtraLength,
  99. OUT PBOOLEAN ObjectAceInherited
  100. );
  101. NTSTATUS
  102. RtlpGenerateInheritAcl(
  103. IN PACL Acl,
  104. IN BOOLEAN IsDirectoryObject,
  105. IN BOOLEAN AutoInherit,
  106. IN PSID ClientOwnerSid,
  107. IN PSID ClientGroupSid,
  108. IN PSID ServerOwnerSid OPTIONAL,
  109. IN PSID ServerGroupSid OPTIONAL,
  110. IN PGENERIC_MAPPING GenericMapping,
  111. IN GUID **pNewObjectType OPTIONAL,
  112. IN ULONG GuidCount,
  113. OUT PULONG NewAclSizeParam,
  114. OUT PACL NewAcl,
  115. OUT PBOOLEAN ObjectAceInherited
  116. );
  117. NTSTATUS
  118. RtlpInheritAcl2 (
  119. IN PACL DirectoryAcl,
  120. IN PACL ChildAcl,
  121. IN ULONG ChildGenericControl,
  122. IN BOOLEAN IsDirectoryObject,
  123. IN BOOLEAN AutoInherit,
  124. IN BOOLEAN DefaultDescriptorForObject,
  125. IN PSID OwnerSid,
  126. IN PSID GroupSid,
  127. IN PSID ServerOwnerSid OPTIONAL,
  128. IN PSID ServerGroupSid OPTIONAL,
  129. IN PGENERIC_MAPPING GenericMapping,
  130. IN BOOLEAN IsSacl,
  131. IN GUID **pNewObjectType OPTIONAL,
  132. IN ULONG GuidCount,
  133. IN PULONG AclBufferSize,
  134. IN OUT PUCHAR AclBuffer,
  135. OUT PBOOLEAN NewAclExplicitlyAssigned,
  136. OUT PULONG NewGenericControl
  137. );
  138. NTSTATUS
  139. RtlpComputeMergedAcl (
  140. IN PACL CurrentAcl,
  141. IN ULONG CurrentGenericControl,
  142. IN PACL ModificationAcl,
  143. IN ULONG ModificationGenericControl,
  144. IN PSID ClientOwnerSid,
  145. IN PSID ClientGroupSid,
  146. IN PGENERIC_MAPPING GenericMapping,
  147. IN BOOLEAN IsSacl,
  148. OUT PACL *NewAcl,
  149. OUT PULONG NewGenericControl
  150. );
  151. NTSTATUS
  152. RtlpComputeMergedAcl2 (
  153. IN PACL CurrentAcl,
  154. IN ULONG CurrentGenericControl,
  155. IN PACL ModificationAcl,
  156. IN ULONG ModificationGenericControl,
  157. IN PSID ClientOwnerSid,
  158. IN PSID ClientGroupSid,
  159. IN PGENERIC_MAPPING GenericMapping,
  160. IN BOOLEAN IsSacl,
  161. IN PULONG AclBufferSize,
  162. IN OUT PUCHAR AclBuffer,
  163. OUT PULONG NewGenericControl
  164. );
  165. BOOLEAN
  166. RtlpCompareAces(
  167. IN PKNOWN_ACE InheritedAce,
  168. IN PKNOWN_ACE ChildAce,
  169. IN PSID OwnerSid,
  170. IN PSID GroupSid
  171. );
  172. BOOLEAN
  173. RtlpCompareKnownObjectAces(
  174. IN PKNOWN_OBJECT_ACE InheritedAce,
  175. IN PKNOWN_OBJECT_ACE ChildAce,
  176. IN PSID OwnerSid OPTIONAL,
  177. IN PSID GroupSid OPTIONAL
  178. );
  179. BOOLEAN
  180. RtlpCompareKnownAces(
  181. IN PKNOWN_ACE InheritedAce,
  182. IN PKNOWN_ACE ChildAce,
  183. IN PSID OwnerSid OPTIONAL,
  184. IN PSID GroupSid OPTIONAL
  185. );
  186. BOOLEAN
  187. RtlpIsDuplicateAce(
  188. IN PACL Acl,
  189. IN PKNOWN_ACE NewAce
  190. );
  191. BOOLEAN
  192. RtlpGuidPresentInGuidList(
  193. IN GUID *InheritedObjectType,
  194. IN GUID **pNewObjectType,
  195. IN ULONG GuidCount
  196. );
  197. NTSTATUS
  198. RtlpCreateServerAcl(
  199. IN PACL Acl,
  200. IN BOOLEAN AclUntrusted,
  201. IN PSID ServerSid,
  202. OUT PACL *ServerAcl,
  203. OUT BOOLEAN *ServerAclAllocated
  204. );
  205. NTSTATUS
  206. RtlpGetDefaultsSubjectContext(
  207. HANDLE ClientToken,
  208. OUT PTOKEN_OWNER *OwnerInfo,
  209. OUT PTOKEN_PRIMARY_GROUP *GroupInfo,
  210. OUT PTOKEN_DEFAULT_DACL *DefaultDaclInfo,
  211. OUT PTOKEN_OWNER *ServerOwner,
  212. OUT PTOKEN_PRIMARY_GROUP *ServerGroup
  213. );
  214. BOOLEAN RtlpValidateSDOffsetAndSize (
  215. IN ULONG Offset,
  216. IN ULONG Length,
  217. IN ULONG MinLength,
  218. OUT PULONG MaxLength
  219. );
  220. BOOLEAN
  221. RtlValidRelativeSecurityDescriptor (
  222. IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
  223. IN ULONG SecurityDescriptorLength,
  224. IN SECURITY_INFORMATION RequiredInformation
  225. );
  226. #if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  227. #pragma alloc_text(PAGE,RtlRunEncodeUnicodeString)
  228. #pragma alloc_text(PAGE,RtlRunDecodeUnicodeString)
  229. #pragma alloc_text(PAGE,RtlEraseUnicodeString)
  230. #pragma alloc_text(PAGE,RtlAdjustPrivilege)
  231. #pragma alloc_text(PAGE,RtlValidSid)
  232. #pragma alloc_text(PAGE,RtlEqualSid)
  233. #pragma alloc_text(PAGE,RtlEqualPrefixSid)
  234. #pragma alloc_text(PAGE,RtlLengthRequiredSid)
  235. #pragma alloc_text(PAGE,RtlInitializeSid)
  236. #pragma alloc_text(PAGE,RtlIdentifierAuthoritySid)
  237. #pragma alloc_text(PAGE,RtlSubAuthoritySid)
  238. #pragma alloc_text(PAGE,RtlSubAuthorityCountSid)
  239. #pragma alloc_text(PAGE,RtlLengthSid)
  240. #pragma alloc_text(PAGE,RtlCopySid)
  241. #pragma alloc_text(PAGE,RtlCopySidAndAttributesArray)
  242. #pragma alloc_text(PAGE,RtlLengthSidAsUnicodeString)
  243. #pragma alloc_text(PAGE,RtlConvertSidToUnicodeString)
  244. #pragma alloc_text(PAGE,RtlEqualLuid)
  245. #pragma alloc_text(PAGE,RtlCopyLuid)
  246. #pragma alloc_text(PAGE,RtlCopyLuidAndAttributesArray)
  247. #pragma alloc_text(PAGE,RtlCreateSecurityDescriptor)
  248. #pragma alloc_text(PAGE,RtlCreateSecurityDescriptorRelative)
  249. #pragma alloc_text(PAGE,RtlValidSecurityDescriptor)
  250. #pragma alloc_text(PAGE,RtlLengthSecurityDescriptor)
  251. #pragma alloc_text(PAGE,RtlSetAttributesSecurityDescriptor)
  252. #pragma alloc_text(PAGE,RtlGetControlSecurityDescriptor)
  253. #pragma alloc_text(PAGE,RtlSetControlSecurityDescriptor)
  254. #pragma alloc_text(PAGE,RtlSetDaclSecurityDescriptor)
  255. #pragma alloc_text(PAGE,RtlGetDaclSecurityDescriptor)
  256. #pragma alloc_text(PAGE,RtlSetSaclSecurityDescriptor)
  257. #pragma alloc_text(PAGE,RtlGetSaclSecurityDescriptor)
  258. #pragma alloc_text(PAGE,RtlSetOwnerSecurityDescriptor)
  259. #pragma alloc_text(PAGE,RtlGetOwnerSecurityDescriptor)
  260. #pragma alloc_text(PAGE,RtlSetGroupSecurityDescriptor)
  261. #pragma alloc_text(PAGE,RtlGetGroupSecurityDescriptor)
  262. #pragma alloc_text(PAGE,RtlAreAllAccessesGranted)
  263. #pragma alloc_text(PAGE,RtlAreAnyAccessesGranted)
  264. #pragma alloc_text(PAGE,RtlMapGenericMask)
  265. #pragma alloc_text(PAGE,RtlImpersonateSelf)
  266. #pragma alloc_text(PAGE,RtlpApplyAclToObject)
  267. #pragma alloc_text(PAGE,RtlpCopyEffectiveAce)
  268. #pragma alloc_text(PAGE,RtlpCopyAces)
  269. #pragma alloc_text(PAGE,RtlpGuidPresentInGuidList)
  270. #pragma alloc_text(PAGE,RtlpInheritAcl2)
  271. #pragma alloc_text(PAGE,RtlpInheritAcl)
  272. #pragma alloc_text(PAGE,RtlpGenerateInheritedAce)
  273. #pragma alloc_text(PAGE,RtlpGenerateInheritAcl)
  274. #pragma alloc_text(PAGE,RtlpComputeMergedAcl2)
  275. #pragma alloc_text(PAGE,RtlpComputeMergedAcl)
  276. #pragma alloc_text(PAGE,RtlpConvertToAutoInheritSecurityObject)
  277. #pragma alloc_text(PAGE,RtlpCompareAces)
  278. #pragma alloc_text(PAGE,RtlpCompareKnownAces)
  279. #pragma alloc_text(PAGE,RtlpCompareKnownObjectAces)
  280. #pragma alloc_text(PAGE,RtlpConvertAclToAutoInherit)
  281. #pragma alloc_text(PAGE,RtlpIsDuplicateAce)
  282. #pragma alloc_text(PAGE,RtlpCreateServerAcl)
  283. #pragma alloc_text(PAGE,RtlpNewSecurityObject)
  284. #pragma alloc_text(PAGE,RtlpSetSecurityObject)
  285. #pragma alloc_text(PAGE,RtlpValidateSDOffsetAndSize)
  286. #pragma alloc_text(PAGE,RtlValidRelativeSecurityDescriptor)
  287. #pragma alloc_text(PAGE,RtlGetSecurityDescriptorRMControl)
  288. #pragma alloc_text(PAGE,RtlSetSecurityDescriptorRMControl)
  289. #endif
  290. ///////////////////////////////////////////////////////////////////////////////
  291. // //
  292. // Local Macros and Symbols //
  293. // //
  294. ///////////////////////////////////////////////////////////////////////////////
  295. #define CREATOR_SID_SIZE 12
  296. #define max(a,b) (((a) > (b)) ? (a) : (b))
  297. //
  298. // Define an array mapping all ACE types to their base type.
  299. //
  300. // For instance, all allowed ACE types are similar. As are all denied ACE types.
  301. //
  302. #if defined(ALLOC_DATA_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
  303. #pragma const_seg("PAGECONST")
  304. #endif
  305. const UCHAR RtlBaseAceType[] = {
  306. ACCESS_ALLOWED_ACE_TYPE, // ACCESS_ALLOWED_ACE_TYPE (0x0)
  307. ACCESS_DENIED_ACE_TYPE, // ACCESS_DENIED_ACE_TYPE (0x1)
  308. SYSTEM_AUDIT_ACE_TYPE, // SYSTEM_AUDIT_ACE_TYPE (0x2)
  309. SYSTEM_ALARM_ACE_TYPE, // SYSTEM_ALARM_ACE_TYPE (0x3)
  310. ACCESS_ALLOWED_ACE_TYPE, // ACCESS_ALLOWED_COMPOUND_ACE_TYPE (0x4)
  311. ACCESS_ALLOWED_ACE_TYPE, // ACCESS_ALLOWED_OBJECT_ACE_TYPE (0x5)
  312. ACCESS_DENIED_ACE_TYPE, // ACCESS_DENIED_OBJECT_ACE_TYPE (0x6)
  313. SYSTEM_AUDIT_ACE_TYPE, // SYSTEM_AUDIT_OBJECT_ACE_TYPE (0x7)
  314. SYSTEM_ALARM_ACE_TYPE // SYSTEM_ALARM_OBJECT_ACE_TYPE (0x8)
  315. };
  316. //
  317. // Define an array defining whether an ACE is a system ACE
  318. //
  319. const UCHAR RtlIsSystemAceType[] = {
  320. FALSE, // ACCESS_ALLOWED_ACE_TYPE (0x0)
  321. FALSE, // ACCESS_DENIED_ACE_TYPE (0x1)
  322. TRUE, // SYSTEM_AUDIT_ACE_TYPE (0x2)
  323. TRUE, // SYSTEM_ALARM_ACE_TYPE (0x3)
  324. FALSE, // ACCESS_ALLOWED_COMPOUND_ACE_TYPE (0x4)
  325. FALSE, // ACCESS_ALLOWED_OBJECT_ACE_TYPE (0x5)
  326. FALSE, // ACCESS_DENIED_OBJECT_ACE_TYPE (0x6)
  327. TRUE, // SYSTEM_AUDIT_OBJECT_ACE_TYPE (0x7)
  328. TRUE // SYSTEM_ALARM_OBJECT_ACE_TYPE (0x8)
  329. };
  330. #if DBG
  331. BOOLEAN RtlpVerboseConvert = FALSE;
  332. #endif // DBG
  333. #define SE_VALID_CONTROL_BITS ( SE_DACL_UNTRUSTED | \
  334. SE_SERVER_SECURITY | \
  335. SE_DACL_AUTO_INHERIT_REQ | \
  336. SE_SACL_AUTO_INHERIT_REQ | \
  337. SE_DACL_AUTO_INHERITED | \
  338. SE_SACL_AUTO_INHERITED | \
  339. SE_DACL_PROTECTED | \
  340. SE_SACL_PROTECTED )
  341. ///////////////////////////////////////////////////////////////////////////////
  342. // //
  343. // Null DACL assertions //
  344. // //
  345. ///////////////////////////////////////////////////////////////////////////////
  346. #if DBG
  347. #define ASSERT_ON_NULL_DACL 1
  348. #endif
  349. #ifdef ASSERT_ON_NULL_DACL
  350. ULONG RtlpAssertOnNullDacls;
  351. #endif // ASSERT_ON_NULL_DACL
  352. ///////////////////////////////////////////////////////////////////////////////
  353. // //
  354. // Exported Procedures //
  355. // //
  356. ///////////////////////////////////////////////////////////////////////////////
  357. VOID
  358. RtlRunEncodeUnicodeString(
  359. PUCHAR Seed OPTIONAL,
  360. PUNICODE_STRING String
  361. )
  362. /*++
  363. Routine Description:
  364. This function performs a trivial XOR run-encoding of a string.
  365. The purpose of this run-encoding is to change the character values
  366. to appear somewhat random and typically not printable. This is
  367. useful for transforming passwords that you don't want to be easily
  368. distinguishable by visually scanning a paging file or memory dump.
  369. Arguments:
  370. Seed - Points to a seed value to use in the encoding. If the
  371. pointed to value is zero, then this routine will assign
  372. a value.
  373. String - The string to encode. This string may be decode
  374. by passing it and the seed value to RtlRunDecodeUnicodeString().
  375. Return Value:
  376. None - Nothing can really go wrong unless the caller passes bogus
  377. parameters. In this case, the caller can catch the access
  378. violation.
  379. --*/
  380. {
  381. LARGE_INTEGER Time;
  382. PUCHAR LocalSeed;
  383. NTSTATUS Status;
  384. ULONG i;
  385. PSTRING S;
  386. RTL_PAGED_CODE();
  387. //
  388. // Typecast so we can work on bytes rather than WCHARs
  389. //
  390. S = (PSTRING)((PVOID)String);
  391. //
  392. // If a seed wasn't passed, use the 2nd byte of current time.
  393. // This byte seems to be sufficiently random (by observation).
  394. //
  395. if ((*Seed) == 0) {
  396. Status = NtQuerySystemTime ( &Time );
  397. ASSERT(NT_SUCCESS(Status));
  398. LocalSeed = (PUCHAR)((PVOID)&Time);
  399. i = 1;
  400. (*Seed) = LocalSeed[ i ];
  401. //
  402. // Occasionally, this byte could be zero. That would cause the
  403. // string to become un-decodable, since 0 is the magic value that
  404. // causes us to re-gen the seed. This loop makes sure that we
  405. // never end up with a zero byte (unless time is zero, as well).
  406. //
  407. while ( ((*Seed) == 0) && ( i < sizeof( Time ) ) )
  408. {
  409. (*Seed) |= LocalSeed[ i++ ] ;
  410. }
  411. if ( (*Seed) == 0 )
  412. {
  413. (*Seed) = 1;
  414. }
  415. }
  416. //
  417. // Transform the initial byte.
  418. // The funny constant just keeps the first byte from propagating
  419. // into the second byte in the next step. Without a funny constant
  420. // this would happen for many languages (which typically have every
  421. // other byte zero.
  422. //
  423. //
  424. if (S->Length >= 1) {
  425. S->Buffer[0] ^= ((*Seed) | 0X43);
  426. }
  427. //
  428. // Now transform the rest of the string
  429. //
  430. for (i=1; i<S->Length; i++) {
  431. //
  432. // There are export issues that cause us to want to
  433. // keep this algorithm simple. Please don't change it
  434. // without checking with JimK first. Thanks.
  435. //
  436. //
  437. // In order to be compatible with zero terminated unicode strings,
  438. // this algorithm is designed to not produce a wide character of
  439. // zero as long a the seed is not zero.
  440. //
  441. //
  442. // Simple running XOR with the previous byte and the
  443. // seed value.
  444. //
  445. S->Buffer[i] ^= (S->Buffer[i-1]^(*Seed));
  446. }
  447. return;
  448. }
  449. VOID
  450. RtlRunDecodeUnicodeString(
  451. UCHAR Seed,
  452. PUNICODE_STRING String
  453. )
  454. /*++
  455. Routine Description:
  456. This function performs the inverse of the function performed
  457. by RtlRunEncodeUnicodeString(). Please see RtlRunEncodeUnicodeString()
  458. for details.
  459. Arguments:
  460. Seed - The seed value to use in RtlRunEncodeUnicodeString().
  461. String - The string to reveal.
  462. Return Value:
  463. None - Nothing can really go wrong unless the caller passes bogus
  464. parameters. In this case, the caller can catch the access
  465. violation.
  466. --*/
  467. {
  468. ULONG
  469. i;
  470. PSTRING
  471. S;
  472. RTL_PAGED_CODE();
  473. //
  474. // Typecast so we can work on bytes rather than WCHARs
  475. //
  476. S = (PSTRING)((PVOID)String);
  477. //
  478. // Transform the end of the string
  479. //
  480. for (i=S->Length; i>1; i--) {
  481. //
  482. // a simple running XOR with the previous byte and the
  483. // seed value.
  484. //
  485. S->Buffer[i-1] ^= (S->Buffer[i-2]^Seed);
  486. }
  487. //
  488. // Finally, transform the initial byte
  489. //
  490. if (S->Length >= 1) {
  491. S->Buffer[0] ^= (Seed | 0X43);
  492. }
  493. return;
  494. }
  495. VOID
  496. RtlEraseUnicodeString(
  497. PUNICODE_STRING String
  498. )
  499. /*++
  500. Routine Description:
  501. This function scrubs the passed string by over-writing all
  502. characters in the string. The entire string (i.e., MaximumLength)
  503. is erased, not just the current length.
  504. Argumen ts:
  505. String - The string to be erased.
  506. Return Value:
  507. None - Nothing can really go wrong unless the caller passes bogus
  508. parameters. In this case, the caller can catch the access
  509. violation.
  510. --*/
  511. {
  512. RTL_PAGED_CODE();
  513. if ((String->Buffer == NULL) || (String->MaximumLength == 0)) {
  514. return;
  515. }
  516. RtlZeroMemory( (PVOID)String->Buffer, (ULONG)String->MaximumLength );
  517. String->Length = 0;
  518. return;
  519. }
  520. NTSTATUS
  521. RtlAdjustPrivilege(
  522. ULONG Privilege,
  523. BOOLEAN Enable,
  524. BOOLEAN Client,
  525. PBOOLEAN WasEnabled
  526. )
  527. /*++
  528. Routine Description:
  529. This procedure enables or disables a privilege process-wide.
  530. Arguments:
  531. Privilege - The lower 32-bits of the privilege ID to be enabled or
  532. disabled. The upper 32-bits is assumed to be zero.
  533. Enable - A boolean indicating whether the privilege is to be enabled
  534. or disabled. TRUE indicates the privilege is to be enabled.
  535. FALSE indicates the privilege is to be disabled.
  536. Client - A boolean indicating whether the privilege should be adjusted
  537. in a client token or the process's own token. TRUE indicates
  538. the client's token should be used (and an error returned if there
  539. is no client token). FALSE indicates the process's token should
  540. be used.
  541. WasEnabled - points to a boolean to receive an indication of whether
  542. the privilege was previously enabled or disabled. TRUE indicates
  543. the privilege was previously enabled. FALSE indicates the privilege
  544. was previoulsy disabled. This value is useful for returning the
  545. privilege to its original state after using it.
  546. Return Value:
  547. STATUS_SUCCESS - The privilege has been sucessfully enabled or disabled.
  548. STATUS_PRIVILEGE_NOT_HELD - The privilege is not held by the specified context.
  549. Other status values as may be returned by:
  550. NtOpenProcessToken()
  551. NtAdjustPrivilegesToken()
  552. --*/
  553. {
  554. NTSTATUS
  555. Status,
  556. TmpStatus;
  557. HANDLE
  558. Token;
  559. LUID
  560. LuidPrivilege;
  561. PTOKEN_PRIVILEGES
  562. NewPrivileges,
  563. OldPrivileges;
  564. ULONG
  565. Length;
  566. UCHAR
  567. Buffer1[sizeof(TOKEN_PRIVILEGES)+
  568. ((1-ANYSIZE_ARRAY)*sizeof(LUID_AND_ATTRIBUTES))],
  569. Buffer2[sizeof(TOKEN_PRIVILEGES)+
  570. ((1-ANYSIZE_ARRAY)*sizeof(LUID_AND_ATTRIBUTES))];
  571. RTL_PAGED_CODE();
  572. NewPrivileges = (PTOKEN_PRIVILEGES)Buffer1;
  573. OldPrivileges = (PTOKEN_PRIVILEGES)Buffer2;
  574. //
  575. // Open the appropriate token...
  576. //
  577. if (Client == TRUE) {
  578. Status = NtOpenThreadToken(
  579. NtCurrentThread(),
  580. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  581. FALSE,
  582. &Token
  583. );
  584. } else {
  585. Status = NtOpenProcessToken(
  586. NtCurrentProcess(),
  587. TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
  588. &Token
  589. );
  590. }
  591. if (!NT_SUCCESS(Status)) {
  592. return(Status);
  593. }
  594. //
  595. // Initialize the privilege adjustment structure
  596. //
  597. LuidPrivilege = RtlConvertUlongToLuid(Privilege);
  598. NewPrivileges->PrivilegeCount = 1;
  599. NewPrivileges->Privileges[0].Luid = LuidPrivilege;
  600. NewPrivileges->Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
  601. //
  602. // Adjust the privilege
  603. //
  604. Status = NtAdjustPrivilegesToken(
  605. Token, // TokenHandle
  606. FALSE, // DisableAllPrivileges
  607. NewPrivileges, // NewPrivileges
  608. sizeof(Buffer1), // BufferLength
  609. OldPrivileges, // PreviousState (OPTIONAL)
  610. &Length // ReturnLength
  611. );
  612. TmpStatus = NtClose(Token);
  613. ASSERT(NT_SUCCESS(TmpStatus));
  614. //
  615. // Map the success code NOT_ALL_ASSIGNED to an appropriate error
  616. // since we're only trying to adjust the one privilege.
  617. //
  618. if (Status == STATUS_NOT_ALL_ASSIGNED) {
  619. Status = STATUS_PRIVILEGE_NOT_HELD;
  620. }
  621. if (NT_SUCCESS(Status)) {
  622. //
  623. // If there are no privileges in the previous state, there were
  624. // no changes made. The previous state of the privilege
  625. // is whatever we tried to change it to.
  626. //
  627. if (OldPrivileges->PrivilegeCount == 0) {
  628. (*WasEnabled) = Enable;
  629. } else {
  630. (*WasEnabled) =
  631. (OldPrivileges->Privileges[0].Attributes & SE_PRIVILEGE_ENABLED)
  632. ? TRUE : FALSE;
  633. }
  634. }
  635. return(Status);
  636. }
  637. BOOLEAN
  638. RtlValidSid (
  639. IN PSID Sid
  640. )
  641. /*++
  642. Routine Description:
  643. This procedure validates an SID's structure.
  644. Arguments:
  645. Sid - Pointer to the SID structure to validate.
  646. Return Value:
  647. BOOLEAN - TRUE if the structure of Sid is valid.
  648. --*/
  649. {
  650. PISID Isid = (PISID) Sid;
  651. RTL_PAGED_CODE();
  652. //
  653. // Make sure revision is SID_REVISION and sub authority count is not
  654. // greater than maximum number of allowed sub-authorities.
  655. //
  656. try {
  657. if ( Isid != NULL && (Isid->Revision & 0x0f) == SID_REVISION) {
  658. if (Isid->SubAuthorityCount <= SID_MAX_SUB_AUTHORITIES) {
  659. //
  660. // Verify the memory actually contains the last subauthority
  661. //
  662. #ifndef NTOS_KERNEL_RUNTIME
  663. #define ProbeAndReadUlongUM(Address) \
  664. (*(volatile ULONG *)(Address))
  665. if (Isid->SubAuthorityCount > 0) {
  666. ProbeAndReadUlongUM(
  667. &Isid->SubAuthority[Isid->SubAuthorityCount-1]
  668. );
  669. }
  670. #endif // !NTOS_KERNEL_RUNTIME
  671. return TRUE;
  672. }
  673. }
  674. } except(EXCEPTION_EXECUTE_HANDLER) {
  675. return FALSE;
  676. }
  677. return FALSE;
  678. }
  679. BOOLEAN
  680. RtlEqualSid (
  681. IN PSID Sid1,
  682. IN PSID Sid2
  683. )
  684. /*++
  685. Routine Description:
  686. This procedure tests two SID values for equality.
  687. Arguments:
  688. Sid1, Sid2 - Supply pointers to the two SID values to compare.
  689. The SID structures are assumed to be valid.
  690. Return Value:
  691. BOOLEAN - TRUE if the value of Sid1 is equal to Sid2, and FALSE
  692. otherwise.
  693. --*/
  694. {
  695. ULONG SidLength;
  696. RTL_PAGED_CODE();
  697. //
  698. // Make sure they are the same revision
  699. //
  700. if ( ((SID *)Sid1)->Revision == ((SID *)Sid2)->Revision ) {
  701. //
  702. // Check the SubAuthorityCount first, because it's fast and
  703. // can help us exit faster.
  704. //
  705. if ( *RtlSubAuthorityCountSid( Sid1 ) == *RtlSubAuthorityCountSid( Sid2 )) {
  706. SidLength = SeLengthSid( Sid1 );
  707. return( (BOOLEAN)RtlEqualMemory( Sid1, Sid2, SidLength) );
  708. }
  709. }
  710. return( FALSE );
  711. }
  712. BOOLEAN
  713. RtlEqualPrefixSid (
  714. IN PSID Sid1,
  715. IN PSID Sid2
  716. )
  717. /*++
  718. Routine Description:
  719. This procedure tests two SID prefix values for equality.
  720. An SID prefix is the entire SID except for the last sub-authority
  721. value.
  722. Arguments:
  723. Sid1, Sid2 - Supply pointers to the two SID values to compare.
  724. The SID structures are assumed to be valid.
  725. Return Value:
  726. BOOLEAN - TRUE if the prefix value of Sid1 is equal to Sid2, and FALSE
  727. otherwise.
  728. --*/
  729. {
  730. LONG Index;
  731. //
  732. // Typecast to the opaque SID structures.
  733. //
  734. SID *ISid1 = Sid1;
  735. SID *ISid2 = Sid2;
  736. RTL_PAGED_CODE();
  737. //
  738. // Make sure they are the same revision
  739. //
  740. if (ISid1->Revision == ISid2->Revision ) {
  741. //
  742. // Compare IdentifierAuthority values
  743. //
  744. if ( (ISid1->IdentifierAuthority.Value[0] ==
  745. ISid2->IdentifierAuthority.Value[0]) &&
  746. (ISid1->IdentifierAuthority.Value[1]==
  747. ISid2->IdentifierAuthority.Value[1]) &&
  748. (ISid1->IdentifierAuthority.Value[2] ==
  749. ISid2->IdentifierAuthority.Value[2]) &&
  750. (ISid1->IdentifierAuthority.Value[3] ==
  751. ISid2->IdentifierAuthority.Value[3]) &&
  752. (ISid1->IdentifierAuthority.Value[4] ==
  753. ISid2->IdentifierAuthority.Value[4]) &&
  754. (ISid1->IdentifierAuthority.Value[5] ==
  755. ISid2->IdentifierAuthority.Value[5])
  756. ) {
  757. //
  758. // Compare SubAuthorityCount values
  759. //
  760. if (ISid1->SubAuthorityCount == ISid2->SubAuthorityCount) {
  761. if (ISid1->SubAuthorityCount == 0) {
  762. return TRUE;
  763. }
  764. Index = 0;
  765. while (Index < (ISid1->SubAuthorityCount - 1)) {
  766. if ((ISid1->SubAuthority[Index]) != (ISid2->SubAuthority[Index])) {
  767. //
  768. // Found some SubAuthority values that weren't equal.
  769. //
  770. return FALSE;
  771. }
  772. Index += 1;
  773. }
  774. //
  775. // All SubAuthority values are equal.
  776. //
  777. return TRUE;
  778. }
  779. }
  780. }
  781. //
  782. // Either the Revision, SubAuthorityCount, or IdentifierAuthority values
  783. // weren't equal.
  784. //
  785. return FALSE;
  786. }
  787. ULONG
  788. RtlLengthRequiredSid (
  789. IN ULONG SubAuthorityCount
  790. )
  791. /*++
  792. Routine Description:
  793. This routine returns the length, in bytes, required to store an SID
  794. with the specified number of Sub-Authorities.
  795. Arguments:
  796. SubAuthorityCount - The number of sub-authorities to be stored in the SID.
  797. Return Value:
  798. ULONG - The length, in bytes, required to store the SID.
  799. --*/
  800. {
  801. RTL_PAGED_CODE();
  802. return (8L + (4 * SubAuthorityCount));
  803. }
  804. #ifndef NTOS_KERNEL_RUNTIME
  805. NTSTATUS
  806. RtlAllocateAndInitializeSid(
  807. IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
  808. IN UCHAR SubAuthorityCount,
  809. IN ULONG SubAuthority0,
  810. IN ULONG SubAuthority1,
  811. IN ULONG SubAuthority2,
  812. IN ULONG SubAuthority3,
  813. IN ULONG SubAuthority4,
  814. IN ULONG SubAuthority5,
  815. IN ULONG SubAuthority6,
  816. IN ULONG SubAuthority7,
  817. OUT PSID *Sid
  818. )
  819. /*++
  820. Routine Description:
  821. This function allocates and initializes a sid with the specified
  822. number of sub-authorities (up to 8). A sid allocated with this
  823. routine must be freed using RtlFreeSid().
  824. THIS ROUTINE IS CURRENTLY NOT CALLABLE FROM KERNEL MODE.
  825. Arguments:
  826. IdentifierAuthority - Pointer to the Identifier Authority value to
  827. set in the SID.
  828. SubAuthorityCount - The number of sub-authorities to place in the SID.
  829. This also identifies how many of the SubAuthorityN parameters
  830. have meaningful values. This must contain a value from 0 through
  831. 8.
  832. SubAuthority0-7 - Provides the corresponding sub-authority value to
  833. place in the SID. For example, a SubAuthorityCount value of 3
  834. indicates that SubAuthority0, SubAuthority1, and SubAuthority0
  835. have meaningful values and the rest are to be ignored.
  836. Sid - Receives a pointer to the SID data structure to initialize.
  837. Return Value:
  838. STATUS_SUCCESS - The SID has been allocated and initialized.
  839. STATUS_NO_MEMORY - The attempt to allocate memory for the SID
  840. failed.
  841. STATUS_INVALID_SID - The number of sub-authorities specified did
  842. not fall in the valid range for this api (0 through 8).
  843. --*/
  844. {
  845. PISID ISid;
  846. RTL_PAGED_CODE();
  847. if ( SubAuthorityCount > 8 ) {
  848. return( STATUS_INVALID_SID );
  849. }
  850. ISid = RtlAllocateHeap( RtlProcessHeap(), 0,
  851. RtlLengthRequiredSid(SubAuthorityCount)
  852. );
  853. if (ISid == NULL) {
  854. return(STATUS_NO_MEMORY);
  855. }
  856. ISid->SubAuthorityCount = (UCHAR)SubAuthorityCount;
  857. ISid->Revision = 1;
  858. ISid->IdentifierAuthority = *IdentifierAuthority;
  859. switch (SubAuthorityCount) {
  860. case 8:
  861. ISid->SubAuthority[7] = SubAuthority7;
  862. case 7:
  863. ISid->SubAuthority[6] = SubAuthority6;
  864. case 6:
  865. ISid->SubAuthority[5] = SubAuthority5;
  866. case 5:
  867. ISid->SubAuthority[4] = SubAuthority4;
  868. case 4:
  869. ISid->SubAuthority[3] = SubAuthority3;
  870. case 3:
  871. ISid->SubAuthority[2] = SubAuthority2;
  872. case 2:
  873. ISid->SubAuthority[1] = SubAuthority1;
  874. case 1:
  875. ISid->SubAuthority[0] = SubAuthority0;
  876. case 0:
  877. ;
  878. }
  879. (*Sid) = ISid;
  880. return( STATUS_SUCCESS );
  881. }
  882. #endif // NTOS_KERNEL_RUNTIME
  883. NTSTATUS
  884. RtlInitializeSid(
  885. IN PSID Sid,
  886. IN PSID_IDENTIFIER_AUTHORITY IdentifierAuthority,
  887. IN UCHAR SubAuthorityCount
  888. )
  889. /*++
  890. Routine Description:
  891. This function initializes an SID data structure. It does not, however,
  892. set the sub-authority values. This must be done separately.
  893. Arguments:
  894. Sid - Pointer to the SID data structure to initialize.
  895. IdentifierAuthority - Pointer to the Identifier Authority value to
  896. set in the SID.
  897. SubAuthorityCount - The number of sub-authorities that will be placed in
  898. the SID (a separate action).
  899. Return Value:
  900. --*/
  901. {
  902. PISID ISid;
  903. RTL_PAGED_CODE();
  904. //
  905. // Typecast to the opaque SID
  906. //
  907. ISid = (PISID)Sid;
  908. if ( SubAuthorityCount > SID_MAX_SUB_AUTHORITIES ) {
  909. return( STATUS_INVALID_PARAMETER );
  910. }
  911. ISid->SubAuthorityCount = (UCHAR)SubAuthorityCount;
  912. ISid->Revision = 1;
  913. ISid->IdentifierAuthority = *IdentifierAuthority;
  914. return( STATUS_SUCCESS );
  915. }
  916. #ifndef NTOS_KERNEL_RUNTIME
  917. PVOID
  918. RtlFreeSid(
  919. IN PSID Sid
  920. )
  921. /*++
  922. Routine Description:
  923. This function is used to free a SID previously allocated using
  924. RtlAllocateAndInitializeSid().
  925. THIS ROUTINE IS CURRENTLY NOT CALLABLE FROM KERNEL MODE.
  926. Arguments:
  927. Sid - Pointer to the SID to free.
  928. Return Value:
  929. None.
  930. --*/
  931. {
  932. RTL_PAGED_CODE();
  933. if (RtlFreeHeap( RtlProcessHeap(), 0, Sid ))
  934. return NULL;
  935. else
  936. return Sid;
  937. }
  938. #endif // NTOS_KERNEL_RUNTIME
  939. PSID_IDENTIFIER_AUTHORITY
  940. RtlIdentifierAuthoritySid(
  941. IN PSID Sid
  942. )
  943. /*++
  944. Routine Description:
  945. This function returns the address of an SID's IdentifierAuthority field.
  946. Arguments:
  947. Sid - Pointer to the SID data structure.
  948. Return Value:
  949. --*/
  950. {
  951. PISID ISid;
  952. RTL_PAGED_CODE();
  953. //
  954. // Typecast to the opaque SID
  955. //
  956. ISid = (PISID)Sid;
  957. return &(ISid->IdentifierAuthority);
  958. }
  959. PULONG
  960. RtlSubAuthoritySid(
  961. IN PSID Sid,
  962. IN ULONG SubAuthority
  963. )
  964. /*++
  965. Routine Description:
  966. This function returns the address of a sub-authority array element of
  967. an SID.
  968. Arguments:
  969. Sid - Pointer to the SID data structure.
  970. SubAuthority - An index indicating which sub-authority is being specified.
  971. This value is not compared against the number of sub-authorities in the
  972. SID for validity.
  973. Return Value:
  974. --*/
  975. {
  976. RTL_PAGED_CODE();
  977. return RtlpSubAuthoritySid( Sid, SubAuthority );
  978. }
  979. PUCHAR
  980. RtlSubAuthorityCountSid(
  981. IN PSID Sid
  982. )
  983. /*++
  984. Routine Description:
  985. This function returns the address of the sub-authority count field of
  986. an SID.
  987. Arguments:
  988. Sid - Pointer to the SID data structure.
  989. Return Value:
  990. --*/
  991. {
  992. PISID ISid;
  993. RTL_PAGED_CODE();
  994. //
  995. // Typecast to the opaque SID
  996. //
  997. ISid = (PISID)Sid;
  998. return &(ISid->SubAuthorityCount);
  999. }
  1000. ULONG
  1001. RtlLengthSid (
  1002. IN PSID Sid
  1003. )
  1004. /*++
  1005. Routine Description:
  1006. This routine returns the length, in bytes, of a structurally valid SID.
  1007. Arguments:
  1008. Sid - Points to the SID whose length is to be returned. The
  1009. SID's structure is assumed to be valid.
  1010. Return Value:
  1011. ULONG - The length, in bytes, of the SID.
  1012. --*/
  1013. {
  1014. RTL_PAGED_CODE();
  1015. return SeLengthSid(Sid);
  1016. }
  1017. NTSTATUS
  1018. RtlCopySid (
  1019. IN ULONG DestinationSidLength,
  1020. OUT PSID DestinationSid,
  1021. IN PSID SourceSid
  1022. )
  1023. /*++
  1024. Routine Description:
  1025. This routine copies the value of the source SID to the destination
  1026. SID.
  1027. Arguments:
  1028. DestinationSidLength - Indicates the length, in bytes, of the
  1029. destination SID buffer.
  1030. DestinationSid - Pointer to a buffer to receive a copy of the
  1031. source Sid value.
  1032. SourceSid - Supplies the Sid value to be copied.
  1033. Return Value:
  1034. STATUS_SUCCESS - Indicates the SID was successfully copied.
  1035. STATUS_BUFFER_TOO_SMALL - Indicates the target buffer wasn't
  1036. large enough to receive a copy of the SID.
  1037. --*/
  1038. {
  1039. ULONG SidLength = SeLengthSid(SourceSid);
  1040. RTL_PAGED_CODE();
  1041. if (SidLength > DestinationSidLength) {
  1042. return STATUS_BUFFER_TOO_SMALL;
  1043. }
  1044. //
  1045. // Buffer is large enough
  1046. //
  1047. RtlMoveMemory( DestinationSid, SourceSid, SidLength );
  1048. return STATUS_SUCCESS;
  1049. }
  1050. NTSTATUS
  1051. RtlCopySidAndAttributesArray (
  1052. IN ULONG ArrayLength,
  1053. IN PSID_AND_ATTRIBUTES Source,
  1054. IN ULONG TargetSidBufferSize,
  1055. OUT PSID_AND_ATTRIBUTES TargetArrayElement,
  1056. OUT PSID TargetSid,
  1057. OUT PSID *NextTargetSid,
  1058. OUT PULONG RemainingTargetSidBufferSize
  1059. )
  1060. /*++
  1061. Routine Description:
  1062. This routine copies the value of the source SID_AND_ATTRIBUTES array
  1063. to the target. The actual SID values are placed according to a separate
  1064. parameter. This allows multiple arrays to be merged using this service
  1065. to copy each.
  1066. Arguments:
  1067. ArrayLength - Number of elements in the source array to copy.
  1068. Source - Pointer to the source array.
  1069. TargetSidBufferSize - Indicates the length, in bytes, of the buffer
  1070. to receive the actual SID values. If this value is less than
  1071. the actual amount needed, then STATUS_BUFFER_TOO_SMALL is returned.
  1072. TargetArrayElement - Indicates where the array elements are to be
  1073. copied to (but not the SID values themselves).
  1074. TargetSid - Indicates where the target SID values s are to be copied. This
  1075. is assumed to be ULONG aligned. Each SID value will be copied
  1076. into this buffer. Each SID will be ULONG aligned.
  1077. NextTargetSid - On completion, will be set to point to the ULONG
  1078. aligned address following the last SID copied.
  1079. RemainingTargetSidBufferSize - On completion, receives an indicatation
  1080. of how much of the SID buffer is still unused.
  1081. Return Value:
  1082. STATUS_SUCCESS - The call completed successfully.
  1083. STATUS_BUFFER_TOO_SMALL - Indicates the buffer to receive the SID
  1084. values wasn't large enough.
  1085. --*/
  1086. {
  1087. ULONG Index = 0;
  1088. PSID NextSid = TargetSid;
  1089. ULONG NextSidLength;
  1090. ULONG AlignedSidLength;
  1091. ULONG RemainingLength = TargetSidBufferSize;
  1092. RTL_PAGED_CODE();
  1093. while (Index < ArrayLength) {
  1094. NextSidLength = SeLengthSid( Source[Index].Sid );
  1095. AlignedSidLength = PtrToUlong(LongAlign(NextSidLength));
  1096. if (NextSidLength > RemainingLength) {
  1097. return STATUS_BUFFER_TOO_SMALL;
  1098. }
  1099. RemainingLength -= AlignedSidLength;
  1100. TargetArrayElement[Index].Sid = NextSid;
  1101. TargetArrayElement[Index].Attributes = Source[Index].Attributes;
  1102. RtlCopySid( NextSidLength, NextSid, Source[Index].Sid );
  1103. NextSid = (PSID)((PCHAR)NextSid + AlignedSidLength);
  1104. Index += 1;
  1105. } //end_while
  1106. (*NextTargetSid) = NextSid;
  1107. (*RemainingTargetSidBufferSize) = RemainingLength;
  1108. return STATUS_SUCCESS;
  1109. }
  1110. NTSTATUS
  1111. RtlLengthSidAsUnicodeString(
  1112. PSID Sid,
  1113. PULONG StringLength
  1114. )
  1115. /*++
  1116. Routine Description:
  1117. This function returns the maximum length of the string needed
  1118. to represent the SID supplied. The actual string may be shorter,
  1119. but this is intended to be a quick calculation.
  1120. Arguments:
  1121. Sid - Supplies the SID that is to be converted to unicode.
  1122. StringLength - Receives the max length required in bytes.
  1123. Return Value:
  1124. SUCCESS - The conversion was successful
  1125. STATUS_INVALID_SID - The sid provided does not have a valid structure,
  1126. or has too many sub-authorities (more than SID_MAX_SUB_AUTHORITIES).
  1127. --*/
  1128. {
  1129. ULONG i ;
  1130. PISID iSid = (PISID)Sid; // pointer to opaque structure
  1131. RTL_PAGED_CODE();
  1132. if ( RtlValidSid( Sid ) != TRUE)
  1133. {
  1134. return(STATUS_INVALID_SID);
  1135. }
  1136. //
  1137. // if the SID's IA value has 5 or 6 significant bytes, the
  1138. // representation will be in hex, with a 0x preceding. Otherwise
  1139. // it will be in decimal, with at most 10 characters.
  1140. //
  1141. if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
  1142. (iSid->IdentifierAuthority.Value[1] != 0) )
  1143. {
  1144. i = 14 ; // 0x665544332211
  1145. }
  1146. else
  1147. {
  1148. i = 10 ; // 4294967295 is the max ulong, at 10 chars
  1149. }
  1150. i += 4 ; // room for the S-1-
  1151. //
  1152. // for each sub authority, it is a max of 10 chars (for a ulong),
  1153. // plus the - separator
  1154. //
  1155. i += 11 * iSid->SubAuthorityCount ;
  1156. *StringLength = i * sizeof( WCHAR );
  1157. return STATUS_SUCCESS ;
  1158. }
  1159. NTSTATUS
  1160. RtlConvertSidToUnicodeString(
  1161. PUNICODE_STRING UnicodeString,
  1162. PSID Sid,
  1163. BOOLEAN AllocateDestinationString
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. This function generates a printable unicode string representation
  1168. of a SID.
  1169. The resulting string will take one of two forms. If the
  1170. IdentifierAuthority value is not greater than 2^32, then
  1171. the SID will be in the form:
  1172. S-1-281736-12-72-9-110
  1173. ^ ^^ ^^ ^ ^^^
  1174. | | | | |
  1175. +-----+--+-+--+---- Decimal
  1176. Otherwise it will take the form:
  1177. S-1-0x173495281736-12-72-9-110
  1178. ^^^^^^^^^^^^^^ ^^ ^^ ^ ^^^
  1179. Hexidecimal | | | |
  1180. +--+-+--+---- Decimal
  1181. Arguments:
  1182. UnicodeString - Returns a unicode string that is equivalent to
  1183. the SID. The maximum length field is only set if
  1184. AllocateDestinationString is TRUE.
  1185. Sid - Supplies the SID that is to be converted to unicode.
  1186. AllocateDestinationString - Supplies a flag that controls whether or
  1187. not this API allocates the buffer space for the destination
  1188. string. If it does, then the buffer must be deallocated using
  1189. RtlFreeUnicodeString (note that only storage for
  1190. DestinationString->Buffer is allocated by this API).
  1191. Return Value:
  1192. SUCCESS - The conversion was successful
  1193. STATUS_INVALID_SID - The sid provided does not have a valid structure,
  1194. or has too many sub-authorities (more than SID_MAX_SUB_AUTHORITIES).
  1195. STATUS_NO_MEMORY - There was not sufficient memory to allocate the
  1196. target string. This is returned only if AllocateDestinationString
  1197. is specified as TRUE.
  1198. STATUS_BUFFER_OVERFLOW - This is returned only if
  1199. AllocateDestinationString is specified as FALSE.
  1200. --*/
  1201. {
  1202. NTSTATUS Status;
  1203. WCHAR UniBuffer[ 256 ];
  1204. PWSTR Offset ;
  1205. UNICODE_STRING LocalString ;
  1206. UCHAR i;
  1207. ULONG Tmp;
  1208. LARGE_INTEGER Auth ;
  1209. PISID iSid = (PISID)Sid; // pointer to opaque structure
  1210. RTL_PAGED_CODE();
  1211. if (RtlValidSid( Sid ) != TRUE) {
  1212. return(STATUS_INVALID_SID);
  1213. }
  1214. if ( iSid->Revision != SID_REVISION )
  1215. {
  1216. return STATUS_INVALID_SID ;
  1217. }
  1218. wcscpy( UniBuffer, L"S-1-" );
  1219. Offset = &UniBuffer[ 4 ];
  1220. if ( (iSid->IdentifierAuthority.Value[0] != 0) ||
  1221. (iSid->IdentifierAuthority.Value[1] != 0) ){
  1222. //
  1223. // Ugly hex dump.
  1224. //
  1225. Auth.HighPart = (LONG) (iSid->IdentifierAuthority.Value[ 0 ] << 8) +
  1226. (LONG) iSid->IdentifierAuthority.Value[ 1 ] ;
  1227. Auth.LowPart = (ULONG)iSid->IdentifierAuthority.Value[5] +
  1228. (ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
  1229. (ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
  1230. (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
  1231. Status = RtlLargeIntegerToUnicode(
  1232. &Auth,
  1233. 16,
  1234. 256 - (LONG) (Offset - UniBuffer),
  1235. Offset );
  1236. } else {
  1237. Tmp = (ULONG)iSid->IdentifierAuthority.Value[5] +
  1238. (ULONG)(iSid->IdentifierAuthority.Value[4] << 8) +
  1239. (ULONG)(iSid->IdentifierAuthority.Value[3] << 16) +
  1240. (ULONG)(iSid->IdentifierAuthority.Value[2] << 24);
  1241. Status = RtlIntegerToUnicode(
  1242. Tmp,
  1243. 10,
  1244. 256 - (LONG) (Offset - UniBuffer),
  1245. Offset );
  1246. }
  1247. if ( !NT_SUCCESS( Status ) )
  1248. {
  1249. return Status ;
  1250. }
  1251. for (i=0;i<iSid->SubAuthorityCount ;i++ ) {
  1252. while ( *Offset && ( Offset < &UniBuffer[ 255 ] ) )
  1253. {
  1254. Offset++ ;
  1255. }
  1256. *Offset++ = L'-' ;
  1257. Status = RtlIntegerToUnicode(
  1258. iSid->SubAuthority[ i ],
  1259. 10,
  1260. 256 - (LONG) (Offset - UniBuffer),
  1261. Offset );
  1262. if ( !NT_SUCCESS( Status ) )
  1263. {
  1264. return Status ;
  1265. }
  1266. }
  1267. if ( AllocateDestinationString )
  1268. {
  1269. if ( RtlCreateUnicodeString( UnicodeString,
  1270. UniBuffer ) )
  1271. {
  1272. Status = STATUS_SUCCESS ;
  1273. }
  1274. else
  1275. {
  1276. Status = STATUS_NO_MEMORY ;
  1277. }
  1278. }
  1279. else
  1280. {
  1281. while ( *Offset && ( Offset < &UniBuffer[ 255 ] ) )
  1282. {
  1283. Offset++ ;
  1284. }
  1285. Tmp = (ULONG) (Offset - UniBuffer) * sizeof( WCHAR );
  1286. if ( Tmp < UnicodeString->MaximumLength )
  1287. {
  1288. LocalString.Length = (USHORT) Tmp ;
  1289. LocalString.MaximumLength = LocalString.Length + sizeof( WCHAR );
  1290. LocalString.Buffer = UniBuffer ;
  1291. RtlCopyUnicodeString(
  1292. UnicodeString,
  1293. &LocalString );
  1294. Status = STATUS_SUCCESS ;
  1295. }
  1296. else
  1297. {
  1298. Status = STATUS_BUFFER_OVERFLOW ;
  1299. }
  1300. }
  1301. return(Status);
  1302. }
  1303. BOOLEAN
  1304. RtlEqualLuid (
  1305. IN PLUID Luid1,
  1306. IN PLUID Luid2
  1307. )
  1308. /*++
  1309. Routine Description:
  1310. This procedure test two LUID values for equality.
  1311. This routine is here for backwards compatibility only. New code
  1312. should use the macro.
  1313. Arguments:
  1314. Luid1, Luid2 - Supply pointers to the two LUID values to compare.
  1315. Return Value:
  1316. BOOLEAN - TRUE if the value of Luid1 is equal to Luid2, and FALSE
  1317. otherwise.
  1318. --*/
  1319. {
  1320. LUID UNALIGNED * TempLuid1;
  1321. LUID UNALIGNED * TempLuid2;
  1322. RTL_PAGED_CODE();
  1323. return((Luid1->HighPart == Luid2->HighPart) &&
  1324. (Luid1->LowPart == Luid2->LowPart));
  1325. }
  1326. VOID
  1327. RtlCopyLuid (
  1328. OUT PLUID DestinationLuid,
  1329. IN PLUID SourceLuid
  1330. )
  1331. /*++
  1332. Routine Description:
  1333. This routine copies the value of the source LUID to the
  1334. destination LUID.
  1335. Arguments:
  1336. DestinationLuid - Receives a copy of the source Luid value.
  1337. SourceLuid - Supplies the Luid value to be copied. This LUID is
  1338. assumed to be structurally valid.
  1339. Return Value:
  1340. None.
  1341. --*/
  1342. {
  1343. RTL_PAGED_CODE();
  1344. (*DestinationLuid) = (*SourceLuid);
  1345. return;
  1346. }
  1347. VOID
  1348. RtlCopyLuidAndAttributesArray (
  1349. IN ULONG ArrayLength,
  1350. IN PLUID_AND_ATTRIBUTES Source,
  1351. OUT PLUID_AND_ATTRIBUTES Target
  1352. )
  1353. /*++
  1354. Routine Description:
  1355. This routine copies the value of the source LUID_AND_ATTRIBUTES array
  1356. to the target.
  1357. Arguments:
  1358. ArrayLength - Number of elements in the source array to copy.
  1359. Source - The source array.
  1360. Target - Indicates where the array elements are to be copied to.
  1361. Return Value:
  1362. None.
  1363. --*/
  1364. {
  1365. ULONG Index = 0;
  1366. RTL_PAGED_CODE();
  1367. while (Index < ArrayLength) {
  1368. Target[Index] = Source[Index];
  1369. Index += 1;
  1370. } //end_while
  1371. return;
  1372. }
  1373. NTSTATUS
  1374. RtlCreateSecurityDescriptor (
  1375. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1376. IN ULONG Revision
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. This procedure initializes a new "absolute format" security descriptor.
  1381. After the procedure call the security descriptor is initialized with no
  1382. system ACL, no discretionary ACL, no owner, no primary group and
  1383. all control flags set to false (null).
  1384. Arguments:
  1385. SecurityDescriptor - Supplies the security descriptor to
  1386. initialize.
  1387. Revision - Provides the revision level to assign to the security
  1388. descriptor. This should be one (1) for this release.
  1389. Return Value:
  1390. STATUS_SUCCESS - Indicates the call completed successfully.
  1391. STATUS_UNKNOWN_REVISION - Indicates the revision level provided
  1392. is not supported by this routine.
  1393. --*/
  1394. {
  1395. RTL_PAGED_CODE();
  1396. //
  1397. // Check the requested revision
  1398. //
  1399. if (Revision == SECURITY_DESCRIPTOR_REVISION) {
  1400. //
  1401. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  1402. //
  1403. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  1404. RtlZeroMemory( ISecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  1405. ISecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
  1406. return STATUS_SUCCESS;
  1407. }
  1408. return STATUS_UNKNOWN_REVISION;
  1409. }
  1410. NTSTATUS
  1411. RtlCreateSecurityDescriptorRelative (
  1412. IN PISECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor,
  1413. IN ULONG Revision
  1414. )
  1415. /*++
  1416. Routine Description:
  1417. This procedure initializes a new "relative format" security descriptor.
  1418. After the procedure call the security descriptor is initialized with no
  1419. system ACL, no discretionary ACL, no owner, no primary group and
  1420. all control flags set to false (null).
  1421. Arguments:
  1422. SecurityDescriptor - Supplies the security descriptor to
  1423. initialize.
  1424. Revision - Provides the revision level to assign to the security
  1425. descriptor. This should be one (1) for this release.
  1426. Return Value:
  1427. STATUS_SUCCESS - Indicates the call completed successfully.
  1428. STATUS_UNKNOWN_REVISION - Indicates the revision level provided
  1429. is not supported by this routine.
  1430. Note:
  1431. Warning, this code assume the caller allocated a relative security
  1432. descriptor rather than a relative one. Absolute is larger on systems
  1433. with 64-bit pointers.
  1434. --*/
  1435. {
  1436. RTL_PAGED_CODE();
  1437. //
  1438. // Check the requested revision
  1439. //
  1440. if (Revision == SECURITY_DESCRIPTOR_REVISION) {
  1441. //
  1442. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  1443. //
  1444. RtlZeroMemory( SecurityDescriptor, sizeof(SECURITY_DESCRIPTOR_RELATIVE));
  1445. SecurityDescriptor->Revision = SECURITY_DESCRIPTOR_REVISION;
  1446. return STATUS_SUCCESS;
  1447. }
  1448. return STATUS_UNKNOWN_REVISION;
  1449. }
  1450. BOOLEAN
  1451. RtlValidSecurityDescriptor (
  1452. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  1453. )
  1454. /*++
  1455. Routine Description:
  1456. This procedure validates a SecurityDescriptor's structure. This
  1457. involves validating the revision levels of each component of the
  1458. security descriptor.
  1459. Arguments:
  1460. SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
  1461. to validate.
  1462. Return Value:
  1463. BOOLEAN - TRUE if the structure of SecurityDescriptor is valid.
  1464. --*/
  1465. {
  1466. PSID Owner;
  1467. PSID Group;
  1468. PACL Dacl;
  1469. PACL Sacl;
  1470. //
  1471. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  1472. //
  1473. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  1474. RTL_PAGED_CODE();
  1475. try {
  1476. //
  1477. // known revision ?
  1478. //
  1479. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  1480. return FALSE;
  1481. }
  1482. //
  1483. // Validate each element contained in the security descriptor
  1484. //
  1485. Owner = RtlpOwnerAddrSecurityDescriptor( ISecurityDescriptor );
  1486. if (Owner != NULL) {
  1487. if (!RtlValidSid( Owner )) {
  1488. return FALSE;
  1489. }
  1490. }
  1491. Group = RtlpGroupAddrSecurityDescriptor( ISecurityDescriptor );
  1492. if (Group != NULL) {
  1493. if (!RtlValidSid( Group )) {
  1494. return FALSE;
  1495. }
  1496. }
  1497. Dacl = RtlpDaclAddrSecurityDescriptor( ISecurityDescriptor );
  1498. if (Dacl != NULL ) {
  1499. if (!RtlValidAcl( Dacl )) {
  1500. return FALSE;
  1501. }
  1502. }
  1503. Sacl = RtlpSaclAddrSecurityDescriptor( ISecurityDescriptor );
  1504. if ( Sacl != NULL ) {
  1505. if (!RtlValidAcl( Sacl )) {
  1506. return FALSE;
  1507. }
  1508. }
  1509. } except(EXCEPTION_EXECUTE_HANDLER) {
  1510. return FALSE;
  1511. }
  1512. //
  1513. // All components are valid
  1514. //
  1515. return TRUE;
  1516. }
  1517. ULONG
  1518. RtlLengthSecurityDescriptor (
  1519. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  1520. )
  1521. /*++
  1522. Routine Description:
  1523. This routine returns the length, in bytes, necessary to capture a
  1524. structurally valid SECURITY_DESCRIPTOR. The length includes the length
  1525. of all associated data structures (like SIDs and ACLs). The length also
  1526. takes into account the alignment requirements of each component.
  1527. The minimum length of a security descriptor (one which has no associated
  1528. SIDs or ACLs) is SECURITY_DESCRIPTOR_MIN_LENGTH.
  1529. Arguments:
  1530. SecurityDescriptor - Points to the SECURITY_DESCRIPTOR whose
  1531. length is to be returned. The SECURITY_DESCRIPTOR's
  1532. structure is assumed to be valid.
  1533. Return Value:
  1534. ULONG - The length, in bytes, of the SECURITY_DESCRIPTOR.
  1535. --*/
  1536. {
  1537. ULONG sum;
  1538. PVOID Temp;
  1539. //
  1540. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  1541. //
  1542. SECURITY_DESCRIPTOR *ISecurityDescriptor = (SECURITY_DESCRIPTOR *)SecurityDescriptor;
  1543. RTL_PAGED_CODE();
  1544. //
  1545. // The length is the sum of the following:
  1546. //
  1547. // SECURITY_DESCRIPTOR_MIN_LENGTH (or sizeof(SECURITY_DESCRIPTOR))
  1548. // length of Owner SID (if present)
  1549. // length of Group SID (if present)
  1550. // length of Discretionary ACL (if present and non-null)
  1551. // length of System ACL (if present and non-null)
  1552. //
  1553. sum = ISecurityDescriptor->Control & SE_SELF_RELATIVE ?
  1554. sizeof(SECURITY_DESCRIPTOR_RELATIVE) :
  1555. sizeof(SECURITY_DESCRIPTOR);
  1556. //
  1557. // Add in length of Owner SID
  1558. //
  1559. Temp = RtlpOwnerAddrSecurityDescriptor(ISecurityDescriptor);
  1560. if (Temp != NULL) {
  1561. sum += LongAlignSize(SeLengthSid(Temp));
  1562. }
  1563. //
  1564. // Add in length of Group SID
  1565. //
  1566. Temp = RtlpGroupAddrSecurityDescriptor(ISecurityDescriptor);
  1567. if (Temp != NULL) {
  1568. sum += LongAlignSize(SeLengthSid(Temp));
  1569. }
  1570. //
  1571. // Add in used length of Discretionary ACL
  1572. //
  1573. Temp = RtlpDaclAddrSecurityDescriptor(ISecurityDescriptor);
  1574. if ( Temp != NULL ) {
  1575. sum += LongAlignSize(((PACL) Temp)->AclSize );
  1576. }
  1577. //
  1578. // Add in used length of System Acl
  1579. //
  1580. Temp = RtlpSaclAddrSecurityDescriptor(ISecurityDescriptor);
  1581. if ( Temp != NULL ) {
  1582. sum += LongAlignSize(((PACL) Temp)->AclSize );
  1583. }
  1584. return sum;
  1585. }
  1586. NTSTATUS
  1587. RtlSetAttributesSecurityDescriptor(
  1588. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1589. IN SECURITY_DESCRIPTOR_CONTROL Control,
  1590. OUT PULONG Revision
  1591. )
  1592. {
  1593. RTL_PAGED_CODE();
  1594. //
  1595. // Always return the revision value - even if this isn't a valid
  1596. // security descriptor
  1597. //
  1598. *Revision = ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision;
  1599. if ( ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision
  1600. != SECURITY_DESCRIPTOR_REVISION ) {
  1601. return STATUS_UNKNOWN_REVISION;
  1602. }
  1603. // This is a worthless API. There is no way to turn any of the bits off.
  1604. // Use the newer RtlSetControlSecurityDescriptor.
  1605. Control &= SE_VALID_CONTROL_BITS;
  1606. return RtlSetControlSecurityDescriptor ( SecurityDescriptor, Control, Control );
  1607. }
  1608. NTSTATUS
  1609. RtlGetControlSecurityDescriptor (
  1610. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1611. OUT PSECURITY_DESCRIPTOR_CONTROL Control,
  1612. OUT PULONG Revision
  1613. )
  1614. /*++
  1615. Routine Description:
  1616. This procedure retrieves the control information from a security descriptor.
  1617. Arguments:
  1618. SecurityDescriptor - Supplies the security descriptor.
  1619. Control - Receives the control information.
  1620. Revision - Receives the revision of the security descriptor.
  1621. This value will always be returned, even if an error
  1622. is returned by this routine.
  1623. Return Value:
  1624. STATUS_SUCCESS - Indicates the call completed successfully.
  1625. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  1626. descriptor is not known to the routine. It may be a newer
  1627. revision than the routine knows about.
  1628. --*/
  1629. {
  1630. RTL_PAGED_CODE();
  1631. //
  1632. // Always return the revision value - even if this isn't a valid
  1633. // security descriptor
  1634. //
  1635. *Revision = ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision;
  1636. if ( ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Revision
  1637. != SECURITY_DESCRIPTOR_REVISION ) {
  1638. return STATUS_UNKNOWN_REVISION;
  1639. }
  1640. *Control = ((SECURITY_DESCRIPTOR *)SecurityDescriptor)->Control;
  1641. return STATUS_SUCCESS;
  1642. }
  1643. NTSTATUS
  1644. RtlSetControlSecurityDescriptor (
  1645. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1646. IN SECURITY_DESCRIPTOR_CONTROL ControlBitsOfInterest,
  1647. IN SECURITY_DESCRIPTOR_CONTROL ControlBitsToSet
  1648. )
  1649. /*++
  1650. Routine Description:
  1651. This procedure sets the control information in a security descriptor.
  1652. For instance,
  1653. SetSecurityDescriptorControl( &SecDesc,
  1654. SE_DACL_PROTECTED,
  1655. SE_DACL_PROTECTED );
  1656. marks the DACL on the security descriptor as protected. And
  1657. SetSecurityDescriptorControl( &SecDesc,
  1658. SE_DACL_PROTECTED,
  1659. 0 );
  1660. marks the DACL as not protected.
  1661. Arguments:
  1662. pSecurityDescriptor - Supplies the security descriptor.
  1663. ControlBitsOfInterest - A mask of the control bits being changed, set,
  1664. or reset by this call. The mask is the logical OR of one or more of
  1665. the following flags:
  1666. SE_DACL_UNTRUSTED
  1667. SE_SERVER_SECURITY
  1668. SE_DACL_AUTO_INHERIT_REQ
  1669. SE_SACL_AUTO_INHERIT_REQ
  1670. SE_DACL_AUTO_INHERITED
  1671. SE_SACL_AUTO_INHERITED
  1672. SE_DACL_PROTECTED
  1673. SE_SACL_PROTECTED
  1674. ControlBitsToSet - A mask indicating what the bits specified by ControlBitsOfInterest
  1675. should be set to.
  1676. Return Value:
  1677. Returns TRUE for success, FALSE for failure. Extended error status
  1678. is available using GetLastError.
  1679. --*/
  1680. {
  1681. //
  1682. // Ensure the caller passed valid bits.
  1683. //
  1684. if ( (ControlBitsOfInterest & ~SE_VALID_CONTROL_BITS) != 0 ||
  1685. (ControlBitsToSet & ~ControlBitsOfInterest) != 0 ) {
  1686. return STATUS_INVALID_PARAMETER;
  1687. }
  1688. ((SECURITY_DESCRIPTOR *)pSecurityDescriptor)->Control &= ~ControlBitsOfInterest;
  1689. ((SECURITY_DESCRIPTOR *)pSecurityDescriptor)->Control |= ControlBitsToSet;
  1690. return STATUS_SUCCESS;
  1691. }
  1692. NTSTATUS
  1693. RtlSetDaclSecurityDescriptor (
  1694. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1695. IN BOOLEAN DaclPresent,
  1696. IN PACL Dacl OPTIONAL,
  1697. IN BOOLEAN DaclDefaulted OPTIONAL
  1698. )
  1699. /*++
  1700. Routine Description:
  1701. This procedure sets the discretionary ACL information of an absolute
  1702. format security descriptor. If there is already a discretionary ACL
  1703. present in the security descriptor, it is superseded.
  1704. Arguments:
  1705. SecurityDescriptor - Supplies the security descriptor to be which
  1706. the discretionary ACL is to be added.
  1707. DaclPresent - If FALSE, indicates the DaclPresent flag in the
  1708. security descriptor should be set to FALSE. In this case,
  1709. the remaining optional parameters are ignored. Otherwise,
  1710. the DaclPresent control flag in the security descriptor is
  1711. set to TRUE and the remaining optional parameters are not
  1712. ignored.
  1713. Dacl - Supplies the discretionary ACL for the security
  1714. descriptor. If this optional parameter is not passed, then a
  1715. null ACL is assigned to the security descriptor. A null
  1716. discretionary ACL unconditionally grants access. The ACL is
  1717. referenced by, not copied into, by the security descriptor.
  1718. DaclDefaulted - When set, indicates the discretionary ACL was
  1719. picked up from some default mechanism (rather than explicitly
  1720. specified by a user). This value is set in the DaclDefaulted
  1721. control flag in the security descriptor. If this optional
  1722. parameter is not passed, then the DaclDefaulted flag will be
  1723. cleared.
  1724. Return Value:
  1725. STATUS_SUCCESS - Indicates the call completed successfully.
  1726. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  1727. descriptor is not known to the routine. It may be a newer
  1728. revision than the routine knows about.
  1729. STATUS_INVALID_SECURITY_DESCR - Indicates the security descriptor
  1730. is not an absolute format security descriptor.
  1731. --*/
  1732. {
  1733. //
  1734. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  1735. //
  1736. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  1737. RTL_PAGED_CODE();
  1738. //
  1739. // Check the revision
  1740. //
  1741. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  1742. return STATUS_UNKNOWN_REVISION;
  1743. }
  1744. //
  1745. // Make sure the descriptor is absolute format
  1746. //
  1747. if (ISecurityDescriptor->Control & SE_SELF_RELATIVE) {
  1748. return STATUS_INVALID_SECURITY_DESCR;
  1749. }
  1750. //
  1751. // Assign the DaclPresent flag value passed
  1752. //
  1753. if (DaclPresent) {
  1754. ISecurityDescriptor->Control |= SE_DACL_PRESENT;
  1755. //
  1756. // Assign the ACL address if passed, otherwise set to null.
  1757. //
  1758. ISecurityDescriptor->Dacl = NULL;
  1759. if (ARGUMENT_PRESENT(Dacl)) {
  1760. ISecurityDescriptor->Dacl = Dacl;
  1761. }
  1762. //
  1763. // Assign DaclDefaulted flag if passed, otherwise clear it.
  1764. //
  1765. ISecurityDescriptor->Control &= ~SE_DACL_DEFAULTED;
  1766. if (DaclDefaulted == TRUE) {
  1767. ISecurityDescriptor->Control |= SE_DACL_DEFAULTED;
  1768. }
  1769. } else {
  1770. ISecurityDescriptor->Control &= ~SE_DACL_PRESENT;
  1771. }
  1772. return STATUS_SUCCESS;
  1773. }
  1774. NTSTATUS
  1775. RtlGetDaclSecurityDescriptor (
  1776. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1777. OUT PBOOLEAN DaclPresent,
  1778. OUT PACL *Dacl,
  1779. OUT PBOOLEAN DaclDefaulted
  1780. )
  1781. /*++
  1782. Routine Description:
  1783. This procedure retrieves the discretionary ACL information of a
  1784. security descriptor.
  1785. Arguments:
  1786. SecurityDescriptor - Supplies the security descriptor.
  1787. DaclPresent - If TRUE, indicates that the security descriptor
  1788. does contain a discretionary ACL. In this case, the
  1789. remaining OUT parameters will receive valid values.
  1790. Otherwise, the security descriptor does not contain a
  1791. discretionary ACL and the remaining OUT parameters will not
  1792. receive valid values.
  1793. Dacl - This value is returned only if the value returned for the
  1794. DaclPresent flag is TRUE. In this case, the Dacl parameter
  1795. receives the address of the security descriptor's
  1796. discretionary ACL. If this value is returned as null, then
  1797. the security descriptor has a null discretionary ACL.
  1798. DaclDefaulted - This value is returned only if the value returned
  1799. for the DaclPresent flag is TRUE. In this case, the
  1800. DaclDefaulted parameter receives the value of the security
  1801. descriptor's DaclDefaulted control flag.
  1802. Return Value:
  1803. STATUS_SUCCESS - Indicates the call completed successfully.
  1804. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  1805. descriptor is not known to the routine. It may be a newer
  1806. revision than the routine knows about.
  1807. --*/
  1808. {
  1809. //
  1810. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  1811. //
  1812. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  1813. RTL_PAGED_CODE();
  1814. //
  1815. // Check the revision
  1816. //
  1817. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  1818. return STATUS_UNKNOWN_REVISION;
  1819. }
  1820. //
  1821. // Assign the DaclPresent flag value
  1822. //
  1823. *DaclPresent = RtlpAreControlBitsSet( ISecurityDescriptor, SE_DACL_PRESENT );
  1824. if (*DaclPresent) {
  1825. //
  1826. // Assign the ACL address.
  1827. //
  1828. *Dacl = RtlpDaclAddrSecurityDescriptor(ISecurityDescriptor);
  1829. //
  1830. // Assign DaclDefaulted flag.
  1831. //
  1832. *DaclDefaulted = RtlpAreControlBitsSet( ISecurityDescriptor, SE_DACL_DEFAULTED );
  1833. }
  1834. return STATUS_SUCCESS;
  1835. }
  1836. NTSTATUS
  1837. RtlSetSaclSecurityDescriptor (
  1838. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1839. IN BOOLEAN SaclPresent,
  1840. IN PACL Sacl OPTIONAL,
  1841. IN BOOLEAN SaclDefaulted OPTIONAL
  1842. )
  1843. /*++
  1844. Routine Description:
  1845. This procedure sets the system ACL information of an absolute security
  1846. descriptor. If there is already a system ACL present in the
  1847. security descriptor, it is superseded.
  1848. Arguments:
  1849. SecurityDescriptor - Supplies the security descriptor to be which
  1850. the system ACL is to be added.
  1851. SaclPresent - If FALSE, indicates the SaclPresent flag in the
  1852. security descriptor should be set to FALSE. In this case,
  1853. the remaining optional parameters are ignored. Otherwise,
  1854. the SaclPresent control flag in the security descriptor is
  1855. set to TRUE and the remaining optional parameters are not
  1856. ignored.
  1857. Sacl - Supplies the system ACL for the security descriptor. If
  1858. this optional parameter is not passed, then a null ACL is
  1859. assigned to the security descriptor. The ACL is referenced
  1860. by, not copied into, by the security descriptor.
  1861. SaclDefaulted - When set, indicates the system ACL was picked up
  1862. from some default mechanism (rather than explicitly specified
  1863. by a user). This value is set in the SaclDefaulted control
  1864. flag in the security descriptor. If this optional parameter
  1865. is not passed, then the SaclDefaulted flag will be cleared.
  1866. Return Value:
  1867. STATUS_SUCCESS - Indicates the call completed successfully.
  1868. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  1869. descriptor is not known to the routine. It may be a newer
  1870. revision than the routine knows about.
  1871. STATUS_INVALID_SECURITY_DESCR - Indicates the security descriptor
  1872. is not an absolute format security descriptor.
  1873. --*/
  1874. {
  1875. //
  1876. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  1877. //
  1878. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  1879. RTL_PAGED_CODE();
  1880. //
  1881. // Check the revision
  1882. //
  1883. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  1884. return STATUS_UNKNOWN_REVISION;
  1885. }
  1886. //
  1887. // Make sure the descriptor is absolute format
  1888. //
  1889. if (ISecurityDescriptor->Control & SE_SELF_RELATIVE) {
  1890. return STATUS_INVALID_SECURITY_DESCR;
  1891. }
  1892. //
  1893. // Assign the SaclPresent flag value passed
  1894. //
  1895. if (SaclPresent) {
  1896. ISecurityDescriptor->Control |= SE_SACL_PRESENT;
  1897. //
  1898. // Assign the ACL address if passed, otherwise set to null.
  1899. //
  1900. ISecurityDescriptor->Sacl = NULL;
  1901. if (ARGUMENT_PRESENT(Sacl)) {
  1902. ISecurityDescriptor->Sacl = Sacl;
  1903. }
  1904. //
  1905. // Assign SaclDefaulted flag if passed, otherwise clear it.
  1906. //
  1907. ISecurityDescriptor->Control &= ~ SE_SACL_DEFAULTED;
  1908. if (ARGUMENT_PRESENT(SaclDefaulted)) {
  1909. ISecurityDescriptor->Control |= SE_SACL_DEFAULTED;
  1910. }
  1911. } else {
  1912. ISecurityDescriptor->Control &= ~SE_SACL_PRESENT;
  1913. }
  1914. return STATUS_SUCCESS;
  1915. }
  1916. NTSTATUS
  1917. RtlGetSaclSecurityDescriptor (
  1918. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1919. OUT PBOOLEAN SaclPresent,
  1920. OUT PACL *Sacl,
  1921. OUT PBOOLEAN SaclDefaulted
  1922. )
  1923. /*++
  1924. Routine Description:
  1925. This procedure retrieves the system ACL information of a security
  1926. descriptor.
  1927. Arguments:
  1928. SecurityDescriptor - Supplies the security descriptor.
  1929. SaclPresent - If TRUE, indicates that the security descriptor
  1930. does contain a system ACL. In this case, the remaining OUT
  1931. parameters will receive valid values. Otherwise, the
  1932. security descriptor does not contain a system ACL and the
  1933. remaining OUT parameters will not receive valid values.
  1934. Sacl - This value is returned only if the value returned for the
  1935. SaclPresent flag is TRUE. In this case, the Sacl parameter
  1936. receives the address of the security descriptor's system ACL.
  1937. If this value is returned as null, then the security
  1938. descriptor has a null system ACL.
  1939. SaclDefaulted - This value is returned only if the value returned
  1940. for the SaclPresent flag is TRUE. In this case, the
  1941. SaclDefaulted parameter receives the value of the security
  1942. descriptor's SaclDefaulted control flag.
  1943. Return Value:
  1944. STATUS_SUCCESS - Indicates the call completed successfully.
  1945. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  1946. descriptor is not known to the routine. It may be a newer
  1947. revision than the routine knows about.
  1948. --*/
  1949. {
  1950. //
  1951. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  1952. //
  1953. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  1954. RTL_PAGED_CODE();
  1955. //
  1956. // Check the revision
  1957. //
  1958. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  1959. return STATUS_UNKNOWN_REVISION;
  1960. }
  1961. //
  1962. // Assign the SaclPresent flag value
  1963. //
  1964. *SaclPresent = RtlpAreControlBitsSet( ISecurityDescriptor, SE_SACL_PRESENT );
  1965. if (*SaclPresent) {
  1966. //
  1967. // Assign the ACL address.
  1968. //
  1969. *Sacl = RtlpSaclAddrSecurityDescriptor(ISecurityDescriptor);
  1970. //
  1971. // Assign SaclDefaulted flag.
  1972. //
  1973. *SaclDefaulted = RtlpAreControlBitsSet( ISecurityDescriptor, SE_SACL_DEFAULTED );
  1974. }
  1975. return STATUS_SUCCESS;
  1976. }
  1977. NTSTATUS
  1978. RtlSetOwnerSecurityDescriptor (
  1979. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1980. IN PSID Owner OPTIONAL,
  1981. IN BOOLEAN OwnerDefaulted OPTIONAL
  1982. )
  1983. /*++
  1984. Routine Description:
  1985. This procedure sets the owner information of an absolute security
  1986. descriptor. If there is already an owner present in the security
  1987. descriptor, it is superseded.
  1988. Arguments:
  1989. SecurityDescriptor - Supplies the security descriptor in which
  1990. the owner is to be set. If the security descriptor already
  1991. includes an owner, it will be superseded by the new owner.
  1992. Owner - Supplies the owner SID for the security descriptor. If
  1993. this optional parameter is not passed, then the owner is
  1994. cleared (indicating the security descriptor has no owner).
  1995. The SID is referenced by, not copied into, the security
  1996. descriptor.
  1997. OwnerDefaulted - When set, indicates the owner was picked up from
  1998. some default mechanism (rather than explicitly specified by a
  1999. user). This value is set in the OwnerDefaulted control flag
  2000. in the security descriptor. If this optional parameter is
  2001. not passed, then the SaclDefaulted flag will be cleared.
  2002. Return Value:
  2003. STATUS_SUCCESS - Indicates the call completed successfully.
  2004. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  2005. descriptor is not known to the routine. It may be a newer
  2006. revision than the routine knows about.
  2007. STATUS_INVALID_SECURITY_DESCR - Indicates the security descriptor
  2008. is not an absolute format security descriptor.
  2009. --*/
  2010. {
  2011. //
  2012. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  2013. //
  2014. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  2015. RTL_PAGED_CODE();
  2016. //
  2017. // Check the revision
  2018. //
  2019. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  2020. return STATUS_UNKNOWN_REVISION;
  2021. }
  2022. //
  2023. // Make sure the descriptor is absolute format
  2024. //
  2025. if (ISecurityDescriptor->Control & SE_SELF_RELATIVE) {
  2026. return STATUS_INVALID_SECURITY_DESCR;
  2027. }
  2028. //
  2029. // Assign the Owner field if passed, otherwise clear it.
  2030. //
  2031. ISecurityDescriptor->Owner = NULL;
  2032. if (ARGUMENT_PRESENT(Owner)) {
  2033. ISecurityDescriptor->Owner = Owner;
  2034. }
  2035. //
  2036. // Assign the OwnerDefaulted flag if passed, otherwise clear it.
  2037. //
  2038. ISecurityDescriptor->Control &= ~SE_OWNER_DEFAULTED;
  2039. if (OwnerDefaulted == TRUE) {
  2040. ISecurityDescriptor->Control |= SE_OWNER_DEFAULTED;
  2041. }
  2042. return STATUS_SUCCESS;
  2043. }
  2044. NTSTATUS
  2045. RtlGetOwnerSecurityDescriptor (
  2046. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  2047. OUT PSID *Owner,
  2048. OUT PBOOLEAN OwnerDefaulted
  2049. )
  2050. /*++
  2051. Routine Description:
  2052. This procedure retrieves the owner information of a security
  2053. descriptor.
  2054. Arguments:
  2055. SecurityDescriptor - Supplies the security descriptor.
  2056. Owner - Receives a pointer to the owner SID. If the security
  2057. descriptor does not currently contain an owner, then this
  2058. value will be returned as null. In this case, the remaining
  2059. OUT parameters are not given valid return values. Otherwise,
  2060. this parameter points to an SID and the remaining OUT
  2061. parameters are provided valid return values.
  2062. OwnerDefaulted - This value is returned only if the value
  2063. returned for the Owner parameter is not null. In this case,
  2064. the OwnerDefaulted parameter receives the value of the
  2065. security descriptor's OwnerDefaulted control flag.
  2066. Return Value:
  2067. STATUS_SUCCESS - Indicates the call completed successfully.
  2068. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  2069. descriptor is not known to the routine. It may be a newer
  2070. revision than the routine knows about.
  2071. --*/
  2072. {
  2073. //
  2074. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  2075. //
  2076. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  2077. RTL_PAGED_CODE();
  2078. //
  2079. // Check the revision
  2080. //
  2081. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  2082. return STATUS_UNKNOWN_REVISION;
  2083. }
  2084. //
  2085. // Return the Owner field value.
  2086. //
  2087. *Owner = RtlpOwnerAddrSecurityDescriptor(ISecurityDescriptor);
  2088. //
  2089. // Return the OwnerDefaulted flag value.
  2090. //
  2091. *OwnerDefaulted = RtlpAreControlBitsSet( ISecurityDescriptor, SE_OWNER_DEFAULTED );
  2092. return STATUS_SUCCESS;
  2093. }
  2094. NTSTATUS
  2095. RtlSetGroupSecurityDescriptor (
  2096. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  2097. IN PSID Group OPTIONAL,
  2098. IN BOOLEAN GroupDefaulted OPTIONAL
  2099. )
  2100. /*++
  2101. Routine Description:
  2102. This procedure sets the primary group information of an absolute security
  2103. descriptor. If there is already an primary group present in the
  2104. security descriptor, it is superseded.
  2105. Arguments:
  2106. SecurityDescriptor - Supplies the security descriptor in which
  2107. the primary group is to be set. If the security descriptor
  2108. already includes a primary group, it will be superseded by
  2109. the new group.
  2110. Group - Supplies the primary group SID for the security
  2111. descriptor. If this optional parameter is not passed, then
  2112. the primary group is cleared (indicating the security
  2113. descriptor has no primary group). The SID is referenced by,
  2114. not copied into, the security descriptor.
  2115. GroupDefaulted - When set, indicates the owner was picked up from
  2116. some default mechanism (rather than explicitly specified by a
  2117. user). This value is set in the OwnerDefaulted control flag
  2118. in the security descriptor. If this optional parameter is
  2119. not passed, then the SaclDefaulted flag will be cleared.
  2120. Return Value:
  2121. STATUS_SUCCESS - Indicates the call completed successfully.
  2122. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  2123. descriptor is not known to the routine. It may be a newer
  2124. revision than the routine knows about.
  2125. STATUS_INVALID_SECURITY_DESCR - Indicates the security descriptor
  2126. is not an absolute format security descriptor.
  2127. --*/
  2128. {
  2129. //
  2130. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  2131. //
  2132. SECURITY_DESCRIPTOR *ISecurityDescriptor = SecurityDescriptor;
  2133. RTL_PAGED_CODE();
  2134. //
  2135. // Check the revision
  2136. //
  2137. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  2138. return STATUS_UNKNOWN_REVISION;
  2139. }
  2140. //
  2141. // Make sure the descriptor is absolute format
  2142. //
  2143. if (ISecurityDescriptor->Control & SE_SELF_RELATIVE) {
  2144. return STATUS_INVALID_SECURITY_DESCR;
  2145. }
  2146. //
  2147. // Assign the Group field if passed, otherwise clear it.
  2148. //
  2149. ISecurityDescriptor->Group = NULL;
  2150. if (ARGUMENT_PRESENT(Group)) {
  2151. ISecurityDescriptor->Group = Group;
  2152. }
  2153. //
  2154. // Assign the GroupDefaulted flag if passed, otherwise clear it.
  2155. //
  2156. ISecurityDescriptor->Control &= ~SE_GROUP_DEFAULTED;
  2157. if (ARGUMENT_PRESENT(GroupDefaulted)) {
  2158. ISecurityDescriptor->Control |= SE_GROUP_DEFAULTED;
  2159. }
  2160. return STATUS_SUCCESS;
  2161. }
  2162. NTSTATUS
  2163. RtlGetGroupSecurityDescriptor (
  2164. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  2165. OUT PSID *Group,
  2166. OUT PBOOLEAN GroupDefaulted
  2167. )
  2168. /*++
  2169. Routine Description:
  2170. This procedure retrieves the primary group information of a
  2171. security descriptor.
  2172. Arguments:
  2173. SecurityDescriptor - Supplies the security descriptor.
  2174. Group - Receives a pointer to the primary group SID. If the
  2175. security descriptor does not currently contain a primary
  2176. group, then this value will be returned as null. In this
  2177. case, the remaining OUT parameters are not given valid return
  2178. values. Otherwise, this parameter points to an SID and the
  2179. remaining OUT parameters are provided valid return values.
  2180. GroupDefaulted - This value is returned only if the value
  2181. returned for the Group parameter is not null. In this case,
  2182. the GroupDefaulted parameter receives the value of the
  2183. security descriptor's GroupDefaulted control flag.
  2184. Return Value:
  2185. STATUS_SUCCESS - Indicates the call completed successfully.
  2186. STATUS_UNKNOWN_REVISION - Indicates the revision of the security
  2187. descriptor is not known to the routine. It may be a newer
  2188. revision than the routine knows about.
  2189. --*/
  2190. {
  2191. //
  2192. // Typecast to the opaque SECURITY_DESCRIPTOR structure.
  2193. //
  2194. SECURITY_DESCRIPTOR *ISecurityDescriptor =
  2195. (SECURITY_DESCRIPTOR *)SecurityDescriptor;
  2196. RTL_PAGED_CODE();
  2197. //
  2198. // Check the revision
  2199. //
  2200. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  2201. return STATUS_UNKNOWN_REVISION;
  2202. }
  2203. //
  2204. // Return the Group field value.
  2205. //
  2206. *Group = RtlpGroupAddrSecurityDescriptor(ISecurityDescriptor);
  2207. //
  2208. // Return the GroupDefaulted flag value.
  2209. //
  2210. *GroupDefaulted = RtlpAreControlBitsSet( ISecurityDescriptor, SE_GROUP_DEFAULTED );
  2211. return STATUS_SUCCESS;
  2212. }
  2213. BOOLEAN
  2214. RtlAreAllAccessesGranted(
  2215. IN ACCESS_MASK GrantedAccess,
  2216. IN ACCESS_MASK DesiredAccess
  2217. )
  2218. /*++
  2219. Routine Description:
  2220. This routine is used to check a desired access mask against a
  2221. granted access mask. It is used by the Object Management
  2222. component when dereferencing a handle.
  2223. Arguments:
  2224. GrantedAccess - Specifies the granted access mask.
  2225. DesiredAccess - Specifies the desired access mask.
  2226. Return Value:
  2227. BOOLEAN - TRUE if the GrantedAccess mask has all the bits set
  2228. that the DesiredAccess mask has set. That is, TRUE is
  2229. returned if all of the desired accesses have been granted.
  2230. --*/
  2231. {
  2232. RTL_PAGED_CODE();
  2233. return ((BOOLEAN)((~(GrantedAccess) & (DesiredAccess)) == 0));
  2234. }
  2235. BOOLEAN
  2236. RtlAreAnyAccessesGranted(
  2237. IN ACCESS_MASK GrantedAccess,
  2238. IN ACCESS_MASK DesiredAccess
  2239. )
  2240. /*++
  2241. Routine Description:
  2242. This routine is used to test whether any of a set of desired
  2243. accesses are granted by a granted access mask. It is used by
  2244. components other than the the Object Management component for
  2245. checking access mask subsets.
  2246. Arguments:
  2247. GrantedAccess - Specifies the granted access mask.
  2248. DesiredAccess - Specifies the desired access mask.
  2249. Return Value:
  2250. BOOLEAN - TRUE if the GrantedAccess mask contains any of the bits
  2251. specified in the DesiredAccess mask. That is, if any of the
  2252. desired accesses have been granted, TRUE is returned.
  2253. --*/
  2254. {
  2255. RTL_PAGED_CODE();
  2256. return ((BOOLEAN)(((GrantedAccess) & (DesiredAccess)) != 0));
  2257. }
  2258. VOID
  2259. RtlMapGenericMask(
  2260. IN OUT PACCESS_MASK AccessMask,
  2261. IN PGENERIC_MAPPING GenericMapping
  2262. )
  2263. /*++
  2264. Routine Description:
  2265. This routine maps all generic accesses in the provided access mask
  2266. to specific and standard accesses according to the provided
  2267. GenericMapping.
  2268. Arguments:
  2269. AccessMask - Points to the access mask to be mapped.
  2270. GenericMapping - The mapping of generic to specific and standard
  2271. access types.
  2272. Return Value:
  2273. None.
  2274. --*/
  2275. {
  2276. RTL_PAGED_CODE();
  2277. // //
  2278. // // Make sure the pointer is properly aligned
  2279. // //
  2280. //
  2281. // ASSERT( ((ULONG)AccessMask >> 2) << 2 == (ULONG)AccessMask );
  2282. if (*AccessMask & GENERIC_READ) {
  2283. *AccessMask |= GenericMapping->GenericRead;
  2284. }
  2285. if (*AccessMask & GENERIC_WRITE) {
  2286. *AccessMask |= GenericMapping->GenericWrite;
  2287. }
  2288. if (*AccessMask & GENERIC_EXECUTE) {
  2289. *AccessMask |= GenericMapping->GenericExecute;
  2290. }
  2291. if (*AccessMask & GENERIC_ALL) {
  2292. *AccessMask |= GenericMapping->GenericAll;
  2293. }
  2294. //
  2295. // Now clear the generic flags
  2296. //
  2297. *AccessMask &= ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
  2298. return;
  2299. }
  2300. NTSTATUS
  2301. RtlImpersonateSelf(
  2302. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  2303. )
  2304. /*++
  2305. Routine Description:
  2306. This routine may be used to obtain an Impersonation token representing
  2307. your own process's context. This may be useful for enabling a privilege
  2308. for a single thread rather than for the entire process; or changing
  2309. the default DACL for a single thread.
  2310. The token is assigned to the callers thread.
  2311. Arguments:
  2312. ImpersonationLevel - The level to make the impersonation token.
  2313. Return Value:
  2314. STATUS_SUCCESS - The thread is now impersonating the calling process.
  2315. Other - Status values returned by:
  2316. NtOpenProcessToken()
  2317. NtDuplicateToken()
  2318. NtSetInformationThread()
  2319. --*/
  2320. {
  2321. NTSTATUS
  2322. Status,
  2323. IgnoreStatus;
  2324. HANDLE
  2325. Token1,
  2326. Token2;
  2327. OBJECT_ATTRIBUTES
  2328. ObjectAttributes;
  2329. SECURITY_QUALITY_OF_SERVICE
  2330. Qos;
  2331. RTL_PAGED_CODE();
  2332. InitializeObjectAttributes(&ObjectAttributes, NULL, 0, 0, NULL);
  2333. Qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  2334. Qos.ImpersonationLevel = ImpersonationLevel;
  2335. Qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  2336. Qos.EffectiveOnly = FALSE;
  2337. ObjectAttributes.SecurityQualityOfService = &Qos;
  2338. Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_DUPLICATE, &Token1 );
  2339. if (NT_SUCCESS(Status)) {
  2340. Status = NtDuplicateToken(
  2341. Token1,
  2342. TOKEN_IMPERSONATE,
  2343. &ObjectAttributes,
  2344. FALSE, //EffectiveOnly
  2345. TokenImpersonation,
  2346. &Token2
  2347. );
  2348. if (NT_SUCCESS(Status)) {
  2349. Status = NtSetInformationThread(
  2350. NtCurrentThread(),
  2351. ThreadImpersonationToken,
  2352. &Token2,
  2353. sizeof(HANDLE)
  2354. );
  2355. IgnoreStatus = NtClose( Token2 );
  2356. }
  2357. IgnoreStatus = NtClose( Token1 );
  2358. }
  2359. return(Status);
  2360. }
  2361. #ifndef WIN16
  2362. #ifndef NTOS_KERNEL_RUNTIME
  2363. BOOLEAN
  2364. RtlpValidOwnerSubjectContext(
  2365. IN HANDLE Token,
  2366. IN PSID Owner,
  2367. IN BOOLEAN ServerObject,
  2368. OUT PNTSTATUS ReturnStatus
  2369. )
  2370. /*++
  2371. Routine Description:
  2372. This routine checks to see whether the provided SID is one the subject
  2373. is authorized to assign as the owner of objects.
  2374. Arguments:
  2375. Token - Points to the subject's effective token
  2376. Owner - Points to the SID to be checked.
  2377. ServerObject - Boolean indicating whether or not this is a server
  2378. object, meaning it is protected by a primary-client combination.
  2379. ReturnStatus - Status to be passed back to the caller on failure.
  2380. Return Value:
  2381. FALSE on failure.
  2382. --*/
  2383. {
  2384. NTSTATUS Status;
  2385. ULONG Index;
  2386. BOOLEAN Found;
  2387. ULONG ReturnLength;
  2388. PTOKEN_GROUPS GroupIds = NULL;
  2389. PTOKEN_USER UserId = NULL;
  2390. PVOID HeapHandle;
  2391. HANDLE TokenToUse;
  2392. BOOLEAN HasPrivilege;
  2393. PRIVILEGE_SET PrivilegeSet;
  2394. RTL_PAGED_CODE();
  2395. //
  2396. // Get the handle to the current process heap
  2397. //
  2398. if ( Owner == NULL ) {
  2399. *ReturnStatus = STATUS_INVALID_OWNER;
  2400. return(FALSE);
  2401. }
  2402. //
  2403. // If it's not a server object, check the owner against the contents of the
  2404. // client token. If it is a server object, the owner must be valid in the
  2405. // primary token.
  2406. //
  2407. if (!ServerObject) {
  2408. TokenToUse = Token;
  2409. } else {
  2410. *ReturnStatus = NtOpenProcessToken(
  2411. NtCurrentProcess(),
  2412. TOKEN_QUERY,
  2413. &TokenToUse
  2414. );
  2415. if (!NT_SUCCESS( *ReturnStatus )) {
  2416. return( FALSE );
  2417. }
  2418. }
  2419. HeapHandle = RtlProcessHeap();
  2420. //
  2421. // Get the User from the Token
  2422. //
  2423. *ReturnStatus = NtQueryInformationToken(
  2424. TokenToUse,
  2425. TokenUser,
  2426. UserId,
  2427. 0,
  2428. &ReturnLength
  2429. );
  2430. if (!NT_SUCCESS( *ReturnStatus ) && (STATUS_BUFFER_TOO_SMALL != *ReturnStatus)) {
  2431. if (ServerObject) {
  2432. NtClose( TokenToUse );
  2433. }
  2434. return( FALSE );
  2435. }
  2436. UserId = RtlAllocateHeap( HeapHandle, 0, ReturnLength );
  2437. if (UserId == NULL) {
  2438. *ReturnStatus = STATUS_NO_MEMORY;
  2439. if (ServerObject) {
  2440. NtClose( TokenToUse );
  2441. }
  2442. return( FALSE );
  2443. }
  2444. *ReturnStatus = NtQueryInformationToken(
  2445. TokenToUse,
  2446. TokenUser,
  2447. UserId,
  2448. ReturnLength,
  2449. &ReturnLength
  2450. );
  2451. if (!NT_SUCCESS( *ReturnStatus )) {
  2452. RtlFreeHeap( HeapHandle, 0, (PVOID)UserId );
  2453. if (ServerObject) {
  2454. NtClose( TokenToUse );
  2455. }
  2456. return( FALSE );
  2457. }
  2458. if ( RtlEqualSid( Owner, UserId->User.Sid ) ) {
  2459. RtlFreeHeap( HeapHandle, 0, (PVOID)UserId );
  2460. if (ServerObject) {
  2461. NtClose( TokenToUse );
  2462. }
  2463. return( TRUE );
  2464. }
  2465. RtlFreeHeap( HeapHandle, 0, (PVOID)UserId );
  2466. //
  2467. // Get the groups from the Token
  2468. //
  2469. *ReturnStatus = NtQueryInformationToken(
  2470. TokenToUse,
  2471. TokenGroups,
  2472. GroupIds,
  2473. 0,
  2474. &ReturnLength
  2475. );
  2476. if (!NT_SUCCESS( *ReturnStatus ) && (STATUS_BUFFER_TOO_SMALL != *ReturnStatus)) {
  2477. if (ServerObject) {
  2478. NtClose( TokenToUse );
  2479. }
  2480. return( FALSE );
  2481. }
  2482. GroupIds = RtlAllocateHeap( HeapHandle, 0, ReturnLength );
  2483. if (GroupIds == NULL) {
  2484. *ReturnStatus = STATUS_NO_MEMORY;
  2485. if (ServerObject) {
  2486. NtClose( TokenToUse );
  2487. }
  2488. return( FALSE );
  2489. }
  2490. *ReturnStatus = NtQueryInformationToken(
  2491. TokenToUse,
  2492. TokenGroups,
  2493. GroupIds,
  2494. ReturnLength,
  2495. &ReturnLength
  2496. );
  2497. if (ServerObject) {
  2498. NtClose( TokenToUse );
  2499. }
  2500. if (!NT_SUCCESS( *ReturnStatus )) {
  2501. RtlFreeHeap( HeapHandle, 0, GroupIds );
  2502. return( FALSE );
  2503. }
  2504. //
  2505. // Walk through the list of group IDs looking for a match to
  2506. // the specified SID. If one is found, make sure it may be
  2507. // assigned as an owner.
  2508. //
  2509. // This code is similar to that performed to set the default
  2510. // owner of a token (NtSetInformationToken).
  2511. //
  2512. Index = 0;
  2513. while (Index < GroupIds->GroupCount) {
  2514. Found = RtlEqualSid(
  2515. Owner,
  2516. GroupIds->Groups[Index].Sid
  2517. );
  2518. if ( Found ) {
  2519. if ( RtlpIdAssignableAsOwner(GroupIds->Groups[Index])) {
  2520. RtlFreeHeap( HeapHandle, 0, GroupIds );
  2521. return TRUE;
  2522. } else {
  2523. break;
  2524. } //endif assignable
  2525. } //endif Found
  2526. Index++;
  2527. } //endwhile
  2528. RtlFreeHeap( HeapHandle, 0, GroupIds );
  2529. //
  2530. // If we are going to fail this call, check for Restore privilege,
  2531. // and succeed if he has it.
  2532. //
  2533. //
  2534. // Check for appropriate Privileges
  2535. //
  2536. // Audit/Alarm messages need to be generated due to the attempt
  2537. // to perform a privileged operation.
  2538. //
  2539. PrivilegeSet.PrivilegeCount = 1;
  2540. PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
  2541. PrivilegeSet.Privilege[0].Luid = RtlConvertLongToLuid(SE_RESTORE_PRIVILEGE);
  2542. PrivilegeSet.Privilege[0].Attributes = 0;
  2543. Status = NtPrivilegeCheck(
  2544. Token,
  2545. &PrivilegeSet,
  2546. &HasPrivilege
  2547. );
  2548. if (!NT_SUCCESS( Status )) {
  2549. HasPrivilege = FALSE;
  2550. }
  2551. if ( HasPrivilege ) {
  2552. return TRUE;
  2553. } else {
  2554. *ReturnStatus = STATUS_INVALID_OWNER;
  2555. return FALSE;
  2556. }
  2557. }
  2558. #endif // NTOS_KERNEL_RUNTIME
  2559. #endif // WIN16
  2560. VOID
  2561. RtlpApplyAclToObject (
  2562. IN PACL Acl,
  2563. IN PGENERIC_MAPPING GenericMapping
  2564. )
  2565. /*++
  2566. Routine Description:
  2567. This is a private routine that maps Access Masks of an ACL so that
  2568. they are applicable to the object type the ACL is being applied to.
  2569. Only known DSA ACEs are mapped. Unknown ACE types are ignored.
  2570. Only access types in the GenericAll mapping for the target object
  2571. type will be non-zero upon return.
  2572. Arguments:
  2573. Acl - Supplies the acl being applied.
  2574. GenericMapping - Specifies the generic mapping to use.
  2575. Return Value:
  2576. None.
  2577. --*/
  2578. {
  2579. ULONG i;
  2580. PACE_HEADER Ace;
  2581. RTL_PAGED_CODE();
  2582. //
  2583. // First check if the acl is null
  2584. //
  2585. if (Acl == NULL) {
  2586. return;
  2587. }
  2588. //
  2589. // Now walk the ACL, mapping each ACE as we go.
  2590. //
  2591. for (i = 0, Ace = FirstAce(Acl);
  2592. i < Acl->AceCount;
  2593. i += 1, Ace = NextAce(Ace)) {
  2594. if (IsMSAceType( Ace )) {
  2595. RtlApplyAceToObject( Ace, GenericMapping );
  2596. }
  2597. }
  2598. return;
  2599. }
  2600. BOOLEAN
  2601. RtlpCopyEffectiveAce (
  2602. IN PACE_HEADER OldAce,
  2603. IN BOOLEAN AutoInherit,
  2604. IN BOOLEAN WillGenerateInheritAce,
  2605. IN PSID ClientOwnerSid,
  2606. IN PSID ClientGroupSid,
  2607. IN PSID ServerOwnerSid OPTIONAL,
  2608. IN PSID ServerGroupSid OPTIONAL,
  2609. IN PGENERIC_MAPPING GenericMapping,
  2610. IN GUID **pNewObjectType OPTIONAL,
  2611. IN ULONG GuidCount,
  2612. IN OUT PVOID *AcePosition,
  2613. OUT PULONG NewAceLength,
  2614. OUT PACL NewAcl,
  2615. OUT PBOOLEAN ObjectAceInherited OPTIONAL,
  2616. OUT PBOOLEAN EffectiveAceMapped,
  2617. OUT PBOOLEAN AclOverflowed
  2618. )
  2619. /*++
  2620. Routine Description:
  2621. This routine copy a specified ACE into an ACL as an effective ACE.
  2622. The resultant ACE has all the inheritance bits turned of.
  2623. The resultant ACE has the SID mapped from a generic SID to a specific SID
  2624. (e.g., From "creator owner" to the passed in owner sid).
  2625. Arguments:
  2626. OldAce - Supplies the ace being inherited
  2627. AutoInherit - Specifies if the inheritance is an "automatic inheritance".
  2628. As such, the inherited ACEs will be marked as such.
  2629. WillGenerateInheritAce - Specifies if the caller intends to generate an
  2630. inheritable ACE the corresponds to OldAce. If TRUE, this routine will
  2631. try to not map the effective ACE (increasing the likelyhood that
  2632. EffectiveAceMapped will return FALSE),
  2633. ClientOwnerSid - Specifies the owner Sid to use
  2634. ClientGroupSid - Specifies the new Group Sid to use
  2635. ServerSid - Optionally specifies the Server Sid to use in compound ACEs.
  2636. ClientSid - Optionally specifies the Client Sid to use in compound ACEs.
  2637. GenericMapping - Specifies the generic mapping to use
  2638. pNewObjectType - List of types of object being inherited to. If not
  2639. specified, the object has no object type.
  2640. GuidCount - Number of object types in the list.
  2641. AcePosition - On entry and exit, specifies location of the next available ACE
  2642. position in NewAcl.
  2643. A NULL ACE position means there is no room at all in NewAcl.
  2644. NewAceLength - Returns the length (in bytes) needed in NewAcl to
  2645. copy the specified ACE. This might be zero to indicate that the ACE
  2646. need not be copied at all.
  2647. NewAcl - Provides a pointer to the ACL into which the ACE is to be
  2648. inherited.
  2649. ObjectAceInherited - Returns true if one or more object ACEs were inherited
  2650. based on NewObjectType
  2651. If NULL, NewObjectType is ignored and the object ACE is always inherited
  2652. EffectiveAceMapped - Return TRUE if the SID, guid, or access mask of Old Ace
  2653. was modifed when copying the ACE.
  2654. AclOverflowed - Returns TRUE if NewAcl wasn't long enough to contain NewAceLength.
  2655. Return Value:
  2656. TRUE - No problem was detected.
  2657. FALSE - Indicates something went wrong preventing
  2658. the ACE from being compied. This generally represents a bugcheck
  2659. situation when returned from this call.
  2660. --*/
  2661. {
  2662. ULONG LengthRequired;
  2663. ACCESS_MASK LocalMask;
  2664. BOOLEAN GuidOptimizationPossible = FALSE;
  2665. PSID LocalServerOwner;
  2666. PSID LocalServerGroup;
  2667. NTSTATUS Status;
  2668. ULONG CreatorSid[CREATOR_SID_SIZE];
  2669. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  2670. RTL_PAGED_CODE();
  2671. //
  2672. // Allocate and initialize the universal SIDs we're going to need
  2673. // to look for inheritable ACEs.
  2674. //
  2675. ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
  2676. Status = RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
  2677. if ( !NT_SUCCESS(Status) ) {
  2678. return FALSE;
  2679. }
  2680. *(RtlpSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_OWNER_RID;
  2681. LocalServerOwner = ARGUMENT_PRESENT(ServerOwnerSid) ? ServerOwnerSid : ClientOwnerSid;
  2682. LocalServerGroup = ARGUMENT_PRESENT(ServerGroupSid) ? ServerGroupSid : ClientGroupSid;
  2683. //
  2684. // Initialization
  2685. //
  2686. *EffectiveAceMapped = FALSE;
  2687. if ( ARGUMENT_PRESENT(ObjectAceInherited)) {
  2688. *ObjectAceInherited = FALSE;
  2689. }
  2690. *AclOverflowed = FALSE;
  2691. LengthRequired = (ULONG)OldAce->AceSize;
  2692. //
  2693. // Process all MS ACE types specially
  2694. //
  2695. if ( IsMSAceType(OldAce) ) {
  2696. ULONG Rid;
  2697. PSID SidToCopy = NULL;
  2698. ULONG AceHeaderToCopyLength;
  2699. PACE_HEADER AceHeaderToCopy = OldAce;
  2700. PSID ServerSidToCopy = NULL;
  2701. UCHAR DummyAce[sizeof(KNOWN_OBJECT_ACE)+sizeof(GUID)];
  2702. //
  2703. // Grab the Sid pointer and access mask as a function of the ACE type
  2704. //
  2705. if (IsKnownAceType( OldAce ) ) {
  2706. SidToCopy = &((PKNOWN_ACE)OldAce)->SidStart;
  2707. AceHeaderToCopyLength = FIELD_OFFSET(KNOWN_ACE, SidStart);
  2708. } else if (IsCompoundAceType(OldAce)) {
  2709. SidToCopy = RtlCompoundAceClientSid( OldAce );
  2710. AceHeaderToCopyLength = FIELD_OFFSET(KNOWN_COMPOUND_ACE, SidStart);
  2711. ASSERT( FIELD_OFFSET(KNOWN_COMPOUND_ACE, Mask) ==
  2712. FIELD_OFFSET(KNOWN_ACE, Mask) );
  2713. //
  2714. // Compound ACEs have two SIDs (Map one now).
  2715. //
  2716. ServerSidToCopy = RtlCompoundAceServerSid( OldAce );
  2717. if (RtlEqualPrefixSid ( ServerSidToCopy, CreatorSid )) {
  2718. Rid = *RtlpSubAuthoritySid( ServerSidToCopy, 0 );
  2719. switch (Rid) {
  2720. case SECURITY_CREATOR_OWNER_RID:
  2721. ServerSidToCopy = ClientOwnerSid;
  2722. LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientOwnerSid);
  2723. *EffectiveAceMapped = TRUE;
  2724. break;
  2725. case SECURITY_CREATOR_GROUP_RID:
  2726. if ( ClientGroupSid != NULL ) {
  2727. ServerSidToCopy = ClientGroupSid;
  2728. LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientGroupSid);
  2729. *EffectiveAceMapped = TRUE;
  2730. }
  2731. break;
  2732. case SECURITY_CREATOR_OWNER_SERVER_RID:
  2733. ServerSidToCopy = LocalServerOwner;
  2734. LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(LocalServerOwner);
  2735. *EffectiveAceMapped = TRUE;
  2736. break;
  2737. case SECURITY_CREATOR_GROUP_SERVER_RID:
  2738. ServerSidToCopy = LocalServerGroup;
  2739. LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(LocalServerGroup);
  2740. *EffectiveAceMapped = TRUE;
  2741. break;
  2742. }
  2743. //
  2744. // If we don't know what this SID is, just copy the original.
  2745. //
  2746. if ( !*EffectiveAceMapped ) {
  2747. AceHeaderToCopyLength += SeLengthSid( ServerSidToCopy );
  2748. ServerSidToCopy = NULL;
  2749. }
  2750. } else {
  2751. //
  2752. // We don't know what this SID is, just copy the original.
  2753. //
  2754. AceHeaderToCopyLength += SeLengthSid( ServerSidToCopy );
  2755. ServerSidToCopy = NULL;
  2756. }
  2757. //
  2758. // Handle Object ACEs
  2759. //
  2760. } else {
  2761. GUID *InheritedObjectType;
  2762. SidToCopy = RtlObjectAceSid( OldAce );
  2763. AceHeaderToCopyLength = (ULONG) ((PUCHAR)SidToCopy - (PUCHAR)OldAce);
  2764. ASSERT( FIELD_OFFSET(KNOWN_OBJECT_ACE, Mask) ==
  2765. FIELD_OFFSET(KNOWN_ACE, Mask) );
  2766. //
  2767. // Handle ACEs that are only inherited for a specific object type,
  2768. //
  2769. InheritedObjectType = RtlObjectAceInheritedObjectType( OldAce );
  2770. if ( ARGUMENT_PRESENT(ObjectAceInherited) && InheritedObjectType != NULL ) {
  2771. //
  2772. // If the object type doesn't match the inherited object type,
  2773. // don't inherit the ACE.
  2774. //
  2775. if ( pNewObjectType == NULL ||
  2776. !RtlpGuidPresentInGuidList( InheritedObjectType,
  2777. pNewObjectType,
  2778. GuidCount ) ) {
  2779. LengthRequired = 0;
  2780. //
  2781. // If the object type matches the inherited object type,
  2782. // Inherit an ACE with no inherited object type.
  2783. //
  2784. } else {
  2785. //
  2786. // Tell the caller we inherited an object type specific ACE.
  2787. //
  2788. *ObjectAceInherited = TRUE;
  2789. //
  2790. // If the caller is not going to generate an inheritable ACE,
  2791. // deleting the inherited object type GUID for the effective ACE.
  2792. //
  2793. // Otherwise, leave it so the caller can merge the two ACEs.
  2794. //
  2795. if ( !WillGenerateInheritAce ) {
  2796. *EffectiveAceMapped = TRUE;
  2797. //
  2798. // If an object type GUID is present,
  2799. // simply delete the inherited object type GUID.
  2800. //
  2801. if ( RtlObjectAceObjectTypePresent( OldAce )) {
  2802. LengthRequired -= sizeof(GUID);
  2803. AceHeaderToCopyLength -= sizeof(GUID);
  2804. RtlCopyMemory( DummyAce, OldAce, AceHeaderToCopyLength );
  2805. AceHeaderToCopy = (PACE_HEADER)DummyAce;
  2806. ((PKNOWN_OBJECT_ACE)AceHeaderToCopy)->Flags &= ~ACE_INHERITED_OBJECT_TYPE_PRESENT;
  2807. //
  2808. // If an object type GUID is not present,
  2809. // convert the ACE to non-object type specific.
  2810. //
  2811. } else {
  2812. AceHeaderToCopyLength = AceHeaderToCopyLength -
  2813. sizeof(GUID) +
  2814. sizeof(KNOWN_ACE) -
  2815. sizeof(KNOWN_OBJECT_ACE);
  2816. LengthRequired = LengthRequired -
  2817. sizeof(GUID) +
  2818. sizeof(KNOWN_ACE) -
  2819. sizeof(KNOWN_OBJECT_ACE);
  2820. RtlCopyMemory( DummyAce, OldAce, AceHeaderToCopyLength );
  2821. AceHeaderToCopy = (PACE_HEADER)DummyAce;
  2822. AceHeaderToCopy->AceType = RtlBaseAceType[ OldAce->AceType ];
  2823. }
  2824. } else {
  2825. GuidOptimizationPossible = TRUE;
  2826. }
  2827. }
  2828. }
  2829. }
  2830. //
  2831. // Only proceed if we've not already determined to drop the ACE.
  2832. //
  2833. if ( LengthRequired != 0 ) {
  2834. //
  2835. // If after mapping the access mask, the access mask
  2836. // is empty, then drop the ACE.
  2837. //
  2838. // This is incompatible with NT 4.0 which simply mapped and left
  2839. // undefined access bits set.
  2840. LocalMask = ((PKNOWN_ACE)(OldAce))->Mask;
  2841. RtlApplyGenericMask( OldAce, &LocalMask, GenericMapping);
  2842. if ( LocalMask != ((PKNOWN_ACE)(OldAce))->Mask ) {
  2843. *EffectiveAceMapped = TRUE;
  2844. }
  2845. //
  2846. // Mask off any bits that aren't meaningful
  2847. //
  2848. LocalMask &= ( STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL | ACCESS_SYSTEM_SECURITY );
  2849. if (LocalMask == 0) {
  2850. LengthRequired = 0;
  2851. } else {
  2852. //
  2853. // See if the SID in the ACE is one of the various CREATOR_* SIDs by
  2854. // comparing identifier authorities.
  2855. //
  2856. if (RtlEqualPrefixSid ( SidToCopy, CreatorSid )) {
  2857. Rid = *RtlpSubAuthoritySid( SidToCopy, 0 );
  2858. switch (Rid) {
  2859. case SECURITY_CREATOR_OWNER_RID:
  2860. SidToCopy = ClientOwnerSid;
  2861. LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientOwnerSid);
  2862. *EffectiveAceMapped = TRUE;
  2863. break;
  2864. case SECURITY_CREATOR_GROUP_RID:
  2865. if ( ClientGroupSid != NULL ) {
  2866. SidToCopy = ClientGroupSid;
  2867. LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(ClientGroupSid);
  2868. *EffectiveAceMapped = TRUE;
  2869. }
  2870. break;
  2871. case SECURITY_CREATOR_OWNER_SERVER_RID:
  2872. SidToCopy = LocalServerOwner;
  2873. LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(LocalServerOwner);
  2874. *EffectiveAceMapped = TRUE;
  2875. break;
  2876. case SECURITY_CREATOR_GROUP_SERVER_RID:
  2877. SidToCopy = LocalServerGroup;
  2878. LengthRequired = LengthRequired - CREATOR_SID_SIZE + SeLengthSid(LocalServerGroup);
  2879. *EffectiveAceMapped = TRUE;
  2880. break;
  2881. default :
  2882. //
  2883. // We don't know what this SID is, just copy the original.
  2884. //
  2885. break;
  2886. }
  2887. }
  2888. //
  2889. // In cases where effective ace has been mapped because of
  2890. // a. CreatorOwner/Group OR
  2891. // b. Generic flags
  2892. // AND
  2893. // this is an object type ace which will generate an IO ace
  2894. // we can save space for a guid.
  2895. //
  2896. if (GuidOptimizationPossible && *EffectiveAceMapped) {
  2897. //
  2898. // If an object type GUID is present,
  2899. // simply delete the inherited object type GUID.
  2900. //
  2901. if ( RtlObjectAceObjectTypePresent( OldAce )) {
  2902. LengthRequired -= sizeof(GUID);
  2903. AceHeaderToCopyLength -= sizeof(GUID);
  2904. RtlCopyMemory( DummyAce, OldAce, AceHeaderToCopyLength );
  2905. AceHeaderToCopy = (PACE_HEADER)DummyAce;
  2906. ((PKNOWN_OBJECT_ACE)AceHeaderToCopy)->Flags &= ~ACE_INHERITED_OBJECT_TYPE_PRESENT;
  2907. //
  2908. // If an object type GUID is not present,
  2909. // convert the ACE to non-object type specific.
  2910. //
  2911. } else {
  2912. AceHeaderToCopyLength = AceHeaderToCopyLength -
  2913. sizeof(GUID) +
  2914. sizeof(KNOWN_ACE) -
  2915. sizeof(KNOWN_OBJECT_ACE);
  2916. LengthRequired = LengthRequired -
  2917. sizeof(GUID) +
  2918. sizeof(KNOWN_ACE) -
  2919. sizeof(KNOWN_OBJECT_ACE);
  2920. RtlCopyMemory( DummyAce, OldAce, AceHeaderToCopyLength );
  2921. AceHeaderToCopy = (PACE_HEADER)DummyAce;
  2922. AceHeaderToCopy->AceType = RtlBaseAceType[ OldAce->AceType ];
  2923. }
  2924. }
  2925. //
  2926. // If the ACE doesn't fit,
  2927. // just note the fact and don't copy the ACE.
  2928. //
  2929. if ( *AcePosition == NULL ||
  2930. LengthRequired > (ULONG)NewAcl->AclSize - ((PUCHAR)(*AcePosition) - (PUCHAR)NewAcl) ) {
  2931. *AclOverflowed = TRUE;
  2932. } else {
  2933. PUCHAR Target;
  2934. //
  2935. // Copy individual parts of the ACE separately.
  2936. //
  2937. Target = (PUCHAR)*AcePosition;
  2938. RtlCopyMemory(
  2939. Target,
  2940. AceHeaderToCopy,
  2941. AceHeaderToCopyLength );
  2942. Target += AceHeaderToCopyLength;
  2943. //
  2944. // Now copy the correct server SID
  2945. //
  2946. if ( ServerSidToCopy != NULL ) {
  2947. RtlCopyMemory(
  2948. Target,
  2949. ServerSidToCopy,
  2950. SeLengthSid(ServerSidToCopy)
  2951. );
  2952. Target += SeLengthSid(ServerSidToCopy);
  2953. }
  2954. //
  2955. // Now copy the correct SID
  2956. //
  2957. RtlCopyMemory(
  2958. Target,
  2959. SidToCopy,
  2960. SeLengthSid(SidToCopy)
  2961. );
  2962. Target += SeLengthSid(SidToCopy);
  2963. //
  2964. // Set the size of the ACE accordingly
  2965. //
  2966. if ( LengthRequired < (ULONG)(Target - (PUCHAR)*AcePosition) ) {
  2967. return FALSE;
  2968. }
  2969. LengthRequired = (ULONG)(Target - (PUCHAR)*AcePosition);
  2970. ((PKNOWN_ACE)*AcePosition)->Header.AceSize =
  2971. (USHORT)LengthRequired;
  2972. //
  2973. // Put the mapped access mask in the new ACE
  2974. //
  2975. ((PKNOWN_ACE)*AcePosition)->Mask = LocalMask;
  2976. }
  2977. }
  2978. }
  2979. } else {
  2980. //
  2981. // If the ACE doesn't fit,
  2982. // just note the fact and don't copy the ACE.
  2983. //
  2984. if ( LengthRequired > (ULONG)NewAcl->AclSize - ((PUCHAR)*AcePosition - (PUCHAR)NewAcl) ) {
  2985. *AclOverflowed = TRUE;
  2986. } else {
  2987. //
  2988. // Not a known ACE type, copy ACE as is
  2989. //
  2990. RtlCopyMemory(
  2991. *AcePosition,
  2992. OldAce,
  2993. LengthRequired );
  2994. }
  2995. }
  2996. //
  2997. // If the ACE was actually kept, clear all the inherit flags
  2998. // and update the ACE count of the ACL.
  2999. //
  3000. if ( !*AclOverflowed && LengthRequired != 0 ) {
  3001. ((PACE_HEADER)*AcePosition)->AceFlags &= ~VALID_INHERIT_FLAGS;
  3002. if ( AutoInherit ) {
  3003. ((PACE_HEADER)*AcePosition)->AceFlags |= INHERITED_ACE;
  3004. }
  3005. NewAcl->AceCount += 1;
  3006. }
  3007. //
  3008. // We have the length of the new ACE, but we've calculated
  3009. // it with a ULONG. It must fit into a USHORT. See if it
  3010. // does.
  3011. //
  3012. if (LengthRequired > 0xFFFF) {
  3013. return FALSE;
  3014. }
  3015. //
  3016. // Move the Ace Position to where the next ACE goes.
  3017. //
  3018. if ( !*AclOverflowed ) {
  3019. *AcePosition = ((PUCHAR)*AcePosition) + LengthRequired;
  3020. }
  3021. //
  3022. // Now return to our caller
  3023. //
  3024. (*NewAceLength) = LengthRequired;
  3025. return TRUE;
  3026. }
  3027. #ifndef WIN16
  3028. NTSTATUS
  3029. RtlpCopyAces(
  3030. IN PACL Acl,
  3031. IN PGENERIC_MAPPING GenericMapping,
  3032. IN ACE_TYPE_TO_COPY AceTypeToCopy,
  3033. IN UCHAR AceFlagsToReset,
  3034. IN BOOLEAN MapSids,
  3035. IN PSID ClientOwnerSid,
  3036. IN PSID ClientGroupSid,
  3037. IN PSID ServerOwnerSid OPTIONAL,
  3038. IN PSID ServerGroupSid OPTIONAL,
  3039. IN BOOLEAN IsDirectoryObject,
  3040. IN BOOLEAN RetainInheritedAceBit,
  3041. OUT PULONG NewAclSizeParam,
  3042. OUT PACL NewAcl
  3043. )
  3044. /*++
  3045. Routine Description:
  3046. Copy ACEs from of an ACL and perform generic mapping. Only ACEs specified
  3047. by 'AceFilter' are copied.
  3048. Arguments:
  3049. Acl - Supplies the ACL to copy from.
  3050. GenericMapping - Specifies the generic mapping to use.
  3051. AceTypeToCopy - Describes which aces to copy.
  3052. AceFlagsToReset - Bit mask of ACE flags to reset (if set) on each ACE.
  3053. MapSids - TRUE if the SID in the ACE is to be mapped to the corresponding
  3054. actual SID.
  3055. ClientOwnerSid - Specifies the owner Sid to use
  3056. ClientGroupSid - Specifies the new Group Sid to use
  3057. ServerOwnerSid - Optionally specifies the Server Sid to use in compound ACEs.
  3058. ServerGroupSid - Optionally specifies the Server group Sid to use in compound ACEs.
  3059. IsDirectoryObject - Whether the object is a container or a non-container
  3060. RetainInheritedAceBit - Whether to retain INHERITED_ACE bit for effective aces.
  3061. NewAclSizeParam - Receives the cumulatiave length of the copies ACEs
  3062. NewAcl - Provides a pointer to the ACL to copy to.
  3063. This ACL must already be initialized.
  3064. Return Value:
  3065. STATUS_SUCCESS - An inheritable ACL has been generated.
  3066. STATUS_BUFFER_TOO_SMALL - The ACL specified by NewAcl is too small for the
  3067. copied ACEs. The required size is returned in NewAceLength.
  3068. --*/
  3069. {
  3070. NTSTATUS Status;
  3071. ULONG i;
  3072. PACE_HEADER OldAce;
  3073. ULONG NewAclSize, NewAceSize;
  3074. BOOLEAN AclOverflowed = FALSE;
  3075. BOOLEAN CopyAce;
  3076. PVOID AcePosition;
  3077. BOOLEAN LocalAutoInherit = FALSE;
  3078. RTL_PAGED_CODE();
  3079. //
  3080. // Validate the ACL.
  3081. //
  3082. if ( !ValidAclRevision(NewAcl) ) {
  3083. return STATUS_UNKNOWN_REVISION;
  3084. }
  3085. //
  3086. // Find where the first ACE goes.
  3087. //
  3088. if (!RtlFirstFreeAce( NewAcl, &AcePosition )) {
  3089. return STATUS_BAD_INHERITANCE_ACL;
  3090. }
  3091. //
  3092. // Walk through the original ACL copying ACEs.
  3093. //
  3094. NewAclSize = 0;
  3095. for (i = 0, OldAce = FirstAce(Acl);
  3096. i < Acl->AceCount;
  3097. i += 1, OldAce = NextAce(OldAce)) {
  3098. //
  3099. // If the ACE wasn't inherited,
  3100. // copy it.
  3101. //
  3102. switch (AceTypeToCopy) {
  3103. case CopyInheritedAces:
  3104. CopyAce = AceInherited(OldAce);
  3105. break;
  3106. case CopyNonInheritedAces:
  3107. CopyAce = !AceInherited(OldAce);
  3108. break;
  3109. case CopyAllAces:
  3110. CopyAce = TRUE;
  3111. break;
  3112. default:
  3113. CopyAce = FALSE;
  3114. break;
  3115. }
  3116. if ( CopyAce ) {
  3117. //
  3118. // If SIDs are to be mapped,
  3119. // do so (and potentially create up to two ACEs).
  3120. //
  3121. if ( MapSids ) {
  3122. PVOID TempAcePosition;
  3123. ULONG EffectiveAceSize = 0;
  3124. BOOLEAN EffectiveAceMapped;
  3125. BOOLEAN GenerateInheritAce;
  3126. //
  3127. // Remember where the next ACE will be copied.
  3128. //
  3129. TempAcePosition = AcePosition;
  3130. NewAceSize = 0;
  3131. GenerateInheritAce = IsDirectoryObject &&
  3132. ((((PACE_HEADER)OldAce)->AceFlags & (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE)) != 0);
  3133. //
  3134. // If the orginal ACE is an effective ACE,
  3135. // create an effective ACE.
  3136. //
  3137. if ( !(((PACE_HEADER)OldAce)->AceFlags & INHERIT_ONLY_ACE)) {
  3138. BOOLEAN LocalAclOverflowed;
  3139. //
  3140. // If the ace has INHERITED_ACE bit and the caller has requested
  3141. // preservation of the bit, copy the effective ace as an
  3142. // INHERITED_ACE.
  3143. //
  3144. LocalAutoInherit = FALSE;
  3145. if ( RetainInheritedAceBit ) {
  3146. if ( OldAce->AceFlags & INHERITED_ACE) {
  3147. LocalAutoInherit = TRUE;
  3148. }
  3149. }
  3150. //
  3151. // Copy the effective ACE into the ACL.
  3152. //
  3153. if ( !RtlpCopyEffectiveAce (
  3154. OldAce,
  3155. LocalAutoInherit,
  3156. GenerateInheritAce,
  3157. ClientOwnerSid,
  3158. ClientGroupSid,
  3159. ServerOwnerSid,
  3160. ServerGroupSid,
  3161. GenericMapping,
  3162. NULL, // Always copy object ACES
  3163. 0,
  3164. &TempAcePosition,
  3165. &EffectiveAceSize,
  3166. NewAcl,
  3167. NULL, // Always copy object ACES
  3168. &EffectiveAceMapped,
  3169. &LocalAclOverflowed ) ) {
  3170. return STATUS_BAD_INHERITANCE_ACL;
  3171. }
  3172. if (LocalAclOverflowed) {
  3173. AclOverflowed = TRUE;
  3174. }
  3175. NewAceSize += EffectiveAceSize;
  3176. //
  3177. // Reset any undesirable AceFlags.
  3178. //
  3179. if ( !AclOverflowed ) {
  3180. ((PACE_HEADER)AcePosition)->AceFlags &= ~AceFlagsToReset;
  3181. }
  3182. }
  3183. //
  3184. // If the original ACE is inheritable,
  3185. // create an inheritable ACE.
  3186. //
  3187. // ASSERT: AcePosition points to where the effective ACE was copied
  3188. // ASSERT: TempAcePosition points to where the inheritable ACE should be copied
  3189. //
  3190. if ( GenerateInheritAce ) {
  3191. //
  3192. // If a effective ACE was created,
  3193. // and it wasn't mapped,
  3194. // avoid generating another ACE and simply merge the inheritance bits into
  3195. // the effective ACE.
  3196. //
  3197. if ( EffectiveAceSize != 0 && !EffectiveAceMapped ) {
  3198. //
  3199. // Copy the inherit bits from the original ACE.
  3200. //
  3201. if ( !AclOverflowed ) {
  3202. ((PACE_HEADER)AcePosition)->AceFlags |=
  3203. ((PACE_HEADER)OldAce)->AceFlags & (VALID_INHERIT_FLAGS);
  3204. ((PACE_HEADER)AcePosition)->AceFlags &= ~AceFlagsToReset;
  3205. }
  3206. //
  3207. // Otherwise, generate an explicit inheritance ACE.
  3208. //
  3209. // But only if the access mask isn't zero.
  3210. //
  3211. } else if ( !IsMSAceType(OldAce) || ((PKNOWN_ACE)(OldAce))->Mask != 0 ) {
  3212. //
  3213. // Account for the new ACE being added to the ACL.
  3214. //
  3215. NewAceSize += (ULONG)(((PACE_HEADER)OldAce)->AceSize);
  3216. if (NewAceSize > 0xFFFF) {
  3217. return STATUS_BAD_INHERITANCE_ACL;
  3218. }
  3219. //
  3220. // If the ACE doesn't fit,
  3221. // just note the fact and don't copy the ACE.
  3222. //
  3223. if ( ((PACE_HEADER)OldAce)->AceSize > NewAcl->AclSize - ((PUCHAR)TempAcePosition - (PUCHAR)NewAcl) ) {
  3224. AclOverflowed = TRUE;
  3225. } else {
  3226. //
  3227. // copy it as is, but make sure the InheritOnly bit is set.
  3228. //
  3229. if ( !AclOverflowed ) {
  3230. RtlCopyMemory(
  3231. TempAcePosition,
  3232. OldAce,
  3233. ((PACE_HEADER)OldAce)->AceSize
  3234. );
  3235. ((PACE_HEADER)TempAcePosition)->AceFlags |= INHERIT_ONLY_ACE;
  3236. ((PACE_HEADER)TempAcePosition)->AceFlags &= ~AceFlagsToReset;
  3237. NewAcl->AceCount += 1;
  3238. }
  3239. }
  3240. }
  3241. }
  3242. } else {
  3243. NewAceSize = (ULONG)OldAce->AceSize;
  3244. //
  3245. // If the ACE doesn't fit,
  3246. // just note the fact and don't copy the ACE.
  3247. //
  3248. if ( AcePosition == NULL ||
  3249. NewAceSize > (ULONG)NewAcl->AclSize - ((PUCHAR)AcePosition - (PUCHAR)NewAcl) ) {
  3250. AclOverflowed = TRUE;
  3251. } else if ( !AclOverflowed ) {
  3252. //
  3253. // Copy the ACE.
  3254. //
  3255. RtlCopyMemory(
  3256. AcePosition,
  3257. OldAce,
  3258. NewAceSize );
  3259. //
  3260. // Map the generic bits.
  3261. //
  3262. // Is it really right to map the generic bits on an ACE
  3263. // that's both effective and inheritable. Shouldn't this
  3264. // be split into two ACEs in that case? Or just skip the mapping?
  3265. //
  3266. if (IsMSAceType( AcePosition )) {
  3267. RtlApplyAceToObject( (PACE_HEADER)AcePosition, GenericMapping );
  3268. }
  3269. //
  3270. // Reset any undesirable AceFlags.
  3271. //
  3272. ((PACE_HEADER)AcePosition)->AceFlags &= ~AceFlagsToReset;
  3273. //
  3274. // Account for the new ACE.
  3275. //
  3276. NewAcl->AceCount += 1;
  3277. }
  3278. }
  3279. //
  3280. // Move the Ace Position to where the next ACE goes.
  3281. //
  3282. if ( !AclOverflowed ) {
  3283. AcePosition = ((PUCHAR)AcePosition) + NewAceSize;
  3284. } else {
  3285. // On overflow, ensure no other ACEs are actually output to the buffer
  3286. AcePosition = ((PUCHAR)NewAcl) + NewAcl->AclSize;
  3287. }
  3288. NewAclSize += NewAceSize;
  3289. }
  3290. }
  3291. //
  3292. // We have the length of the new ACE, but we've calculated
  3293. // it with a ULONG. It must fit into a USHORT. See if it
  3294. // does.
  3295. //
  3296. if (NewAclSize > 0xFFFF) {
  3297. return STATUS_BAD_INHERITANCE_ACL;
  3298. }
  3299. (*NewAclSizeParam) = NewAclSize;
  3300. return AclOverflowed ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
  3301. }
  3302. NTSTATUS
  3303. RtlpInheritAcl2 (
  3304. IN PACL DirectoryAcl,
  3305. IN PACL ChildAcl,
  3306. IN ULONG ChildGenericControl,
  3307. IN BOOLEAN IsDirectoryObject,
  3308. IN BOOLEAN AutoInherit,
  3309. IN BOOLEAN DefaultDescriptorForObject,
  3310. IN PSID OwnerSid,
  3311. IN PSID GroupSid,
  3312. IN PSID ServerOwnerSid OPTIONAL,
  3313. IN PSID ServerGroupSid OPTIONAL,
  3314. IN PGENERIC_MAPPING GenericMapping,
  3315. IN BOOLEAN IsSacl,
  3316. IN GUID **pNewObjectType OPTIONAL,
  3317. IN ULONG GuidCount,
  3318. IN PULONG AclBufferSize,
  3319. IN OUT PUCHAR AclBuffer,
  3320. OUT PBOOLEAN NewAclExplicitlyAssigned,
  3321. OUT PULONG NewGenericControl
  3322. )
  3323. /*++
  3324. Routine Description:
  3325. This is a private routine that produces an inherited acl from
  3326. a parent acl according to the rules of inheritance
  3327. Arguments:
  3328. DirectoryAcl - Supplies the acl being inherited.
  3329. ChildAcl - Supplies the acl associated with the object. This
  3330. is either the current acl on the object or the acl being assigned
  3331. to the object.
  3332. ChildGenericControl - Specifies the control flags from the SecurityDescriptor
  3333. describing the ChildAcl:
  3334. SEP_ACL_PRESENT: Specifies that the child ACL is explictly supplied by
  3335. the caller.
  3336. SEP_ACL_DEFAULTED: Specifies that the child ACL was supplied by some
  3337. defaulting mechanism.
  3338. SEP_ACL_PROTECTED: Specifies that the child ACL is protected and
  3339. should not inherit any ACE from the DirectoryACL
  3340. IsDirectoryObject - Specifies if the new acl is for a directory.
  3341. AutoInherit - Specifies if the inheritance is an "automatic inheritance".
  3342. As such, the non-inherited ACEs from the ChildAcl will be preserved and
  3343. the inherited ACEs from the DirectoryAcl will be marked as such.
  3344. DefaultDescriptorForObject - If set, the CreatorDescriptor
  3345. is the default descriptor for ObjectType. As such, the
  3346. CreatorDescriptor will be ignored if any ObjectType specific
  3347. ACEs are inherited from the parent. If not such ACEs are inherited,
  3348. the CreatorDescriptor is handled as though this flag were not
  3349. specified.
  3350. OwnerSid - Specifies the owner Sid to use.
  3351. GroupSid - Specifies the group SID to use.
  3352. GenericMapping - Specifies the generic mapping to use.
  3353. IsSacl - True if this is the SACL. False if this is the DACL.
  3354. pNewObjectType - List of types of object being inherited to. If not
  3355. specified, the object has no object type.
  3356. GuidCount - Number of object types in the list.
  3357. AclBufferSize - On input, specifies the size of AclBuffer.
  3358. On output, on success, returns the used size of AclBuffer.
  3359. On output, if the buffer is too small, returns the required size of AclBuffer.
  3360. AclBuffer - Receives a pointer to the new (inherited) acl.
  3361. NewAclExplicitlyAssigned - Returns true to indicate that some portion of
  3362. "NewAcl" was derived from an the explicit ChildAcl
  3363. NewGenericControl - Specifies the control flags for the newly
  3364. generated ACL.
  3365. SEP_ACL_AUTO_INHERITED: Set if the ACL was generated using the
  3366. Automatic Inheritance algorithm.
  3367. SEP_ACL_PROTECTED: Specifies that the ACL is protected and
  3368. was not inherited from the parent ACL.
  3369. Return Value:
  3370. STATUS_SUCCESS - An inheritable ACL was successfully generated.
  3371. STATUS_NO_INHERITANCE - An inheritable ACL was not successfully generated.
  3372. This is a warning completion status. The caller should use the default
  3373. ACL.
  3374. STATUS_BAD_INHERITANCE_ACL - Indicates the acl built was not a valid ACL.
  3375. This can becaused by a number of things. One of the more probable
  3376. causes is the replacement of a CreatorId with an SID that didn't fit
  3377. into the ACE or ACL.
  3378. STATUS_UNKNOWN_REVISION - Indicates the source ACL is a revision that
  3379. is unknown to this routine.
  3380. STATUS_BUFFER_TOO_SMALL - The ACL specified by NewAcl is too small for the
  3381. inheritance ACEs. The required size is returned in AclBufferSize.
  3382. --*/
  3383. {
  3384. NTSTATUS Status;
  3385. ULONG ChildNewAclSize = 0;
  3386. ULONG UsedChildNewAclSize = 0;
  3387. ULONG DirectoryNewAclSize = 0;
  3388. ULONG AclRevision;
  3389. USHORT ChildAceCount;
  3390. PVOID ChildAcePosition;
  3391. PVOID DirectoryAcePosition;
  3392. BOOLEAN AclOverflowed = FALSE;
  3393. BOOLEAN AclProtected = FALSE;
  3394. BOOLEAN NullAclOk = TRUE;
  3395. BOOLEAN ObjectAceInherited;
  3396. RTL_PAGED_CODE();
  3397. //
  3398. // Assume the ACL revision.
  3399. //
  3400. AclRevision = ACL_REVISION;
  3401. RtlCreateAcl( (PACL)AclBuffer, *AclBufferSize, AclRevision );
  3402. *NewAclExplicitlyAssigned = FALSE;
  3403. *NewGenericControl = AutoInherit ? SEP_ACL_AUTO_INHERITED : 0;
  3404. //
  3405. // If the a current child ACL is not defaulted,
  3406. // the non-inherited ACEs from the current child ACL are to be preserved.
  3407. //
  3408. if ( (ChildGenericControl & SEP_ACL_DEFAULTED) == 0 ) {
  3409. //
  3410. // The resultant ACL should be protected if the input ACL is
  3411. // protected.
  3412. //
  3413. if ( ChildGenericControl & SEP_ACL_PROTECTED ) {
  3414. AclProtected = TRUE;
  3415. *NewGenericControl |= SEP_ACL_PROTECTED;
  3416. }
  3417. //
  3418. // Only copy ACEs if the child ACL is actually present.
  3419. //
  3420. if ( (ChildGenericControl & (SEP_ACL_PRESENT|SEP_ACL_PROTECTED)) != 0 ) {
  3421. if ( ChildAcl != NULL ) {
  3422. ACE_TYPE_TO_COPY AceTypeToCopy;
  3423. UCHAR AceFlagsToReset;
  3424. BOOLEAN MapSids;
  3425. AclRevision = max( AclRevision, ChildAcl->AclRevision );
  3426. //
  3427. // Since we're explicitly using the ACL specified by the caller,
  3428. // we never want to return a NULL ACL.
  3429. // Rather, if we have an ACL with no ACEs,
  3430. // we'll return exactly that. For a DACL, that results
  3431. // in a DACL that grants no access rather than a DACL
  3432. // that grants all access.
  3433. //
  3434. NullAclOk = FALSE;
  3435. //
  3436. // If the caller doesn't understand auto inheritance,
  3437. // simply preserve the specified ACL 100% intact.
  3438. //
  3439. if ( !AutoInherit ) {
  3440. AceTypeToCopy = CopyAllAces;
  3441. AceFlagsToReset = 0; // Don't turn off any ACE Flags
  3442. MapSids = FALSE; // For backward compatibility
  3443. //
  3444. // If the child is protected,
  3445. // keep all of the ACEs turning off the INHERITED ACE flags.
  3446. //
  3447. } else if ( ChildGenericControl & SEP_ACL_PROTECTED ) {
  3448. AceTypeToCopy = CopyAllAces;
  3449. AceFlagsToReset = INHERITED_ACE; // Turn off all INHERITED_ACE flags
  3450. MapSids = TRUE;
  3451. //
  3452. // If the child is not protected,
  3453. // just copy the non-inherited ACEs.
  3454. //
  3455. // (The inherited ACEs will be recomputed from the parent.)
  3456. //
  3457. } else {
  3458. AceTypeToCopy = CopyNonInheritedAces;
  3459. AceFlagsToReset = 0; // Don't turn off any ACE Flags
  3460. MapSids = TRUE;
  3461. }
  3462. //
  3463. // Copy the requested ACEs.
  3464. //
  3465. Status = RtlpCopyAces(
  3466. ChildAcl,
  3467. GenericMapping,
  3468. AceTypeToCopy,
  3469. AceFlagsToReset,
  3470. MapSids,
  3471. OwnerSid,
  3472. GroupSid,
  3473. ServerOwnerSid,
  3474. ServerGroupSid,
  3475. IsDirectoryObject,
  3476. FALSE, // Do not retain INHERITED_ACE bit for effective aces
  3477. &ChildNewAclSize,
  3478. (PACL)AclBuffer );
  3479. UsedChildNewAclSize = ChildNewAclSize;
  3480. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  3481. AclOverflowed = TRUE;
  3482. Status = STATUS_SUCCESS;
  3483. }
  3484. if ( !NT_SUCCESS(Status) ) {
  3485. return Status;
  3486. }
  3487. //
  3488. // If this ACL might be ignored later,
  3489. // remember the current state of the ACL.
  3490. //
  3491. if ( DefaultDescriptorForObject && ChildNewAclSize != 0 ) {
  3492. ChildAceCount = ((PACL)AclBuffer)->AceCount;
  3493. if (!RtlFirstFreeAce( (PACL)AclBuffer, &ChildAcePosition ) ) {
  3494. return STATUS_BAD_INHERITANCE_ACL;
  3495. }
  3496. }
  3497. //
  3498. // If the ACL isn't protected,
  3499. // don't allow NULL ACL semantics.
  3500. // (those semantics are ambiguous for auto inheritance)
  3501. //
  3502. } else if ( AutoInherit &&
  3503. !IsSacl &&
  3504. (ChildGenericControl & (SEP_ACL_PRESENT|SEP_ACL_PROTECTED)) == SEP_ACL_PRESENT ) {
  3505. return STATUS_INVALID_ACL;
  3506. }
  3507. *NewAclExplicitlyAssigned = TRUE;
  3508. }
  3509. }
  3510. //
  3511. // Inherit ACEs from the Directory ACL in any of the following cases:
  3512. // If !AutoInheriting,
  3513. // Inherit if there is no explicit child ACL (ignoring a defaulted child).
  3514. // If AutoInheriting,
  3515. // observe the protected flag.
  3516. //
  3517. if ( (!AutoInherit &&
  3518. (ChildGenericControl & SEP_ACL_PRESENT) == 0 ||
  3519. (ChildGenericControl & SEP_ACL_DEFAULTED) != 0) ||
  3520. (AutoInherit && !AclProtected) ) {
  3521. //
  3522. // If there is no directory ACL,
  3523. // don't inherit from it.
  3524. //
  3525. if ( DirectoryAcl != NULL ) {
  3526. //
  3527. // If the DirectoryAcl is used,
  3528. // the revision of the Directory ACL is picked up.
  3529. //
  3530. if ( !ValidAclRevision(DirectoryAcl) ) {
  3531. return STATUS_UNKNOWN_REVISION;
  3532. }
  3533. AclRevision = max( AclRevision, DirectoryAcl->AclRevision );
  3534. //
  3535. // Inherit the Parent's ACL.
  3536. //
  3537. Status = RtlpGenerateInheritAcl(
  3538. DirectoryAcl,
  3539. IsDirectoryObject,
  3540. AutoInherit,
  3541. OwnerSid,
  3542. GroupSid,
  3543. ServerOwnerSid,
  3544. ServerGroupSid,
  3545. GenericMapping,
  3546. pNewObjectType,
  3547. GuidCount,
  3548. &DirectoryNewAclSize,
  3549. (PACL)AclBuffer,
  3550. &ObjectAceInherited );
  3551. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  3552. AclOverflowed = TRUE;
  3553. Status = STATUS_SUCCESS;
  3554. }
  3555. if ( !NT_SUCCESS(Status) ) {
  3556. return Status;
  3557. }
  3558. //
  3559. // If the default descriptor for the object should be ditched,
  3560. // because object specific ACEs were inherited from the directory,
  3561. // ditch them now.
  3562. //
  3563. if ( DefaultDescriptorForObject &&
  3564. ChildNewAclSize != 0 &&
  3565. ObjectAceInherited &&
  3566. !AclOverflowed ) {
  3567. //
  3568. // Compute the last used byte of the combined ACL
  3569. //
  3570. if (!RtlFirstFreeAce( (PACL)AclBuffer, &DirectoryAcePosition ) ) {
  3571. return STATUS_BAD_INHERITANCE_ACL;
  3572. }
  3573. if ( DirectoryAcePosition == NULL ) {
  3574. DirectoryAcePosition = AclBuffer + ((PACL)AclBuffer)->AclSize;
  3575. }
  3576. //
  3577. // Move all the inherited ACEs to the front of the ACL.
  3578. //
  3579. RtlMoveMemory( FirstAce( AclBuffer ),
  3580. ChildAcePosition,
  3581. (ULONG)(((PUCHAR)DirectoryAcePosition) -
  3582. (PUCHAR)ChildAcePosition) );
  3583. //
  3584. // Adjust the ACE count to remove the deleted ACEs
  3585. //
  3586. ((PACL)AclBuffer)->AceCount -= ChildAceCount;
  3587. //
  3588. // Save the number of bytes of the Child ACL that were
  3589. // actually used.
  3590. //
  3591. UsedChildNewAclSize = 0;
  3592. }
  3593. }
  3594. }
  3595. //
  3596. // If this routine didn't build the ACL,
  3597. // tell the caller.
  3598. //
  3599. if ( DirectoryNewAclSize + UsedChildNewAclSize == 0) {
  3600. //
  3601. // If the ACL was not explicitly assigned,
  3602. // tell the caller to default the ACL.
  3603. //
  3604. if ( !(*NewAclExplicitlyAssigned) ) {
  3605. *AclBufferSize = 0;
  3606. return STATUS_NO_INHERITANCE;
  3607. //
  3608. // If the Acl was explictly assigned,
  3609. // generate a NULL ACL based on the path taken above.
  3610. //
  3611. } else if ( NullAclOk ) {
  3612. *AclBufferSize = 0;
  3613. return STATUS_SUCCESS;
  3614. }
  3615. // DbgBreakPoint();
  3616. }
  3617. //
  3618. // And make sure we don't exceed the length limitations of an ACL (WORD)
  3619. //
  3620. if ( DirectoryNewAclSize + UsedChildNewAclSize + sizeof(ACL) > 0xFFFF) {
  3621. return(STATUS_BAD_INHERITANCE_ACL);
  3622. }
  3623. // The caller has to allocate a buffer large enough for
  3624. // ChildNewAclSize rather than UsedChildNewAclSize. Due to the nature of
  3625. // my algorithm above.
  3626. (*AclBufferSize) = DirectoryNewAclSize + ChildNewAclSize + sizeof(ACL);
  3627. if ( AclOverflowed ) {
  3628. return STATUS_BUFFER_TOO_SMALL;
  3629. }
  3630. //
  3631. // Patch the real ACL size and revision into the ACL
  3632. //
  3633. ((PACL)AclBuffer)->AclSize = (USHORT)
  3634. (DirectoryNewAclSize + UsedChildNewAclSize + sizeof(ACL));
  3635. ((PACL)AclBuffer)->AclRevision = (UCHAR) AclRevision;
  3636. return STATUS_SUCCESS;
  3637. }
  3638. NTSTATUS
  3639. RtlpInheritAcl (
  3640. IN PACL DirectoryAcl,
  3641. IN PACL ChildAcl,
  3642. IN ULONG ChildGenericControl,
  3643. IN BOOLEAN IsDirectoryObject,
  3644. IN BOOLEAN AutoInherit,
  3645. IN BOOLEAN DefaultDescriptorForObject,
  3646. IN PSID OwnerSid,
  3647. IN PSID GroupSid,
  3648. IN PSID ServerOwnerSid OPTIONAL,
  3649. IN PSID ServerGroupSid OPTIONAL,
  3650. IN PGENERIC_MAPPING GenericMapping,
  3651. IN BOOLEAN IsSacl,
  3652. IN GUID **pNewObjectType OPTIONAL,
  3653. IN ULONG GuidCount,
  3654. OUT PACL *NewAcl,
  3655. OUT PBOOLEAN NewAclExplicitlyAssigned,
  3656. OUT PULONG NewGenericControl
  3657. )
  3658. /*++
  3659. Routine Description:
  3660. This is a private routine that produces an inherited acl from
  3661. a parent acl according to the rules of inheritance
  3662. Arguments:
  3663. DirectoryAcl - Supplies the acl being inherited.
  3664. ChildAcl - Supplies the acl associated with the object. This
  3665. is either the current acl on the object or the acl being assigned
  3666. to the object.
  3667. ChildGenericControl - Specifies the control flags from the SecurityDescriptor
  3668. describing the ChildAcl:
  3669. SEP_ACL_PRESENT: Specifies that the child ACL is explictly supplied by
  3670. the caller.
  3671. SEP_ACL_DEFAULTED: Specifies that the child ACL was supplied by some
  3672. defaulting mechanism.
  3673. SEP_ACL_PROTECTED: Specifies that the child ACL is protected and
  3674. should not inherit any ACE from the DirectoryACL
  3675. IsDirectoryObject - Specifies if the new acl is for a directory.
  3676. AutoInherit - Specifies if the inheritance is an "automatic inheritance".
  3677. As such, the non-inherited ACEs from the ChildAcl will be preserved and
  3678. the inherited ACEs from the DirectoryAcl will be marked as such.
  3679. DefaultDescriptorForObject - If set, the CreatorDescriptor
  3680. is the default descriptor for ObjectType. As such, the
  3681. CreatorDescriptor will be ignored if any ObjectType specific
  3682. ACEs are inherited from the parent. If not such ACEs are inherited,
  3683. the CreatorDescriptor is handled as though this flag were not
  3684. specified.
  3685. OwnerSid - Specifies the owner Sid to use.
  3686. GroupSid - Specifies the group SID to use.
  3687. GenericMapping - Specifies the generic mapping to use.
  3688. IsSacl - True if this is the SACL. False if this is the DACL.
  3689. pNewObjectType - List of types of object being inherited to. If not
  3690. specified, the object has no object type.
  3691. GuidCount - Number of object types in the list.
  3692. NewAcl - Receives a pointer to the new (inherited) acl.
  3693. NewAclExplicitlyAssigned - Returns true to indicate that some portion of
  3694. "NewAcl" was derived from an the explicit ChildAcl
  3695. NewGenericControl - Specifies the control flags for the newly
  3696. generated ACL.
  3697. SEP_ACL_AUTO_INHERITED: Set if the ACL was generated using the
  3698. Automatic Inheritance algorithm.
  3699. SEP_ACL_PROTECTED: Specifies that the ACL is protected and
  3700. was not inherited from the parent ACL.
  3701. Return Value:
  3702. STATUS_SUCCESS - An inheritable ACL was successfully generated.
  3703. STATUS_NO_INHERITANCE - An inheritable ACL was not successfully generated.
  3704. This is a warning completion status.
  3705. STATUS_BAD_INHERITANCE_ACL - Indicates the acl built was not a valid ACL.
  3706. This can becaused by a number of things. One of the more probable
  3707. causes is the replacement of a CreatorId with an SID that didn't fit
  3708. into the ACE or ACL.
  3709. STATUS_UNKNOWN_REVISION - Indicates the source ACL is a revision that
  3710. is unknown to this routine.
  3711. --*/
  3712. {
  3713. //////////////////////////////////////////////////////////////////////////////
  3714. // //
  3715. // The logic in the ACL inheritance code must mirror the code for //
  3716. // inheritance in the executive (in seassign.c). Do not make changes //
  3717. // here without also making changes in that module. //
  3718. // //
  3719. //////////////////////////////////////////////////////////////////////////////
  3720. NTSTATUS Status;
  3721. ULONG AclBufferSize;
  3722. ULONG i;
  3723. #ifndef NTOS_KERNEL_RUNTIME
  3724. PVOID HeapHandle;
  3725. #endif // NTOS_KERNEL_RUNTIME
  3726. RTL_PAGED_CODE();
  3727. //
  3728. // Get the handle to the current process heap
  3729. //
  3730. #ifndef NTOS_KERNEL_RUNTIME
  3731. HeapHandle = RtlProcessHeap();
  3732. #endif // NTOS_KERNEL_RUNTIME
  3733. //
  3734. // Implement a two pass strategy.
  3735. //
  3736. // First try to create the ACL in a fixed length buffer.
  3737. // If that is too small,
  3738. // then use the buffer size determined on the first pass
  3739. //
  3740. AclBufferSize = 1024; // Typical maximum size of an ACL
  3741. for ( i=0; i<2 ; i++ ) {
  3742. //
  3743. // Allocate heap for the new ACL.
  3744. //
  3745. #ifdef NTOS_KERNEL_RUNTIME
  3746. (*NewAcl) = ExAllocatePoolWithTag(
  3747. PagedPool,
  3748. AclBufferSize,
  3749. 'cAeS' );
  3750. #else // NTOS_KERNEL_RUNTIME
  3751. (*NewAcl) = RtlAllocateHeap(
  3752. HeapHandle,
  3753. MAKE_TAG(SE_TAG),
  3754. AclBufferSize );
  3755. #endif // NTOS_KERNEL_RUNTIME
  3756. if ((*NewAcl) == NULL ) {
  3757. return( STATUS_NO_MEMORY );
  3758. }
  3759. //
  3760. // Actually build the inherited ACL.
  3761. //
  3762. Status = RtlpInheritAcl2 (
  3763. DirectoryAcl,
  3764. ChildAcl,
  3765. ChildGenericControl,
  3766. IsDirectoryObject,
  3767. AutoInherit,
  3768. DefaultDescriptorForObject,
  3769. OwnerSid,
  3770. GroupSid,
  3771. ServerOwnerSid,
  3772. ServerGroupSid,
  3773. GenericMapping,
  3774. IsSacl,
  3775. pNewObjectType,
  3776. GuidCount,
  3777. &AclBufferSize,
  3778. (PUCHAR) *NewAcl,
  3779. NewAclExplicitlyAssigned,
  3780. NewGenericControl );
  3781. if ( NT_SUCCESS(Status) ) {
  3782. //
  3783. // If a NULL ACL should be used,
  3784. // tell the caller.
  3785. //
  3786. if ( AclBufferSize == 0 ) {
  3787. #ifdef NTOS_KERNEL_RUNTIME
  3788. ExFreePool( *NewAcl );
  3789. #else // NTOS_KERNEL_RUNTIME
  3790. RtlFreeHeap( HeapHandle, 0, *NewAcl );
  3791. #endif // NTOS_KERNEL_RUNTIME
  3792. *NewAcl = NULL;
  3793. }
  3794. break;
  3795. } else {
  3796. #ifdef NTOS_KERNEL_RUNTIME
  3797. ExFreePool( *NewAcl );
  3798. #else // NTOS_KERNEL_RUNTIME
  3799. RtlFreeHeap( HeapHandle, 0, *NewAcl );
  3800. #endif // NTOS_KERNEL_RUNTIME
  3801. *NewAcl = NULL;
  3802. if ( Status != STATUS_BUFFER_TOO_SMALL ) {
  3803. break;
  3804. }
  3805. }
  3806. }
  3807. return Status;
  3808. }
  3809. NTSTATUS
  3810. RtlpGenerateInheritedAce (
  3811. IN PACE_HEADER OldAce,
  3812. IN BOOLEAN IsDirectoryObject,
  3813. IN BOOLEAN AutoInherit,
  3814. IN PSID ClientOwnerSid,
  3815. IN PSID ClientGroupSid,
  3816. IN PSID ServerOwnerSid OPTIONAL,
  3817. IN PSID ServerGroupSid OPTIONAL,
  3818. IN PGENERIC_MAPPING GenericMapping,
  3819. IN GUID **pNewObjectType OPTIONAL,
  3820. IN ULONG GuidCount,
  3821. OUT PULONG NewAceLength,
  3822. OUT PACL NewAcl,
  3823. OUT PULONG NewAceExtraLength,
  3824. OUT PBOOLEAN ObjectAceInherited
  3825. )
  3826. /*++
  3827. Routine Description:
  3828. This is a private routine that checks if the input ace is inheritable
  3829. and produces 0, 1, or 2 inherited aces in the given buffer.
  3830. Arguments:
  3831. OldAce - Supplies the ace being inherited
  3832. IsDirectoryObject - Specifies if the new ACE is for a directory
  3833. AutoInherit - Specifies if the inheritance is an "automatic inheritance".
  3834. As such, the inherited ACEs will be marked as such.
  3835. ClientOwnerSid - Specifies the owner Sid to use
  3836. ClientGroupSid - Specifies the new Group Sid to use
  3837. ServerSid - Optionally specifies the Server Sid to use in compound ACEs.
  3838. ClientSid - Optionally specifies the Client Sid to use in compound ACEs.
  3839. GenericMapping - Specifies the generic mapping to use
  3840. pNewObjectType - List of types of object being inherited to. If not
  3841. specified, the object has no object type.
  3842. GuidCount - Number of object types in the list.
  3843. NewAceLength - Receives the length (number of bytes) needed to allow for
  3844. the inheritance of the specified ACE. This might be zero.
  3845. NewAcl - Provides a pointer to the ACL into which the ACE is to be
  3846. inherited.
  3847. NewAceExtraLength - Receives a length (number of bytes) temporarily used
  3848. in the ACL for the inheritance ACE. This might be zero
  3849. ObjectAceInherited - Returns true if one or more object ACEs were inherited
  3850. based on NewObjectType
  3851. Return Value:
  3852. STATUS_SUCCESS - The ACE was inherited successfully.
  3853. STATUS_BAD_INHERITANCE_ACL - Indicates something went wrong preventing
  3854. the ACE from being inherited. This generally represents a bugcheck
  3855. situation when returned from this call.
  3856. STATUS_BUFFER_TOO_SMALL - The ACL specified by NewAcl is too small for the
  3857. inheritance ACEs. The required size is returned in NewAceLength.
  3858. --*/
  3859. {
  3860. ///////////////////////////////////////////////////////////////////////////
  3861. // //
  3862. // !!!!!!!!! This is tricky !!!!!!!!!! //
  3863. // //
  3864. // The inheritence flags AND the sid of the ACE determine whether //
  3865. // we need 0, 1, or 2 ACEs. //
  3866. // //
  3867. // BE CAREFUL WHEN CHANGING THIS CODE. READ THE DSA ACL ARCHITECTURE //
  3868. // SECTION COVERING INHERITENCE BEFORE ASSUMING YOU KNOW WHAT YOU ARE //
  3869. // DOING!!!! //
  3870. // //
  3871. // The general gist of the algorithm is: //
  3872. // //
  3873. // if ( (container && ContainerInherit) || //
  3874. // (!container && ObjectInherit) ) { //
  3875. // GenerateEffectiveAce; //
  3876. // } //
  3877. // //
  3878. // //
  3879. // if (Container && Propagate) { //
  3880. // Propogate copy of ACE and set InheritOnly; //
  3881. // } //
  3882. // //
  3883. // //
  3884. // A slightly more accurate description of this algorithm is: //
  3885. // //
  3886. // IO === InheritOnly flag //
  3887. // CI === ContainerInherit flag //
  3888. // OI === ObjectInherit flag //
  3889. // NPI === NoPropagateInherit flag //
  3890. // //
  3891. // if ( (container && CI) || //
  3892. // (!container && OI) ) { //
  3893. // Copy Header of ACE; //
  3894. // Clear IO, NPI, CI, OI; //
  3895. // //
  3896. // if (KnownAceType) { //
  3897. // if (SID is a creator ID) { //
  3898. // Copy appropriate creator SID; //
  3899. // } else { //
  3900. // Copy SID of original; //
  3901. // } //
  3902. // //
  3903. // Copy AccessMask of original; //
  3904. // MapGenericAccesses; //
  3905. // if (AccessMask == 0) { //
  3906. // discard new ACE; //
  3907. // } //
  3908. // //
  3909. // } else { //
  3910. // Copy body of ACE; //
  3911. // } //
  3912. // //
  3913. // } //
  3914. // //
  3915. // if (!NPI) { //
  3916. // Copy ACE as is; //
  3917. // Set IO; //
  3918. // } //
  3919. // //
  3920. // //
  3921. // //
  3922. ///////////////////////////////////////////////////////////////////////////
  3923. ULONG LengthRequired = 0;
  3924. ULONG ExtraLengthRequired = 0;
  3925. PVOID AcePosition;
  3926. PVOID EffectiveAcePosition;
  3927. ULONG EffectiveAceSize = 0;
  3928. BOOLEAN EffectiveAceMapped;
  3929. BOOLEAN AclOverflowed = FALSE;
  3930. BOOLEAN GenerateInheritAce;
  3931. RTL_PAGED_CODE();
  3932. //
  3933. // This is gross and ugly, but it's better than allocating
  3934. // virtual memory to hold the ClientSid, because that can
  3935. // fail, and propogating the error back is a tremendous pain
  3936. //
  3937. ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
  3938. *ObjectAceInherited = FALSE;
  3939. GenerateInheritAce = IsDirectoryObject && Propagate(OldAce);
  3940. //
  3941. // Allocate and initialize the universal SIDs we're going to need
  3942. // to look for inheritable ACEs.
  3943. //
  3944. if (!RtlFirstFreeAce( NewAcl, &AcePosition ) ) {
  3945. return STATUS_BAD_INHERITANCE_ACL;
  3946. }
  3947. //
  3948. // check to see if we will have a effective ACE (one mapped to
  3949. // the target object type).
  3950. //
  3951. if ( (IsDirectoryObject && ContainerInherit(OldAce)) ||
  3952. (!IsDirectoryObject && ObjectInherit(OldAce)) ) {
  3953. //
  3954. // Remember where the effective ACE will be copied to.
  3955. //
  3956. EffectiveAcePosition = AcePosition;
  3957. //
  3958. // Copy the effective ACE into the ACL.
  3959. //
  3960. if ( !RtlpCopyEffectiveAce (
  3961. OldAce,
  3962. AutoInherit,
  3963. GenerateInheritAce,
  3964. ClientOwnerSid,
  3965. ClientGroupSid,
  3966. ServerOwnerSid,
  3967. ServerGroupSid,
  3968. GenericMapping,
  3969. pNewObjectType,
  3970. GuidCount,
  3971. &AcePosition,
  3972. &EffectiveAceSize,
  3973. NewAcl,
  3974. ObjectAceInherited,
  3975. &EffectiveAceMapped,
  3976. &AclOverflowed ) ) {
  3977. return STATUS_BAD_INHERITANCE_ACL;
  3978. }
  3979. //
  3980. // If the effective ACE is a duplicate of existing inherited ACEs,
  3981. // Don't really generate it.
  3982. //
  3983. if ( !AclOverflowed &&
  3984. EffectiveAceSize > 0 &&
  3985. EffectiveAcePosition != NULL &&
  3986. RtlpIsDuplicateAce(
  3987. NewAcl,
  3988. EffectiveAcePosition ) ) {
  3989. //
  3990. // Truncate the ACE we just added.
  3991. //
  3992. NewAcl->AceCount--;
  3993. AcePosition = EffectiveAcePosition;
  3994. ExtraLengthRequired = max( ExtraLengthRequired, EffectiveAceSize );
  3995. EffectiveAceSize = 0;
  3996. }
  3997. LengthRequired += EffectiveAceSize;
  3998. }
  3999. //
  4000. // If we are inheriting onto a container, then we may need to
  4001. // propagate the inheritance as well.
  4002. //
  4003. if ( GenerateInheritAce ) {
  4004. //
  4005. // If a effective ACE was created,
  4006. // and it wasn't mapped,
  4007. // avoid generating another ACE and simply merge the inheritance bits into
  4008. // the effective ACE.
  4009. //
  4010. if ( EffectiveAceSize != 0 && !EffectiveAceMapped ) {
  4011. //
  4012. // Copy the inherit bits from the original ACE.
  4013. //
  4014. if ( !AclOverflowed ) {
  4015. ((PACE_HEADER)EffectiveAcePosition)->AceFlags |=
  4016. ((PACE_HEADER)OldAce)->AceFlags & (CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE);
  4017. if ( AutoInherit ) {
  4018. ((PACE_HEADER)EffectiveAcePosition)->AceFlags |= INHERITED_ACE;
  4019. }
  4020. }
  4021. //
  4022. // Otherwise, generate an explicit inheritance ACE.
  4023. //
  4024. // But only if the access mask isn't zero.
  4025. //
  4026. } else if ( !IsMSAceType(OldAce) || ((PKNOWN_ACE)(OldAce))->Mask != 0 ) {
  4027. //
  4028. // Account for the new ACE being added to the ACL.
  4029. //
  4030. LengthRequired += (ULONG)(((PACE_HEADER)OldAce)->AceSize);
  4031. if (LengthRequired > 0xFFFF) {
  4032. return STATUS_BAD_INHERITANCE_ACL;
  4033. }
  4034. //
  4035. // If the ACE doesn't fit,
  4036. // just note the fact and don't copy the ACE.
  4037. //
  4038. if ( ((PACE_HEADER)OldAce)->AceSize > NewAcl->AclSize - ((PUCHAR)AcePosition - (PUCHAR)NewAcl) ) {
  4039. AclOverflowed = TRUE;
  4040. } else if (!AclOverflowed){
  4041. //
  4042. // copy it as is, but make sure the InheritOnly bit is set.
  4043. //
  4044. RtlCopyMemory(
  4045. AcePosition,
  4046. OldAce,
  4047. ((PACE_HEADER)OldAce)->AceSize
  4048. );
  4049. ((PACE_HEADER)AcePosition)->AceFlags |= INHERIT_ONLY_ACE;
  4050. NewAcl->AceCount += 1;
  4051. if ( AutoInherit ) {
  4052. ((PACE_HEADER)AcePosition)->AceFlags |= INHERITED_ACE;
  4053. //
  4054. // If the inheritance ACE is a duplicate of existing inherited ACEs,
  4055. // Don't really generate it.
  4056. //
  4057. if ( RtlpIsDuplicateAce(
  4058. NewAcl,
  4059. AcePosition ) ) {
  4060. //
  4061. // Truncate the ACE we just added.
  4062. //
  4063. NewAcl->AceCount--;
  4064. ExtraLengthRequired = max( ExtraLengthRequired,
  4065. ((PACE_HEADER)OldAce)->AceSize );
  4066. LengthRequired -= (ULONG)(((PACE_HEADER)OldAce)->AceSize);
  4067. }
  4068. }
  4069. }
  4070. }
  4071. }
  4072. //
  4073. // Now return to our caller
  4074. //
  4075. (*NewAceLength) = LengthRequired;
  4076. (*NewAceExtraLength) = ExtraLengthRequired;
  4077. return AclOverflowed ? STATUS_BUFFER_TOO_SMALL : STATUS_SUCCESS;
  4078. }
  4079. NTSTATUS
  4080. RtlpGenerateInheritAcl(
  4081. IN PACL Acl,
  4082. IN BOOLEAN IsDirectoryObject,
  4083. IN BOOLEAN AutoInherit,
  4084. IN PSID ClientOwnerSid,
  4085. IN PSID ClientGroupSid,
  4086. IN PSID ServerOwnerSid OPTIONAL,
  4087. IN PSID ServerGroupSid OPTIONAL,
  4088. IN PGENERIC_MAPPING GenericMapping,
  4089. IN GUID **pNewObjectType OPTIONAL,
  4090. IN ULONG GuidCount,
  4091. OUT PULONG NewAclSizeParam,
  4092. OUT PACL NewAcl,
  4093. OUT PBOOLEAN ObjectAceInherited
  4094. )
  4095. /*++
  4096. Routine Description:
  4097. This is a private routine that produces an inheritable ACL.
  4098. The buffer to contain the inherted ACL is passed in. If the buffer is
  4099. too small, the corect size is computed and STATUS_BUFFER_TOO_SMALL is
  4100. returned.
  4101. Arguments:
  4102. Acl - Supplies the acl being inherited.
  4103. IsDirectoryObject - Specifies if the new acl is for a directory.
  4104. AutoInherit - Specifies if the inheritance is an "automatic inheritance".
  4105. As such, the inherited ACEs will be marked as such.
  4106. OwnerSid - Specifies the owner Sid to use.
  4107. GroupSid - Specifies the group SID to use.
  4108. GenericMapping - Specifies the generic mapping to use.
  4109. pNewObjectType - List of types of object being inherited to. If not
  4110. specified, the object has no object type.
  4111. GuidCount - Number of object types in the list.
  4112. NewAclSizeParam - Receives the length of the inherited ACL.
  4113. NewAcl - Provides a pointer to the buffer to receive the new
  4114. (inherited) acl. This ACL must already be initialized.
  4115. ObjectAceInherited - Returns true if one or more object ACEs were inherited
  4116. based on NewObjectType
  4117. Return Value:
  4118. STATUS_SUCCESS - An inheritable ACL has been generated.
  4119. STATUS_BAD_INHERITANCE_ACL - Indicates the acl built was not a valid ACL.
  4120. This can becaused by a number of things. One of the more probable
  4121. causes is the replacement of a CreatorId with an SID that didn't fit
  4122. into the ACE or ACL.
  4123. STATUS_BUFFER_TOO_SMALL - The ACL specified by NewAcl is too small for the
  4124. inheritance ACEs. The required size is returned in NewAceLength.
  4125. --*/
  4126. {
  4127. NTSTATUS Status;
  4128. ULONG i;
  4129. PACE_HEADER OldAce;
  4130. ULONG NewAclSize, NewAceSize;
  4131. ULONG NewAclExtraSize, NewAceExtraSize;
  4132. BOOLEAN AclOverflowed = FALSE;
  4133. BOOLEAN LocalObjectAceInherited;
  4134. RTL_PAGED_CODE();
  4135. //
  4136. // Walk through the original ACL generating any necessary
  4137. // inheritable ACEs.
  4138. //
  4139. NewAclSize = 0;
  4140. NewAclExtraSize = 0;
  4141. *ObjectAceInherited = FALSE;
  4142. for (i = 0, OldAce = FirstAce(Acl);
  4143. i < Acl->AceCount;
  4144. i += 1, OldAce = NextAce(OldAce)) {
  4145. //
  4146. // RtlpGenerateInheritedAce() will generate the ACE(s) necessary
  4147. // to inherit a single ACE. This may be 0, 1, or more ACEs.
  4148. //
  4149. Status = RtlpGenerateInheritedAce(
  4150. OldAce,
  4151. IsDirectoryObject,
  4152. AutoInherit,
  4153. ClientOwnerSid,
  4154. ClientGroupSid,
  4155. ServerOwnerSid,
  4156. ServerGroupSid,
  4157. GenericMapping,
  4158. pNewObjectType,
  4159. GuidCount,
  4160. &NewAceSize,
  4161. NewAcl,
  4162. &NewAceExtraSize,
  4163. &LocalObjectAceInherited
  4164. );
  4165. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  4166. AclOverflowed = TRUE;
  4167. Status = STATUS_SUCCESS;
  4168. }
  4169. if ( !NT_SUCCESS(Status) ) {
  4170. return Status;
  4171. }
  4172. if ( LocalObjectAceInherited ) {
  4173. *ObjectAceInherited = TRUE;
  4174. }
  4175. //
  4176. // Make room in the ACL for the new ACE
  4177. //
  4178. NewAclSize += NewAceSize;
  4179. //
  4180. // If a previous ACE needed 'extra' space,
  4181. // reduce that requirement by the size of this ACE.
  4182. //
  4183. // The previous ACE can use this ACE's space temporarily
  4184. //
  4185. if ( NewAceSize > NewAclExtraSize ) {
  4186. NewAclExtraSize = 0 ;
  4187. } else {
  4188. NewAclExtraSize -= NewAceSize;
  4189. }
  4190. //
  4191. // The 'extra' space needed is the larger of that needed by any
  4192. // previous ACE and that need by this ACE
  4193. //
  4194. NewAclExtraSize = max( NewAclExtraSize, NewAceExtraSize );
  4195. }
  4196. //
  4197. // We only need to include the "ExtraSize" if we've overflowed.
  4198. // In those cases, the caller will allocate the size we requested and
  4199. // try again. Otherwise, the caller won't call back so we don't care
  4200. // if it knows about the extra size.
  4201. //
  4202. if ( AclOverflowed ) {
  4203. (*NewAclSizeParam) = NewAclSize + NewAclExtraSize;
  4204. return STATUS_BUFFER_TOO_SMALL;
  4205. } else {
  4206. (*NewAclSizeParam) = NewAclSize;
  4207. return STATUS_SUCCESS;
  4208. }
  4209. }
  4210. NTSTATUS
  4211. RtlpComputeMergedAcl2 (
  4212. IN PACL CurrentAcl,
  4213. IN ULONG CurrentGenericControl,
  4214. IN PACL ModificationAcl,
  4215. IN ULONG ModificationGenericControl,
  4216. IN PSID ClientOwnerSid,
  4217. IN PSID ClientGroupSid,
  4218. IN PGENERIC_MAPPING GenericMapping,
  4219. IN BOOLEAN IsSacl,
  4220. IN PULONG AclBufferSize,
  4221. IN OUT PUCHAR AclBuffer,
  4222. OUT PULONG NewGenericControl
  4223. )
  4224. /*++
  4225. Routine Description:
  4226. This routine implements the 'set' semantics for auto inheritance.
  4227. This routine builds the actual ACL that should be set on an object.
  4228. The built ACL is a composite of the previous ACL on an object and
  4229. the newly set ACL on the object. The New ACL is built as follows:
  4230. If SEP_ACL_PROTECTED is set in neither CurrentAcl nor ModificationAcl,
  4231. the NewAcl is constructed from the inherited ACEs from the
  4232. CurrentAcl and the non-inherited ACEs from the ModificationAcl.
  4233. (That is, it is impossible to edit an inherited ACE by changing the
  4234. ACL on an object.)
  4235. If SEP_ACL_PROTECTED is set on ModificationAcl, CurrentAcl is ignored.
  4236. NewAcl is built as a copy of ModificationAcl with any INHERITED_ACE
  4237. bits turned off.
  4238. If SEP_ACL_PROTECTED is set on CurrentAcl and not ModificationAcl, the
  4239. CurrentAcl is ignored. NewAcl is built as a copy of
  4240. ModificationDescriptor. It is the callers responsibility to ensure
  4241. that the correct ACEs have the INHERITED_ACE bit turned on.
  4242. Arguments:
  4243. CurrentAcl - The current ACL on the object.
  4244. CurrentGenericControl - Specifies the control flags from the SecurityDescriptor
  4245. describing the CurrentAcl.
  4246. ModificationAcl - The ACL being applied to the object.
  4247. ModificationGenericControl - Specifies the control flags from the SecurityDescriptor
  4248. describing the CurrentAcl.
  4249. ClientOwnerSid - Specifies the owner Sid to use
  4250. ClientGroupSid - Specifies the new Group Sid to use
  4251. GenericMapping - The mapping of generic to specific and standard
  4252. access types.
  4253. IsSacl - True if this is the SACL. False if this is the DACL.
  4254. AclBufferSize - On input, specifies the size of AclBuffer.
  4255. On output, on success, returns the used size of AclBuffer.
  4256. On output, if the buffer is too small, returns the required size of AclBuffer.
  4257. AclBuffer - Receives a pointer to the new (inherited) acl.
  4258. NewGenericControl - Specifies the control flags for the newly
  4259. generated ACL.
  4260. Only the Protected and AutoInherited bits are returned.
  4261. Return Value:
  4262. STATUS_SUCCESS - An ACL was successfully generated.
  4263. STATUS_UNKNOWN_REVISION - Indicates the source ACL is a revision that
  4264. is unknown to this routine.
  4265. --*/
  4266. {
  4267. NTSTATUS Status;
  4268. ULONG ModificationNewAclSize = 0;
  4269. ULONG CurrentNewAclSize = 0;
  4270. ULONG AclRevision;
  4271. BOOLEAN AclOverflowed = FALSE;
  4272. BOOLEAN NullAclOk = TRUE;
  4273. RTL_PAGED_CODE();
  4274. //
  4275. // Assume the ACL revision.
  4276. //
  4277. AclRevision = ACL_REVISION;
  4278. RtlCreateAcl( (PACL)AclBuffer, *AclBufferSize, AclRevision );
  4279. //
  4280. // This routine is only called for the AutoInheritance case.
  4281. //
  4282. *NewGenericControl = SEP_ACL_AUTO_INHERITED;
  4283. //
  4284. // If the new ACL is protected,
  4285. // simply use the new ACL with the INHERITED_ACE bits turned off.
  4286. //
  4287. if ( (ModificationGenericControl & SEP_ACL_PROTECTED) != 0 ) {
  4288. //
  4289. // Set the Control bits for the resultant descriptor.
  4290. //
  4291. *NewGenericControl |= SEP_ACL_PROTECTED;
  4292. //
  4293. // Only copy the ACL if it is actually present
  4294. //
  4295. if ( ModificationAcl != NULL ) {
  4296. AclRevision = max( AclRevision, ModificationAcl->AclRevision );
  4297. //
  4298. // Copy all ACES, turn off the inherited bit, and generic map them.
  4299. //
  4300. Status = RtlpCopyAces(
  4301. ModificationAcl,
  4302. GenericMapping,
  4303. CopyAllAces,
  4304. INHERITED_ACE, // Turn off all INHERITED_ACE flags
  4305. TRUE, // Map sids as needed
  4306. ClientOwnerSid,
  4307. ClientGroupSid,
  4308. ClientOwnerSid, // Not technically correct. s.b. server sid
  4309. ClientGroupSid, // Not technically correct. s.b. server sid
  4310. TRUE, // Assume container and skip optimization
  4311. FALSE, // Do not retain INHERITED_ACE bit for effective aces
  4312. &ModificationNewAclSize,
  4313. (PACL)AclBuffer );
  4314. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  4315. AclOverflowed = TRUE;
  4316. Status = STATUS_SUCCESS;
  4317. }
  4318. if ( !NT_SUCCESS(Status) ) {
  4319. return Status;
  4320. }
  4321. //
  4322. // If the caller specified an ACL with no ACES,
  4323. // make sure we generate an ACL with no ACES.
  4324. //
  4325. NullAclOk = FALSE;
  4326. }
  4327. //
  4328. // If the old ACL is protected but the new one isn't,
  4329. // simply use the new ACL as is.
  4330. //
  4331. // Rely on the caller to get the INHERITED_ACE bits right.
  4332. //
  4333. } else if ( (CurrentGenericControl & SEP_ACL_PROTECTED) != 0 ) {
  4334. //
  4335. // Only do the copy if the new ACL is specified.
  4336. //
  4337. if ( ModificationAcl != NULL ) {
  4338. AclRevision = max( AclRevision, ModificationAcl->AclRevision );
  4339. //
  4340. // Copy all ACES, and generic map them.
  4341. //
  4342. Status = RtlpCopyAces(
  4343. ModificationAcl,
  4344. GenericMapping,
  4345. CopyAllAces,
  4346. 0,
  4347. TRUE, // Map sids as needed
  4348. ClientOwnerSid,
  4349. ClientGroupSid,
  4350. ClientOwnerSid, // Not technically correct. s.b. server sid
  4351. ClientGroupSid, // Not technically correct. s.b. server sid
  4352. TRUE, // Assume container and skip optimization
  4353. TRUE, // Retain INHERITED_ACE bit for effective aces
  4354. &ModificationNewAclSize,
  4355. (PACL)AclBuffer );
  4356. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  4357. AclOverflowed = TRUE;
  4358. Status = STATUS_SUCCESS;
  4359. }
  4360. if ( !NT_SUCCESS(Status) ) {
  4361. return Status;
  4362. }
  4363. //
  4364. // If the caller specified an ACL with no ACES,
  4365. // make sure we generate an ACL with no ACES.
  4366. //
  4367. NullAclOk = FALSE;
  4368. //
  4369. // Since the ACL isn't protected,
  4370. // don't allow NULL ACL semantics.
  4371. // (those semantics are ambiguous for auto inheritance)
  4372. //
  4373. } else if ( !IsSacl ) {
  4374. return STATUS_INVALID_ACL;
  4375. }
  4376. //
  4377. // If neither are protected,
  4378. // use the non-inherited ACEs from the new ACL, and
  4379. // preserve the inherited ACEs from the old ACL.
  4380. //
  4381. } else {
  4382. //
  4383. // NULL ACLs are always OK for a SACL.
  4384. // NULL ACLs are never OK for a non-protected DACL.
  4385. //
  4386. NullAclOk = IsSacl;
  4387. //
  4388. // Only do the copy if the new ACL is specified.
  4389. //
  4390. if ( ModificationAcl != NULL ) {
  4391. AclRevision = max( AclRevision, ModificationAcl->AclRevision );
  4392. //
  4393. // Copy the non-inherited ACES, and generic map them.
  4394. //
  4395. Status = RtlpCopyAces(
  4396. ModificationAcl,
  4397. GenericMapping,
  4398. CopyNonInheritedAces,
  4399. 0,
  4400. TRUE, // Map sids as needed
  4401. ClientOwnerSid,
  4402. ClientGroupSid,
  4403. ClientOwnerSid, // Not technically correct. s.b. server sid
  4404. ClientGroupSid, // Not technically correct. s.b. server sid
  4405. TRUE, // Assume container and skip optimization
  4406. FALSE, // Do not retain INHERITED_ACE bit for effective aces
  4407. &ModificationNewAclSize,
  4408. (PACL)AclBuffer );
  4409. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  4410. AclOverflowed = TRUE;
  4411. Status = STATUS_SUCCESS;
  4412. }
  4413. if ( !NT_SUCCESS(Status) ) {
  4414. return Status;
  4415. }
  4416. //
  4417. // If the caller specified an ACL with no ACES,
  4418. // make sure we generate an ACL with no ACES.
  4419. //
  4420. // If inherited aces were deleted, leave the flag alone allowing
  4421. // a NULL SACL to be generated.
  4422. //
  4423. if ( ModificationAcl->AceCount == 0 ) {
  4424. NullAclOk = FALSE;
  4425. }
  4426. //
  4427. // Since the ACL isn't protected,
  4428. // don't allow NULL ACL semantics.
  4429. // (those semantics are ambiguous for auto inheritance)
  4430. //
  4431. } else if ( !IsSacl ) {
  4432. return STATUS_INVALID_ACL;
  4433. }
  4434. //
  4435. // Only do the copy if the old ACL is specified.
  4436. //
  4437. if ( CurrentAcl != NULL ) {
  4438. AclRevision = max( AclRevision, CurrentAcl->AclRevision );
  4439. //
  4440. // Copy the inherited ACES, and generic map them.
  4441. //
  4442. // Don't bother mapping the sids in these ACEs. They got mapped
  4443. // during inheritance.
  4444. //
  4445. Status = RtlpCopyAces(
  4446. CurrentAcl,
  4447. GenericMapping,
  4448. CopyInheritedAces,
  4449. 0,
  4450. FALSE, // Don't map the sids,
  4451. NULL,
  4452. NULL,
  4453. NULL,
  4454. NULL,
  4455. TRUE, // Assume container and skip optimization
  4456. FALSE, // Do not retain INHERITED_ACE bit for effective aces
  4457. &CurrentNewAclSize,
  4458. (PACL)AclBuffer );
  4459. if ( Status == STATUS_BUFFER_TOO_SMALL ) {
  4460. AclOverflowed = TRUE;
  4461. Status = STATUS_SUCCESS;
  4462. }
  4463. if ( !NT_SUCCESS(Status) ) {
  4464. return Status;
  4465. }
  4466. }
  4467. }
  4468. //
  4469. // If this routine didn't build the ACL,
  4470. // tell the caller to use an explict NULL ACL
  4471. //
  4472. if ( ModificationNewAclSize + CurrentNewAclSize == 0) {
  4473. //
  4474. // If the Acl was explictly assigned,
  4475. // generate a NULL ACL based on the path taken above.
  4476. //
  4477. if ( NullAclOk ) {
  4478. *AclBufferSize = 0;
  4479. return STATUS_SUCCESS;
  4480. }
  4481. }
  4482. //
  4483. // And make sure we don't exceed the length limitations of an ACL (WORD)
  4484. //
  4485. if ( ModificationNewAclSize + CurrentNewAclSize + sizeof(ACL) > 0xFFFF) {
  4486. return(STATUS_BAD_INHERITANCE_ACL);
  4487. }
  4488. (*AclBufferSize) = ModificationNewAclSize + CurrentNewAclSize + sizeof(ACL);
  4489. if ( AclOverflowed ) {
  4490. return STATUS_BUFFER_TOO_SMALL;
  4491. }
  4492. //
  4493. // Patch the real ACL size and revision into the ACL
  4494. //
  4495. ((PACL)AclBuffer)->AclSize = (USHORT) *AclBufferSize;
  4496. ((PACL)AclBuffer)->AclRevision = (UCHAR) AclRevision;
  4497. return STATUS_SUCCESS;
  4498. }
  4499. NTSTATUS
  4500. RtlpComputeMergedAcl (
  4501. IN PACL CurrentAcl,
  4502. IN ULONG CurrentGenericControl,
  4503. IN PACL ModificationAcl,
  4504. IN ULONG ModificationGenericControl,
  4505. IN PSID ClientOwnerSid,
  4506. IN PSID ClientGroupSid,
  4507. IN PGENERIC_MAPPING GenericMapping,
  4508. IN BOOLEAN IsSacl,
  4509. OUT PACL *NewAcl,
  4510. OUT PULONG NewGenericControl
  4511. )
  4512. /*++
  4513. Routine Description:
  4514. This routine builds the actual ACL that should be set on an object.
  4515. The built ACL is a composite of the previous ACL on an object and
  4516. the newly set ACL on the object. The New ACL is built as follows:
  4517. If SEP_ACL_PROTECTED is set in neither CurrentAcl nor ModificationAcl,
  4518. the NewAcl is constructed from the inherited ACEs from the
  4519. CurrentAcl and the non-inherited ACEs from the ModificationAcl.
  4520. (That is, it is impossible to edit an inherited ACE by changing the
  4521. ACL on an object.)
  4522. If SEP_ACL_PROTECTED is set on ModificationAcl, CurrentAcl is ignored.
  4523. NewAcl is built as a copy of ModificationAcl with any INHERITED_ACE
  4524. bits turned off.
  4525. If SEP_ACL_PROTECTED is set on CurrentAcl and not ModificationAcl, the
  4526. CurrentAcl is ignored. NewAcl is built as a copy of
  4527. ModificationDescriptor. It is the callers responsibility to ensure
  4528. that the correct ACEs have the INHERITED_ACE bit turned on.
  4529. Arguments:
  4530. CurrentAcl - The current ACL on the object.
  4531. CurrentGenericControl - Specifies the control flags from the SecurityDescriptor
  4532. describing the CurrentAcl.
  4533. ModificationAcl - The ACL being applied to the object.
  4534. ModificationGenericControl - Specifies the control flags from the SecurityDescriptor
  4535. describing the CurrentAcl.
  4536. ClientOwnerSid - Specifies the owner Sid to use
  4537. ClientGroupSid - Specifies the new Group Sid to use
  4538. GenericMapping - The mapping of generic to specific and standard
  4539. access types.
  4540. IsSacl - True if this is the SACL. False if this is the DACL.
  4541. NewAcl - Receives a pointer to the new resultant acl.
  4542. NewGenericControl - Specifies the control flags for the newly
  4543. generated ACL.
  4544. Only the Protected and AutoInherited bits are returned.
  4545. Return Value:
  4546. STATUS_SUCCESS - An ACL was successfully generated.
  4547. STATUS_UNKNOWN_REVISION - Indicates the source ACL is a revision that
  4548. is unknown to this routine.
  4549. --*/
  4550. {
  4551. NTSTATUS Status;
  4552. ULONG AclBufferSize;
  4553. ULONG i;
  4554. #ifndef NTOS_KERNEL_RUNTIME
  4555. PVOID HeapHandle;
  4556. #endif // NTOS_KERNEL_RUNTIME
  4557. RTL_PAGED_CODE();
  4558. //
  4559. // Get the handle to the current process heap
  4560. //
  4561. #ifndef NTOS_KERNEL_RUNTIME
  4562. HeapHandle = RtlProcessHeap();
  4563. #endif // NTOS_KERNEL_RUNTIME
  4564. //
  4565. // Implement a two pass strategy.
  4566. //
  4567. // First try to create the ACL in a fixed length buffer.
  4568. // If that is too small,
  4569. // then use the buffer size determined on the first pass
  4570. //
  4571. AclBufferSize = 1024;
  4572. for ( i=0; i<2 ; i++ ) {
  4573. //
  4574. // Allocate heap for the new ACL.
  4575. //
  4576. #ifdef NTOS_KERNEL_RUNTIME
  4577. (*NewAcl) = ExAllocatePoolWithTag(
  4578. PagedPool,
  4579. AclBufferSize,
  4580. 'cAeS' );
  4581. #else // NTOS_KERNEL_RUNTIME
  4582. (*NewAcl) = RtlAllocateHeap( HeapHandle, 0, AclBufferSize );
  4583. #endif // NTOS_KERNEL_RUNTIME
  4584. if ((*NewAcl) == NULL ) {
  4585. return( STATUS_NO_MEMORY );
  4586. }
  4587. //
  4588. // Merge the ACLs
  4589. //
  4590. Status = RtlpComputeMergedAcl2 (
  4591. CurrentAcl,
  4592. CurrentGenericControl,
  4593. ModificationAcl,
  4594. ModificationGenericControl,
  4595. ClientOwnerSid,
  4596. ClientGroupSid,
  4597. GenericMapping,
  4598. IsSacl,
  4599. &AclBufferSize,
  4600. (PUCHAR) *NewAcl,
  4601. NewGenericControl );
  4602. if ( NT_SUCCESS(Status) ) {
  4603. //
  4604. // If a NULL ACL should be used,
  4605. // tell the caller.
  4606. //
  4607. if ( AclBufferSize == 0 ) {
  4608. #ifdef NTOS_KERNEL_RUNTIME
  4609. ExFreePool( *NewAcl );
  4610. #else // NTOS_KERNEL_RUNTIME
  4611. RtlFreeHeap( HeapHandle, 0, *NewAcl );
  4612. #endif // NTOS_KERNEL_RUNTIME
  4613. *NewAcl = NULL;
  4614. }
  4615. break;
  4616. } else {
  4617. #ifdef NTOS_KERNEL_RUNTIME
  4618. ExFreePool( *NewAcl );
  4619. #else // NTOS_KERNEL_RUNTIME
  4620. RtlFreeHeap( HeapHandle, 0, *NewAcl );
  4621. #endif // NTOS_KERNEL_RUNTIME
  4622. *NewAcl = NULL;
  4623. if ( Status != STATUS_BUFFER_TOO_SMALL ) {
  4624. break;
  4625. }
  4626. }
  4627. }
  4628. return Status;
  4629. }
  4630. #endif // WIN16
  4631. #if DBG
  4632. NTSTATUS
  4633. RtlDumpUserSid(
  4634. VOID
  4635. )
  4636. {
  4637. NTSTATUS Status;
  4638. HANDLE TokenHandle;
  4639. CHAR Buffer[200];
  4640. ULONG ReturnLength;
  4641. PSID pSid;
  4642. UNICODE_STRING SidString;
  4643. PTOKEN_USER User;
  4644. //
  4645. // Attempt to open the impersonation token first
  4646. //
  4647. Status = NtOpenThreadToken(
  4648. NtCurrentThread(),
  4649. GENERIC_READ,
  4650. FALSE,
  4651. &TokenHandle
  4652. );
  4653. if (!NT_SUCCESS( Status )) {
  4654. DbgPrint("Not impersonating, status = %X, trying process token\n",Status);
  4655. Status = NtOpenProcessToken(
  4656. NtCurrentProcess(),
  4657. GENERIC_READ,
  4658. &TokenHandle
  4659. );
  4660. if (!NT_SUCCESS( Status )) {
  4661. DbgPrint("Unable to open process token, status = %X\n",Status);
  4662. return( Status );
  4663. }
  4664. }
  4665. Status = NtQueryInformationToken (
  4666. TokenHandle,
  4667. TokenUser,
  4668. Buffer,
  4669. 200,
  4670. &ReturnLength
  4671. );
  4672. if (!NT_SUCCESS( Status )) {
  4673. DbgPrint("Unable to query user sid, status = %X \n",Status);
  4674. NtClose(TokenHandle);
  4675. return( Status );
  4676. }
  4677. User = (PTOKEN_USER)Buffer;
  4678. pSid = User->User.Sid;
  4679. Status = RtlConvertSidToUnicodeString( &SidString, pSid, TRUE );
  4680. if (!NT_SUCCESS( Status )) {
  4681. DbgPrint("Unable to format sid string, status = %X \n",Status);
  4682. NtClose(TokenHandle);
  4683. return( Status );
  4684. }
  4685. DbgPrint("Current Sid = %wZ \n",&SidString);
  4686. RtlFreeUnicodeString( &SidString );
  4687. return( STATUS_SUCCESS );
  4688. }
  4689. #endif
  4690. NTSTATUS
  4691. RtlpConvertToAutoInheritSecurityObject(
  4692. IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
  4693. IN PSECURITY_DESCRIPTOR CurrentSecurityDescriptor,
  4694. OUT PSECURITY_DESCRIPTOR *NewSecurityDescriptor,
  4695. IN GUID *ObjectType OPTIONAL,
  4696. IN BOOLEAN IsDirectoryObject,
  4697. IN PGENERIC_MAPPING GenericMapping
  4698. )
  4699. /*++
  4700. Routine Description:
  4701. This routine a converts a security descriptor whose ACLs are not marked
  4702. as AutoInherit to a security descriptor whose ACLs are marked as
  4703. AutoInherit.
  4704. See comments for RtlConvertToAutoInheritSecurityObject.
  4705. Arguments:
  4706. ParentDescriptor - Supplies the Security Descriptor for the parent
  4707. directory under which a object exists. If there is
  4708. no parent directory, then this argument is specified as NULL.
  4709. CurrentSecurityDescriptor - Supplies a pointer to the objects security descriptor
  4710. that is going to be altered by this procedure.
  4711. NewSecurityDescriptor Points to a pointer that is to be made to point to the
  4712. newly allocated self-relative security descriptor. When no
  4713. longer needed, this descriptor must be freed using
  4714. DestroyPrivateObjectSecurity().
  4715. ObjectType - GUID of the object type being created. If the object being
  4716. created has no GUID associated with it, then this argument is
  4717. specified as NULL.
  4718. IsDirectoryObject - Specifies if the object is a
  4719. directory object. A value of TRUE indicates the object is a
  4720. container of other objects.
  4721. GenericMapping - Supplies a pointer to a generic mapping array denoting
  4722. the mapping between each generic right to specific rights.
  4723. Return Value:
  4724. STATUS_SUCCESS - The operation was successful.
  4725. See comments for RtlConvertToAutoInheritSecurityObject.
  4726. --*/
  4727. {
  4728. NTSTATUS Status;
  4729. PISECURITY_DESCRIPTOR CurrentDescriptor;
  4730. PACL CurrentSacl;
  4731. PACL CurrentDacl;
  4732. PSID NewOwner;
  4733. PSID NewGroup;
  4734. PACL NewSacl = NULL;
  4735. ULONG NewSaclControl = 0;
  4736. BOOLEAN NewSaclAllocated = FALSE;
  4737. PACL NewDacl = NULL;
  4738. ULONG NewDaclControl = 0;
  4739. BOOLEAN NewDaclAllocated = FALSE;
  4740. PACL TemplateInheritedDacl = NULL;
  4741. ULONG GenericControl;
  4742. ULONG AllocationSize;
  4743. ULONG NewOwnerSize;
  4744. ULONG NewGroupSize;
  4745. ULONG NewSaclSize;
  4746. ULONG NewDaclSize;
  4747. PCHAR Field;
  4748. PCHAR Base;
  4749. PISECURITY_DESCRIPTOR_RELATIVE INewDescriptor = NULL;
  4750. ULONG ReturnLength;
  4751. NTSTATUS PassedStatus;
  4752. HANDLE PrimaryToken;
  4753. #ifndef NTOS_KERNEL_RUNTIME
  4754. PVOID HeapHandle;
  4755. #endif // NTOS_KERNEL_RUNTIME
  4756. RTL_PAGED_CODE();
  4757. //
  4758. // Get the handle to the current process heap
  4759. //
  4760. #ifndef NTOS_KERNEL_RUNTIME
  4761. HeapHandle = RtlProcessHeap();
  4762. #endif // NTOS_KERNEL_RUNTIME
  4763. //
  4764. //
  4765. CurrentDescriptor = CurrentSecurityDescriptor;
  4766. //
  4767. // Validate the incoming security descriptor.
  4768. //
  4769. if (!RtlValidSecurityDescriptor ( CurrentDescriptor )) {
  4770. Status = STATUS_INVALID_SECURITY_DESCR;
  4771. goto Cleanup;
  4772. }
  4773. NewOwner = RtlpOwnerAddrSecurityDescriptor( CurrentDescriptor );
  4774. if ( NewOwner == NULL ) {
  4775. Status = STATUS_INVALID_SECURITY_DESCR;
  4776. goto Cleanup;
  4777. }
  4778. NewGroup = RtlpGroupAddrSecurityDescriptor( CurrentDescriptor );
  4779. //
  4780. // Handle the SACL.
  4781. //
  4782. //
  4783. // If the SACL isn't present,
  4784. // special case it.
  4785. //
  4786. CurrentSacl = RtlpSaclAddrSecurityDescriptor( CurrentDescriptor );
  4787. if ( CurrentSacl == NULL ) {
  4788. PACL ParentSacl;
  4789. // Preserve the Acl Present bit and protected bit from the existing descriptor.
  4790. NewSaclControl |= CurrentDescriptor->Control & (SE_SACL_PROTECTED|SE_SACL_PRESENT);
  4791. // Always set the autoinherited bit.
  4792. NewSaclControl |= SE_SACL_AUTO_INHERITED;
  4793. //
  4794. // If the Parent also has a NULL SACL,
  4795. // just consider this SACL as inherited.
  4796. // otherwise, this SACL is protected.
  4797. //
  4798. ParentSacl = ARGUMENT_PRESENT(ParentDescriptor) ?
  4799. RtlpSaclAddrSecurityDescriptor( ((SECURITY_DESCRIPTOR *)ParentDescriptor)) :
  4800. NULL;
  4801. if ( ParentSacl != NULL) {
  4802. NewSaclControl |= SE_SACL_PROTECTED;
  4803. }
  4804. //
  4805. // If the SACL is already converted,
  4806. // or if this object is at the root of the tree,
  4807. // simply leave it alone.
  4808. //
  4809. // Don't force the Protect bit on at the root of the tree since it is semantically
  4810. // a no-op and gets in the way if the object is ever moved.
  4811. //
  4812. } else if ( RtlpAreControlBitsSet( CurrentDescriptor, SE_SACL_AUTO_INHERITED) ||
  4813. RtlpAreControlBitsSet( CurrentDescriptor, SE_SACL_PROTECTED ) ||
  4814. !ARGUMENT_PRESENT(ParentDescriptor) ) {
  4815. // Preserve the Acl Present bit and protected bit from the existing descriptor.
  4816. NewSaclControl |= CurrentDescriptor->Control & (SE_SACL_PROTECTED|SE_SACL_PRESENT);
  4817. // Always set the autoinherited bit.
  4818. NewSaclControl |= SE_SACL_AUTO_INHERITED;
  4819. NewSacl = CurrentSacl;
  4820. //
  4821. // If the SACL is present,
  4822. // compute a new SACL with appropriate ACEs marked as inherited.
  4823. //
  4824. } else {
  4825. Status = RtlpConvertAclToAutoInherit (
  4826. ARGUMENT_PRESENT(ParentDescriptor) ?
  4827. RtlpSaclAddrSecurityDescriptor(
  4828. ((SECURITY_DESCRIPTOR *)ParentDescriptor)) :
  4829. NULL,
  4830. RtlpSaclAddrSecurityDescriptor(CurrentDescriptor),
  4831. ObjectType,
  4832. IsDirectoryObject,
  4833. RtlpOwnerAddrSecurityDescriptor(CurrentDescriptor),
  4834. RtlpGroupAddrSecurityDescriptor(CurrentDescriptor),
  4835. GenericMapping,
  4836. &NewSacl,
  4837. &GenericControl );
  4838. if ( !NT_SUCCESS(Status) ) {
  4839. goto Cleanup;
  4840. }
  4841. NewSaclAllocated = TRUE;
  4842. NewSaclControl |= SE_SACL_PRESENT | SeControlGenericToSacl( GenericControl );
  4843. }
  4844. //
  4845. // Handle the DACL.
  4846. //
  4847. //
  4848. // If the DACL isn't present,
  4849. // special case it.
  4850. //
  4851. CurrentDacl = RtlpDaclAddrSecurityDescriptor( CurrentDescriptor );
  4852. if ( CurrentDacl == NULL ) {
  4853. // Preserve the Dacl Present bit from the existing descriptor.
  4854. NewDaclControl |= CurrentDescriptor->Control & SE_DACL_PRESENT;
  4855. // Always set the autoinherited bit.
  4856. // Force it protected.
  4857. NewDaclControl |= SE_DACL_AUTO_INHERITED | SE_DACL_PROTECTED;
  4858. //
  4859. // If the DACL is already converted,
  4860. // or if this object is at the root of the tree,
  4861. // simply leave it alone.
  4862. //
  4863. // Don't force the Protect bit on at the root of the tree since it is semantically
  4864. // a no-op and gets in the way if the object is ever moved.
  4865. //
  4866. } else if ( RtlpAreControlBitsSet( CurrentDescriptor, SE_DACL_AUTO_INHERITED) ||
  4867. RtlpAreControlBitsSet( CurrentDescriptor, SE_DACL_PROTECTED ) ||
  4868. !ARGUMENT_PRESENT(ParentDescriptor) ) {
  4869. // Preserve the Acl Present bit and protected bit from the existing descriptor.
  4870. NewDaclControl |= CurrentDescriptor->Control & (SE_DACL_PROTECTED|SE_DACL_PRESENT);
  4871. // Always set the autoinherited bit.
  4872. NewDaclControl |= SE_DACL_AUTO_INHERITED;
  4873. NewDacl = CurrentDacl;
  4874. //
  4875. // If the DACL is present,
  4876. // compute a new DACL with appropriate ACEs marked as inherited.
  4877. //
  4878. } else {
  4879. Status = RtlpConvertAclToAutoInherit (
  4880. ARGUMENT_PRESENT(ParentDescriptor) ?
  4881. RtlpDaclAddrSecurityDescriptor(
  4882. ((SECURITY_DESCRIPTOR *)ParentDescriptor)) :
  4883. NULL,
  4884. RtlpDaclAddrSecurityDescriptor(CurrentDescriptor),
  4885. ObjectType,
  4886. IsDirectoryObject,
  4887. RtlpOwnerAddrSecurityDescriptor(CurrentDescriptor),
  4888. RtlpGroupAddrSecurityDescriptor(CurrentDescriptor),
  4889. GenericMapping,
  4890. &NewDacl,
  4891. &GenericControl );
  4892. if ( !NT_SUCCESS(Status) ) {
  4893. goto Cleanup;
  4894. }
  4895. NewDaclAllocated = TRUE;
  4896. NewDaclControl |= SE_DACL_PRESENT | SeControlGenericToDacl( GenericControl );
  4897. }
  4898. //
  4899. // Build the resultant security descriptor
  4900. //
  4901. // Also map the ACEs for application to the target object
  4902. // type, if they haven't already been mapped.
  4903. //
  4904. NewOwnerSize = LongAlignSize(SeLengthSid(NewOwner));
  4905. if ( NewGroup != NULL ) {
  4906. NewGroupSize = LongAlignSize(SeLengthSid(NewGroup));
  4907. } else {
  4908. NewGroupSize = 0;
  4909. }
  4910. if (NewSacl != NULL) {
  4911. NewSaclSize = LongAlignSize(NewSacl->AclSize);
  4912. } else {
  4913. NewSaclSize = 0;
  4914. }
  4915. if (NewDacl != NULL) {
  4916. NewDaclSize = LongAlignSize(NewDacl->AclSize);
  4917. } else {
  4918. NewDaclSize = 0;
  4919. }
  4920. AllocationSize = LongAlignSize(sizeof(SECURITY_DESCRIPTOR_RELATIVE)) +
  4921. NewOwnerSize +
  4922. NewGroupSize +
  4923. NewSaclSize +
  4924. NewDaclSize;
  4925. //
  4926. // Allocate and initialize the security descriptor as
  4927. // self-relative form.
  4928. //
  4929. #ifdef NTOS_KERNEL_RUNTIME
  4930. INewDescriptor = ExAllocatePoolWithTag(
  4931. PagedPool,
  4932. AllocationSize,
  4933. 'dSeS' );
  4934. #else // NTOS_KERNEL_RUNTIME
  4935. INewDescriptor = RtlAllocateHeap(
  4936. HeapHandle,
  4937. MAKE_TAG(SE_TAG),
  4938. AllocationSize );
  4939. #endif // NTOS_KERNEL_RUNTIME
  4940. if ( INewDescriptor == NULL ) {
  4941. Status = STATUS_NO_MEMORY;
  4942. goto Cleanup;
  4943. }
  4944. //
  4945. // Initialize the security descriptor as self-relative form.
  4946. //
  4947. RtlCreateSecurityDescriptorRelative(
  4948. INewDescriptor,
  4949. SECURITY_DESCRIPTOR_REVISION
  4950. );
  4951. RtlpSetControlBits( INewDescriptor, SE_SELF_RELATIVE );
  4952. Base = (PCHAR)(INewDescriptor);
  4953. Field = Base + sizeof(SECURITY_DESCRIPTOR_RELATIVE);
  4954. //
  4955. // Copy the Sacl
  4956. //
  4957. RtlpSetControlBits( INewDescriptor, NewSaclControl );
  4958. if (NewSacl != NULL ) {
  4959. RtlCopyMemory( Field, NewSacl, NewSacl->AclSize );
  4960. INewDescriptor->Sacl = RtlPointerToOffset(Base,Field);
  4961. Field += NewSaclSize;
  4962. } else {
  4963. INewDescriptor->Sacl = 0;
  4964. }
  4965. //
  4966. // Copy the Dacl
  4967. //
  4968. RtlpSetControlBits( INewDescriptor, NewDaclControl );
  4969. if (NewDacl != NULL ) {
  4970. RtlCopyMemory( Field, NewDacl, NewDacl->AclSize );
  4971. INewDescriptor->Dacl = RtlPointerToOffset(Base,Field);
  4972. Field += NewDaclSize;
  4973. } else {
  4974. INewDescriptor->Dacl = 0;
  4975. }
  4976. //
  4977. // Assign the owner
  4978. //
  4979. RtlCopyMemory( Field, NewOwner, SeLengthSid(NewOwner) );
  4980. INewDescriptor->Owner = RtlPointerToOffset(Base,Field);
  4981. Field += NewOwnerSize;
  4982. if ( NewGroup != NULL ) {
  4983. RtlCopyMemory( Field, NewGroup, SeLengthSid(NewGroup) );
  4984. INewDescriptor->Group = RtlPointerToOffset(Base,Field);
  4985. }
  4986. Status = STATUS_SUCCESS;
  4987. //
  4988. // Cleanup any locally used resources.
  4989. //
  4990. Cleanup:
  4991. if (NewDaclAllocated) {
  4992. #ifdef NTOS_KERNEL_RUNTIME
  4993. ExFreePool( NewDacl );
  4994. #else // NTOS_KERNEL_RUNTIME
  4995. RtlFreeHeap( HeapHandle, 0, NewDacl );
  4996. #endif // NTOS_KERNEL_RUNTIME
  4997. }
  4998. if (NewSaclAllocated) {
  4999. #ifdef NTOS_KERNEL_RUNTIME
  5000. ExFreePool( NewSacl );
  5001. #else // NTOS_KERNEL_RUNTIME
  5002. RtlFreeHeap( HeapHandle, 0, NewSacl );
  5003. #endif // NTOS_KERNEL_RUNTIME
  5004. }
  5005. *NewSecurityDescriptor = (PSECURITY_DESCRIPTOR) INewDescriptor;
  5006. return Status;
  5007. }
  5008. //
  5009. // Local macro to classify the ACE flags in an ACE.
  5010. //
  5011. // Returns one or more of the following ACE flags:
  5012. //
  5013. // CONTAINER_INHERIT_ACE - ACE is inherited to child containers
  5014. // OBJECT_INHERIT_ACE - ACE is inherited to child leaf objects
  5015. // EFFECTIVE_ACE - ACE is used during access validation
  5016. //
  5017. #define MAX_CHILD_SID_GROUP_SIZE 3 // Number of bits in above list
  5018. #define EFFECTIVE_ACE INHERIT_ONLY_ACE
  5019. #define AceFlagsInAce( _Ace) \
  5020. (((PACE_HEADER)(_Ace))->AceFlags & (OBJECT_INHERIT_ACE|CONTAINER_INHERIT_ACE) | \
  5021. (((PACE_HEADER)(_Ace))->AceFlags & INHERIT_ONLY_ACE) ^ INHERIT_ONLY_ACE )
  5022. BOOLEAN
  5023. RtlpCompareAces(
  5024. IN PKNOWN_ACE InheritedAce,
  5025. IN PKNOWN_ACE ChildAce,
  5026. IN PSID OwnerSid,
  5027. IN PSID GroupSid
  5028. )
  5029. /*++
  5030. Routine Description:
  5031. Compare two aces to see if they are "substantially" the same.
  5032. Arguments:
  5033. InheritedAce - Computed ACE as inherited from DirectoryAcl.
  5034. ChildAce - The current acl on the object. This ACL must be a revision 2 ACL.
  5035. ObjectType - GUID of the object type being created. If the object being
  5036. created has no GUID associated with it, then this argument is
  5037. specified as NULL.
  5038. OwnerSid - Specifies the owner Sid to use.
  5039. If not specified, the owner sid is not treated as special.
  5040. GroupSid - Specifies the group SID to use.
  5041. If not specified, the group sid is not treated as special.
  5042. Return Value:
  5043. TRUE - The ACEs are substantially the same.
  5044. FALSE - The ACEs are not substantially the same.
  5045. --*/
  5046. {
  5047. BOOLEAN AcesCompare = FALSE;
  5048. if (IsObjectAceType(InheritedAce) && IsObjectAceType(ChildAce)) {
  5049. AcesCompare = RtlpCompareKnownObjectAces( (PKNOWN_OBJECT_ACE)InheritedAce,
  5050. (PKNOWN_OBJECT_ACE)ChildAce,
  5051. OwnerSid,
  5052. GroupSid
  5053. );
  5054. } else {
  5055. if (!IsObjectAceType(InheritedAce) && !IsObjectAceType(ChildAce)) {
  5056. AcesCompare = RtlpCompareKnownAces( InheritedAce,
  5057. ChildAce,
  5058. OwnerSid,
  5059. GroupSid
  5060. );
  5061. }
  5062. }
  5063. return( AcesCompare );
  5064. }
  5065. BOOLEAN
  5066. RtlpCompareKnownAces(
  5067. IN PKNOWN_ACE InheritedAce,
  5068. IN PKNOWN_ACE ChildAce,
  5069. IN PSID OwnerSid OPTIONAL,
  5070. IN PSID GroupSid OPTIONAL
  5071. )
  5072. /*++
  5073. Routine Description:
  5074. Compare two aces to see if they are "substantially" the same.
  5075. Arguments:
  5076. InheritedAce - Computed ACE as inherited from DirectoryAcl.
  5077. ChildAce - The current acl on the object. This ACL must be a revision 2 ACL.
  5078. OwnerSid - Specifies the owner Sid to use.
  5079. If not specified, the owner sid is not treated as special.
  5080. GroupSid - Specifies the group SID to use.
  5081. If not specified, the group sid is not treated as special.
  5082. Return Value:
  5083. TRUE - The ACEs are substantially the same.
  5084. FALSE - The ACEs are not substantially the same.
  5085. --*/
  5086. {
  5087. NTSTATUS Status;
  5088. ACE_HEADER volatile *InheritedAceHdr = &InheritedAce->Header;
  5089. RTL_PAGED_CODE();
  5090. ASSERT(!IsObjectAceType(InheritedAce));
  5091. ASSERT(!IsObjectAceType(ChildAce));
  5092. //
  5093. // If the Ace types are different,
  5094. // we don't match.
  5095. //
  5096. if ( RtlBaseAceType[ChildAce->Header.AceType] != RtlBaseAceType[InheritedAceHdr->AceType] ) {
  5097. #if DBG
  5098. if ( RtlpVerboseConvert ) {
  5099. KdPrint(("AceType mismatch"));
  5100. }
  5101. #endif // DBG
  5102. return FALSE;
  5103. }
  5104. //
  5105. // If this is a system ACE,
  5106. // ensure the SUCCESS/FAILURE flags match.
  5107. //
  5108. if ( RtlIsSystemAceType[ChildAce->Header.AceType] ) {
  5109. if ( (ChildAce->Header.AceFlags & (SUCCESSFUL_ACCESS_ACE_FLAG|FAILED_ACCESS_ACE_FLAG)) !=
  5110. (InheritedAceHdr->AceFlags & (SUCCESSFUL_ACCESS_ACE_FLAG|FAILED_ACCESS_ACE_FLAG)) ) {
  5111. #if DBG
  5112. if ( RtlpVerboseConvert ) {
  5113. KdPrint(("System ace success/fail mismatch"));
  5114. }
  5115. #endif // DBG
  5116. return FALSE;
  5117. }
  5118. }
  5119. //
  5120. // If the SID of the inherited ACE doesn't match,
  5121. // we don't match.
  5122. //
  5123. if ( !RtlEqualSid( (PSID)&ChildAce->SidStart, (PSID)&InheritedAce->SidStart )) {
  5124. //
  5125. // The inheritance algorithm only does SID mapping when building the effective
  5126. // ace. So, we only check for a mapped SID if the child ACE is an effective ACE.
  5127. //
  5128. if ( AceFlagsInAce(ChildAce) != EFFECTIVE_ACE ) {
  5129. #if DBG
  5130. if ( RtlpVerboseConvert ) {
  5131. KdPrint(("SID mismatch"));
  5132. }
  5133. #endif // DBG
  5134. return FALSE;
  5135. }
  5136. //
  5137. // In the case of CreatorOwner and CreatorGroup, the SIDs don't have to
  5138. // exactly match. When the InheritedAce was generated, care was taken
  5139. // to NOT map these sids. The SID may (or may not) have been mapped in
  5140. // the ChildAce. We want to compare equal in both cases.
  5141. //
  5142. // If the InheritedAce contains a CreatorOwner/Group SID,
  5143. // do the another comparison of the SID in the child ACE with the
  5144. // real owner/group from the child security descriptor.
  5145. //
  5146. if ( OwnerSid != NULL || GroupSid != NULL ) {
  5147. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  5148. ULONG CreatorSid[CREATOR_SID_SIZE];
  5149. //
  5150. // Allocate and initialize the universal SIDs we're going to need
  5151. // to look for inheritable ACEs.
  5152. //
  5153. ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
  5154. Status = RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
  5155. if ( !NT_SUCCESS(Status) ) {
  5156. return FALSE;
  5157. }
  5158. *(RtlpSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_OWNER_RID;
  5159. if (RtlEqualPrefixSid ( (PSID)&InheritedAce->SidStart, CreatorSid )) {
  5160. ULONG Rid;
  5161. Rid = *RtlpSubAuthoritySid( (PSID)&InheritedAce->SidStart, 0 );
  5162. switch (Rid) {
  5163. case SECURITY_CREATOR_OWNER_RID:
  5164. if ( OwnerSid == NULL ||
  5165. !RtlEqualSid( (PSID)&ChildAce->SidStart, OwnerSid )) {
  5166. #if DBG
  5167. if ( RtlpVerboseConvert ) {
  5168. KdPrint(("SID mismatch (Creator Owner)"));
  5169. }
  5170. #endif // DBG
  5171. return FALSE;
  5172. }
  5173. break;
  5174. case SECURITY_CREATOR_GROUP_RID:
  5175. if ( GroupSid == NULL ||
  5176. !RtlEqualSid( (PSID)&ChildAce->SidStart, GroupSid )) {
  5177. #if DBG
  5178. if ( RtlpVerboseConvert ) {
  5179. KdPrint(("SID mismatch (Creator Group)"));
  5180. }
  5181. #endif // DBG
  5182. return FALSE;
  5183. }
  5184. break;
  5185. default:
  5186. #if DBG
  5187. if ( RtlpVerboseConvert ) {
  5188. KdPrint(("SID mismatch (Creator)"));
  5189. }
  5190. #endif // DBG
  5191. return FALSE;
  5192. }
  5193. } else {
  5194. #if DBG
  5195. if ( RtlpVerboseConvert ) {
  5196. KdPrint(("SID mismatch"));
  5197. }
  5198. #endif // DBG
  5199. return FALSE;
  5200. }
  5201. } else {
  5202. #if DBG
  5203. if ( RtlpVerboseConvert ) {
  5204. KdPrint(("SID mismatch"));
  5205. }
  5206. #endif // DBG
  5207. return FALSE;
  5208. }
  5209. }
  5210. return TRUE;
  5211. }
  5212. BOOLEAN
  5213. RtlpCompareKnownObjectAces(
  5214. IN PKNOWN_OBJECT_ACE InheritedAce,
  5215. IN PKNOWN_OBJECT_ACE ChildAce,
  5216. IN PSID OwnerSid OPTIONAL,
  5217. IN PSID GroupSid OPTIONAL
  5218. )
  5219. /*++
  5220. Routine Description:
  5221. Compare two aces to see if they are "substantially" the same.
  5222. Arguments:
  5223. InheritedAce - Computed ACE as inherited from DirectoryAcl.
  5224. ChildAce - The current acl on the object. This ACL must be a revision 2 ACL.
  5225. ObjectType - GUID of the object type being created. If the object being
  5226. created has no GUID associated with it, then this argument is
  5227. specified as NULL.
  5228. OwnerSid - Specifies the owner Sid to use.
  5229. If not specified, the owner sid is not treated as special.
  5230. GroupSid - Specifies the group SID to use.
  5231. If not specified, the group sid is not treated as special.
  5232. Return Value:
  5233. TRUE - The ACEs are substantially the same.
  5234. FALSE - The ACEs are not substantially the same.
  5235. --*/
  5236. {
  5237. NTSTATUS Status;
  5238. BOOLEAN DoingObjectAces;
  5239. GUID *ChildObjectGuid;
  5240. GUID *InhObjectGuid;
  5241. GUID *ChildInheritedObjectGuid;
  5242. GUID *InhInheritedObjectGuid;
  5243. ACE_HEADER volatile *InheritedAceHdr = &InheritedAce->Header;
  5244. RTL_PAGED_CODE();
  5245. ASSERT(IsObjectAceType(InheritedAce));
  5246. ASSERT(IsObjectAceType(ChildAce));
  5247. //
  5248. // If the Ace types are different,
  5249. // we don't match.
  5250. //
  5251. if ( RtlBaseAceType[ChildAce->Header.AceType] != RtlBaseAceType[InheritedAceHdr->AceType] ) {
  5252. #if DBG
  5253. if ( RtlpVerboseConvert ) {
  5254. KdPrint(("AceType mismatch"));
  5255. }
  5256. #endif // DBG
  5257. return FALSE;
  5258. }
  5259. //
  5260. // If this is a system ACE,
  5261. // ensure the SUCCESS/FAILURE flags match.
  5262. //
  5263. if ( RtlIsSystemAceType[ChildAce->Header.AceType] ) {
  5264. if ( (ChildAce->Header.AceFlags & (SUCCESSFUL_ACCESS_ACE_FLAG|FAILED_ACCESS_ACE_FLAG)) !=
  5265. (InheritedAceHdr->AceFlags & (SUCCESSFUL_ACCESS_ACE_FLAG|FAILED_ACCESS_ACE_FLAG)) ) {
  5266. #if DBG
  5267. if ( RtlpVerboseConvert ) {
  5268. KdPrint(("System ace success/fail mismatch"));
  5269. }
  5270. #endif // DBG
  5271. return FALSE;
  5272. }
  5273. }
  5274. //
  5275. // Get the GUIDs from the Object Aces
  5276. //
  5277. ChildObjectGuid = RtlObjectAceObjectType(ChildAce);
  5278. ChildInheritedObjectGuid = RtlObjectAceInheritedObjectType(ChildAce);
  5279. InhObjectGuid = RtlObjectAceObjectType(InheritedAce);
  5280. InhInheritedObjectGuid = RtlObjectAceInheritedObjectType(InheritedAce);
  5281. //
  5282. // If the InheritedObjectGuid is present in either ACE,
  5283. // they must be equal.
  5284. //
  5285. if ( ChildInheritedObjectGuid != NULL || InhInheritedObjectGuid != NULL ) {
  5286. if ( ChildInheritedObjectGuid == NULL ||
  5287. InhInheritedObjectGuid == NULL ||
  5288. !RtlpIsEqualGuid( ChildInheritedObjectGuid, InhInheritedObjectGuid )) {
  5289. #if DBG
  5290. if ( RtlpVerboseConvert ) {
  5291. KdPrint(("InheritedObject GUID mismatch"));
  5292. }
  5293. #endif // DBG
  5294. return FALSE;
  5295. }
  5296. }
  5297. //
  5298. // If the ObjectGUID is present in either ACE,
  5299. // they must be equal.
  5300. //
  5301. // Any missing object GUID defaults to the passed in object GUID.
  5302. //
  5303. if ( (ChildObjectGuid != NULL) && (InhObjectGuid != NULL) ) {
  5304. if (!RtlpIsEqualGuid( ChildObjectGuid, InhObjectGuid )) {
  5305. #if DBG
  5306. if ( RtlpVerboseConvert ) {
  5307. KdPrint(("Object GUID mismatch"));
  5308. }
  5309. #endif // DBG
  5310. return( FALSE );
  5311. }
  5312. } else {
  5313. //
  5314. // One or both is NULL, if it's only one, they don't match.
  5315. //
  5316. if ( !((ChildObjectGuid == NULL) && (InhObjectGuid == NULL)) ) {
  5317. #if DBG
  5318. if ( RtlpVerboseConvert ) {
  5319. KdPrint(("Object GUID mismatch"));
  5320. }
  5321. #endif // DBG
  5322. return( FALSE );
  5323. }
  5324. }
  5325. //
  5326. // If the SID of the inherited ACE doesn't match,
  5327. // we don't match.
  5328. //
  5329. if ( !RtlEqualSid( RtlObjectAceSid(ChildAce), RtlObjectAceSid(InheritedAce))) {
  5330. //
  5331. // The inheritance algorithm only does SID mapping when building the effective
  5332. // ace. So, we only check for a mapped SID if the child ACE is an effective ACE.
  5333. //
  5334. if ( AceFlagsInAce(ChildAce) != EFFECTIVE_ACE ) {
  5335. #if DBG
  5336. if ( RtlpVerboseConvert ) {
  5337. KdPrint(("SID mismatch"));
  5338. }
  5339. #endif // DBG
  5340. return FALSE;
  5341. }
  5342. //
  5343. // In the case of CreatorOwner and CreatorGroup, the SIDs don't have to
  5344. // exactly match. When the InheritedAce was generated, care was taken
  5345. // to NOT map these sids. The SID may (or may not) have been mapped in
  5346. // the ChildAce. We want to compare equal in both cases.
  5347. //
  5348. // If the InheritedAce contains a CreatorOwner/Group SID,
  5349. // do the another comparison of the SID in the child ACE with the
  5350. // real owner/group from the child security descriptor.
  5351. //
  5352. if ( OwnerSid != NULL || GroupSid != NULL ) {
  5353. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  5354. ULONG CreatorSid[CREATOR_SID_SIZE];
  5355. //
  5356. // Allocate and initialize the universal SIDs we're going to need
  5357. // to look for inheritable ACEs.
  5358. //
  5359. ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
  5360. Status = RtlInitializeSid( (PSID)CreatorSid, &CreatorSidAuthority, 1 );
  5361. if ( !NT_SUCCESS(Status) ) {
  5362. return FALSE;
  5363. }
  5364. *(RtlpSubAuthoritySid( (PSID)CreatorSid, 0 )) = SECURITY_CREATOR_OWNER_RID;
  5365. if (RtlEqualPrefixSid ( RtlObjectAceSid(InheritedAce), CreatorSid )) {
  5366. ULONG Rid;
  5367. Rid = *RtlpSubAuthoritySid( RtlObjectAceSid(InheritedAce), 0 );
  5368. switch (Rid) {
  5369. case SECURITY_CREATOR_OWNER_RID:
  5370. if ( OwnerSid == NULL ||
  5371. !RtlEqualSid( RtlObjectAceSid(ChildAce), OwnerSid )) {
  5372. #if DBG
  5373. if ( RtlpVerboseConvert ) {
  5374. KdPrint(("SID mismatch (Creator Owner)"));
  5375. }
  5376. #endif // DBG
  5377. return FALSE;
  5378. }
  5379. break;
  5380. case SECURITY_CREATOR_GROUP_RID:
  5381. if ( GroupSid == NULL ||
  5382. !RtlEqualSid( RtlObjectAceSid(ChildAce), GroupSid )) {
  5383. #if DBG
  5384. if ( RtlpVerboseConvert ) {
  5385. KdPrint(("SID mismatch (Creator Group)"));
  5386. }
  5387. #endif // DBG
  5388. return FALSE;
  5389. }
  5390. break;
  5391. default:
  5392. #if DBG
  5393. if ( RtlpVerboseConvert ) {
  5394. KdPrint(("SID mismatch (Creator)"));
  5395. }
  5396. #endif // DBG
  5397. return FALSE;
  5398. }
  5399. } else {
  5400. #if DBG
  5401. if ( RtlpVerboseConvert ) {
  5402. KdPrint(("SID mismatch"));
  5403. }
  5404. #endif // DBG
  5405. return FALSE;
  5406. }
  5407. } else {
  5408. #if DBG
  5409. if ( RtlpVerboseConvert ) {
  5410. KdPrint(("SID mismatch"));
  5411. }
  5412. #endif // DBG
  5413. return FALSE;
  5414. }
  5415. }
  5416. return TRUE;
  5417. }
  5418. NTSTATUS
  5419. RtlpConvertAclToAutoInherit (
  5420. IN PACL ParentAcl OPTIONAL,
  5421. IN PACL ChildAcl,
  5422. IN GUID *ObjectType OPTIONAL,
  5423. IN BOOLEAN IsDirectoryObject,
  5424. IN PSID OwnerSid,
  5425. IN PSID GroupSid,
  5426. IN PGENERIC_MAPPING GenericMapping,
  5427. OUT PACL *NewAcl,
  5428. OUT PULONG NewGenericControl
  5429. )
  5430. /*++
  5431. Routine Description:
  5432. This is a private routine that produces an auto inherited acl from
  5433. a ChildAcl that is not marked as auto inherited. The passed in InheritedAcl
  5434. is computed as the pure inherited ACL of Parent ACL of the object.
  5435. See comments for RtlConvertToAutoInheritSecurityObject.
  5436. Arguments:
  5437. ParentAcl - Supplies the ACL of the parent object.
  5438. ChildAcl - Supplies the acl associated with the object. This
  5439. is the current acl on the object.
  5440. ObjectType - GUID of the object type being created. If the object being
  5441. created has no GUID associated with it, then this argument is
  5442. specified as NULL.
  5443. IsDirectoryObject - Specifies if the object is a
  5444. directory object. A value of TRUE indicates the object is a
  5445. container of other objects.
  5446. OwnerSid - Specifies the owner Sid to use.
  5447. GroupSid - Specifies the group SID to use.
  5448. GenericMapping - Specifies the generic mapping to use.
  5449. NewAcl - Receives a pointer to the new (auto inherited) acl.
  5450. The ACL must be deallocated using the pool (kernel mode) or
  5451. heap (user mode) deallocator.
  5452. NewGenericControl - Specifies the control flags for the newly
  5453. generated ACL.
  5454. SEP_ACL_PRESENT: Specifies that the ACL is explictly supplied by
  5455. the caller. ?? Ever set?
  5456. SEP_ACL_DEFAULTED: Specifies that the ACL was supplied by some
  5457. defaulting mechanism. ?? Ever set
  5458. SEP_ACL_AUTO_INHERITED: Set if the ACL was generated using the
  5459. Automatic Inheritance algorithm.
  5460. SEP_ACL_PROTECTED: Specifies that the ACL is protected and
  5461. was not inherited from the parent ACL.
  5462. Return Value:
  5463. STATUS_SUCCESS - An inheritable ACL was successfully generated.
  5464. STATUS_UNKNOWN_REVISION - Indicates the source ACL is a revision that
  5465. is unknown to this routine.
  5466. STATUS_INVALID_ACL - The structure of one of the ACLs in invalid.
  5467. --*/
  5468. {
  5469. NTSTATUS Status;
  5470. PACL InheritedAcl = NULL;
  5471. PACL RealInheritedAcl = NULL;
  5472. BOOLEAN AclExplicitlyAssigned;
  5473. ULONG GenericControl;
  5474. PKNOWN_ACE ChildAce = NULL;
  5475. PKNOWN_ACE InheritedAce;
  5476. LONG ChildAceIndex;
  5477. LONG InheritedAceIndex;
  5478. BOOLEAN InheritedAllowFound;
  5479. BOOLEAN InheritedDenyFound;
  5480. BOOLEAN AcesCompare;
  5481. ACCESS_MASK InheritedContainerInheritMask;
  5482. ACCESS_MASK InheritedObjectInheritMask;
  5483. ACCESS_MASK InheritedEffectiveMask;
  5484. ACCESS_MASK OriginalInheritedContainerInheritMask;
  5485. ACCESS_MASK OriginalInheritedObjectInheritMask;
  5486. ACCESS_MASK OriginalInheritedEffectiveMask;
  5487. ULONG InheritedAceFlags;
  5488. ULONG MatchedFlags;
  5489. ULONG NonInheritedAclSize;
  5490. PACE_HEADER AceHeader;
  5491. PUCHAR Where;
  5492. // ULONG i;
  5493. //
  5494. // This routine maintains an array of the structure below (one element per ACE in
  5495. // the ChildAcl).
  5496. //
  5497. // The ACE is broken down into its component parts. The access mask is triplicated.
  5498. // That is, if the ACE is a ContainerInherit ACE, the access mask is remembered as
  5499. // being a "ContainerInheritMask". The same is true if the ACE is an ObjectInherit ACE
  5500. // on an effective ACE. This is done since each of the resultant 96 bits are
  5501. // individually matched against corresponding bits in the computed inherited ACE.
  5502. //
  5503. // Each of the above mentioned masks are maintained in two forms. The first is never
  5504. // changed and represents the bits as the originally appeared in the child ACL.
  5505. // This second is modified as the corresponding bits are matched in the inherited ACL.
  5506. // When the algorithm is completed, bits that haven't been matched represent ACEs
  5507. // that weren't inherited from the parent.
  5508. //
  5509. typedef struct {
  5510. ACCESS_MASK OriginalContainerInheritMask;
  5511. ACCESS_MASK OriginalObjectInheritMask;
  5512. ACCESS_MASK OriginalEffectiveMask;
  5513. ACCESS_MASK ContainerInheritMask;
  5514. ACCESS_MASK ObjectInheritMask;
  5515. ACCESS_MASK EffectiveMask;
  5516. } ACE_INFO, *PACE_INFO;
  5517. PACE_INFO ChildAceInfo = NULL;
  5518. ULONG CreatorOwnerSid[CREATOR_SID_SIZE];
  5519. ULONG CreatorGroupSid[CREATOR_SID_SIZE];
  5520. SID_IDENTIFIER_AUTHORITY CreatorSidAuthority = SECURITY_CREATOR_SID_AUTHORITY;
  5521. #ifndef NTOS_KERNEL_RUNTIME
  5522. PVOID HeapHandle;
  5523. #endif // NTOS_KERNEL_RUNTIME
  5524. RTL_PAGED_CODE();
  5525. //
  5526. // Get the handle to the current process heap
  5527. //
  5528. #ifndef NTOS_KERNEL_RUNTIME
  5529. HeapHandle = RtlProcessHeap();
  5530. #endif // NTOS_KERNEL_RUNTIME
  5531. //
  5532. // Allocate and initialize the universal SIDs we're going to need
  5533. // to look for inheritable ACEs.
  5534. //
  5535. ASSERT(RtlLengthRequiredSid( 1 ) == CREATOR_SID_SIZE);
  5536. Status = RtlInitializeSid( (PSID)CreatorOwnerSid, &CreatorSidAuthority, 1 );
  5537. if ( !NT_SUCCESS(Status) ) {
  5538. goto Cleanup;
  5539. }
  5540. *(RtlpSubAuthoritySid( (PSID)CreatorOwnerSid, 0 )) = SECURITY_CREATOR_OWNER_RID;
  5541. Status = RtlInitializeSid( (PSID)CreatorGroupSid, &CreatorSidAuthority, 1 );
  5542. if ( !NT_SUCCESS(Status) ) {
  5543. goto Cleanup;
  5544. }
  5545. *(RtlpSubAuthoritySid( (PSID)CreatorGroupSid, 0 )) = SECURITY_CREATOR_GROUP_RID;
  5546. //
  5547. // Ensure the passed in ACLs are valid.
  5548. //
  5549. *NewGenericControl = SEP_ACL_AUTO_INHERITED;
  5550. *NewAcl = NULL;
  5551. if ( ParentAcl != NULL && !RtlValidAcl( ParentAcl ) ) {
  5552. Status = STATUS_INVALID_ACL;
  5553. goto Cleanup;
  5554. }
  5555. if (!RtlValidAcl( ChildAcl ) ) {
  5556. Status = STATUS_INVALID_ACL;
  5557. goto Cleanup;
  5558. }
  5559. //
  5560. // Compute what the inherited ACL "should" look like.
  5561. //
  5562. // The inherited ACL is computed to NOT SID-map Creator Owner and Creator Group.
  5563. // This allows use to later recognize the constant SIDs and special case them
  5564. // rather than mistakenly confuse them with the mapped SID.
  5565. //
  5566. Status = RtlpInheritAcl (
  5567. ParentAcl,
  5568. NULL, // No explicit child ACL
  5569. 0, // No Child Generic Control
  5570. IsDirectoryObject,
  5571. TRUE, // AutoInherit the DACL
  5572. FALSE, // Not default descriptor for object
  5573. CreatorOwnerSid, // Subsitute a constant SID
  5574. CreatorGroupSid, // Subsitute a constant SID
  5575. CreatorOwnerSid, // Server Owner (Technically incorrect, but OK since we don't support compound ACEs)
  5576. CreatorGroupSid, // Server Group
  5577. GenericMapping,
  5578. TRUE, // Is a SACL
  5579. ObjectType ? &ObjectType : NULL,
  5580. ObjectType ? 1 : 0,
  5581. &InheritedAcl,
  5582. &AclExplicitlyAssigned,
  5583. &GenericControl );
  5584. if ( Status == STATUS_NO_INHERITANCE ) {
  5585. *NewGenericControl |= SEP_ACL_PROTECTED;
  5586. #if DBG
  5587. if ( RtlpVerboseConvert ) {
  5588. KdPrint(("NO_INHERITANCE of the parent ACL\n" ));
  5589. }
  5590. #endif // DBG
  5591. Status = STATUS_SUCCESS;
  5592. goto Cleanup;
  5593. }
  5594. if ( !NT_SUCCESS(Status) ) {
  5595. #if DBG
  5596. if ( RtlpVerboseConvert ) {
  5597. KdPrint(("Can't build inherited ACL %lX\n", Status ));
  5598. }
  5599. #endif // DBG
  5600. goto Cleanup;
  5601. }
  5602. //
  5603. // Allocate a work buffer describing the ChildAcl
  5604. //
  5605. #ifdef NTOS_KERNEL_RUNTIME
  5606. ChildAceInfo = ExAllocatePoolWithTag(
  5607. PagedPool,
  5608. ChildAcl->AceCount * sizeof(ACE_INFO),
  5609. 'cAeS' );
  5610. #else // NTOS_KERNEL_RUNTIME
  5611. ChildAceInfo = RtlAllocateHeap(
  5612. HeapHandle,
  5613. MAKE_TAG(SE_TAG),
  5614. ChildAcl->AceCount * sizeof(ACE_INFO) );
  5615. #endif // NTOS_KERNEL_RUNTIME
  5616. if (ChildAceInfo == NULL ) {
  5617. Status = STATUS_NO_MEMORY;
  5618. goto Cleanup;
  5619. }
  5620. for (ChildAceIndex = 0, ChildAce = FirstAce(ChildAcl);
  5621. ChildAceIndex < ChildAcl->AceCount;
  5622. ChildAceIndex += 1, ChildAce = NextAce(ChildAce)) {
  5623. ACCESS_MASK LocalMask;
  5624. ULONG ChildAceFlags;
  5625. if ( !IsV4AceType(ChildAce) || IsCompoundAceType(ChildAce)) {
  5626. *NewGenericControl |= SEP_ACL_PROTECTED;
  5627. #if DBG
  5628. if ( RtlpVerboseConvert ) {
  5629. KdPrint(("Inherited Ace type (%ld) not known\n", ChildAce->Header.AceType ));
  5630. }
  5631. #endif // DBG
  5632. Status = STATUS_SUCCESS;
  5633. goto Cleanup;
  5634. }
  5635. //
  5636. // Compute the generic mapped mask for use in all comparisons. The
  5637. // generic mapping will be undone if needed later.
  5638. //
  5639. // All V4 aces have an access mask in the same location.
  5640. //
  5641. LocalMask = ((PKNOWN_ACE)(ChildAce))->Mask;
  5642. RtlApplyGenericMask( ChildAce, &LocalMask, GenericMapping);
  5643. //
  5644. // Break the ACE into its component parts.
  5645. //
  5646. ChildAceFlags = AceFlagsInAce( ChildAce );
  5647. if ( ChildAceFlags & CONTAINER_INHERIT_ACE ) {
  5648. ChildAceInfo[ChildAceIndex].OriginalContainerInheritMask = LocalMask;
  5649. ChildAceInfo[ChildAceIndex].ContainerInheritMask = LocalMask;
  5650. } else {
  5651. ChildAceInfo[ChildAceIndex].OriginalContainerInheritMask = 0;
  5652. ChildAceInfo[ChildAceIndex].ContainerInheritMask = 0;
  5653. }
  5654. if ( ChildAceFlags & OBJECT_INHERIT_ACE ) {
  5655. ChildAceInfo[ChildAceIndex].OriginalObjectInheritMask = LocalMask;
  5656. ChildAceInfo[ChildAceIndex].ObjectInheritMask = LocalMask;
  5657. } else {
  5658. ChildAceInfo[ChildAceIndex].OriginalObjectInheritMask = 0;
  5659. ChildAceInfo[ChildAceIndex].ObjectInheritMask = 0;
  5660. }
  5661. if ( ChildAceFlags & EFFECTIVE_ACE ) {
  5662. ChildAceInfo[ChildAceIndex].OriginalEffectiveMask = LocalMask;
  5663. ChildAceInfo[ChildAceIndex].EffectiveMask = LocalMask;
  5664. } else {
  5665. ChildAceInfo[ChildAceIndex].OriginalEffectiveMask = 0;
  5666. ChildAceInfo[ChildAceIndex].EffectiveMask = 0;
  5667. }
  5668. }
  5669. //
  5670. // Walk through the computed inherited ACL one ACE at a time.
  5671. //
  5672. for (InheritedAceIndex = 0, InheritedAce = FirstAce(InheritedAcl);
  5673. InheritedAceIndex < InheritedAcl->AceCount;
  5674. InheritedAceIndex += 1, InheritedAce = NextAce(InheritedAce)) {
  5675. ACCESS_MASK LocalMask;
  5676. //
  5677. // If the ACE isn't a valid version 4 ACE,
  5678. // this isn't an ACL we're interested in handling.
  5679. //
  5680. if ( !IsV4AceType(InheritedAce) || IsCompoundAceType(InheritedAce)) {
  5681. *NewGenericControl |= SEP_ACL_PROTECTED;
  5682. #if DBG
  5683. if ( RtlpVerboseConvert ) {
  5684. KdPrint(("Inherited Ace type (%ld) not known\n", InheritedAce->Header.AceType ));
  5685. }
  5686. #endif // DBG
  5687. Status = STATUS_SUCCESS;
  5688. goto Cleanup;
  5689. }
  5690. //
  5691. // Compute the generic mapped mask for use in all comparisons. The
  5692. // generic mapping will be undone if needed later.
  5693. //
  5694. // All V4 aces have an access mask in the same location.
  5695. //
  5696. LocalMask = ((PKNOWN_ACE)(InheritedAce))->Mask;
  5697. RtlApplyGenericMask( InheritedAce, &LocalMask, GenericMapping);
  5698. if ( LocalMask == 0 ) {
  5699. #if DBG
  5700. if ( RtlpVerboseConvert ) {
  5701. KdPrint(("Worthless INH ACE: %ld 0x%8.8lx\n", InheritedAceIndex, LocalMask ));
  5702. }
  5703. #endif // DBG
  5704. continue;
  5705. }
  5706. //
  5707. // This ACE is some combination of an effective ACE, a container
  5708. // inherit ACE and an object inherit ACE. Process each of those
  5709. // attributes separately since they might be represented separately
  5710. // in the ChildAcl.
  5711. //
  5712. InheritedAceFlags = AceFlagsInAce( InheritedAce );
  5713. if ( InheritedAceFlags == 0 ) {
  5714. #if DBG
  5715. if ( RtlpVerboseConvert ) {
  5716. KdPrint(("Worthless INH ACE: %ld 0x%lx\n", InheritedAceIndex, InheritedAceFlags ));
  5717. }
  5718. #endif // DBG
  5719. continue;
  5720. }
  5721. if ( InheritedAceFlags & CONTAINER_INHERIT_ACE ) {
  5722. OriginalInheritedContainerInheritMask = InheritedContainerInheritMask = LocalMask;
  5723. } else {
  5724. OriginalInheritedContainerInheritMask = InheritedContainerInheritMask = 0;
  5725. }
  5726. if ( InheritedAceFlags & OBJECT_INHERIT_ACE ) {
  5727. OriginalInheritedObjectInheritMask = InheritedObjectInheritMask = LocalMask;
  5728. } else {
  5729. OriginalInheritedObjectInheritMask = InheritedObjectInheritMask = 0;
  5730. }
  5731. if ( InheritedAceFlags & EFFECTIVE_ACE ) {
  5732. OriginalInheritedEffectiveMask = InheritedEffectiveMask = LocalMask;
  5733. } else {
  5734. OriginalInheritedEffectiveMask = InheritedEffectiveMask = 0;
  5735. }
  5736. #if DBG
  5737. if ( RtlpVerboseConvert ) {
  5738. KdPrint(("Doing INH ACE: %ld %8.8lX %8.8lX %8.8lX\n", InheritedAceIndex, InheritedEffectiveMask, InheritedContainerInheritMask, InheritedObjectInheritMask ));
  5739. }
  5740. #endif // DBG
  5741. //
  5742. // Loop through the entire child ACL comparing each inherited ACE with
  5743. // each child ACE. Don't stop simply because we've matched once.
  5744. // Multiple ACEs in the one ACL may have been condensed into a single ACE
  5745. // in the other ACL in any combination (by any of our friendly ACL editors).
  5746. // In all cases, it is better to compute a resultant auto inherited ACL
  5747. // than it is to compute a protected ACL.
  5748. //
  5749. for (ChildAceIndex = 0, ChildAce = FirstAce(ChildAcl);
  5750. ChildAceIndex < ChildAcl->AceCount;
  5751. ChildAceIndex += 1, ChildAce = NextAce(ChildAce)) {
  5752. //
  5753. // Ensure the ACE represents the same principal and object,
  5754. //
  5755. #if DBG
  5756. if ( RtlpVerboseConvert ) {
  5757. KdPrint(("Compare Child Ace: %ld ", ChildAceIndex ));
  5758. }
  5759. #endif // DBG
  5760. if ( !RtlpCompareAces( InheritedAce,
  5761. ChildAce,
  5762. OwnerSid,
  5763. GroupSid ) ) {
  5764. #if DBG
  5765. if ( RtlpVerboseConvert ) {
  5766. KdPrint(("\n" ));
  5767. }
  5768. #endif // DBG
  5769. continue;
  5770. }
  5771. #if DBG
  5772. if ( RtlpVerboseConvert ) {
  5773. KdPrint(("\n" ));
  5774. }
  5775. #endif // DBG
  5776. //
  5777. // Match as many access bits in the INH ACE as possible.
  5778. //
  5779. // Don't pay any attention to whether the bits have been previously matched
  5780. // in the CHILD ACE. To do so, would imply that there is a one-to-one
  5781. // correspondance between bits in the INH ACL and Child ACL. Unfortunately,
  5782. // ACL editors feel free to compress out duplicate bits in both
  5783. // the CHILD ACL and PARENT ACL as they see fit.
  5784. //
  5785. InheritedEffectiveMask &= ~ChildAceInfo[ChildAceIndex].OriginalEffectiveMask;
  5786. InheritedContainerInheritMask &= ~ChildAceInfo[ChildAceIndex].OriginalContainerInheritMask;
  5787. InheritedObjectInheritMask &= ~ChildAceInfo[ChildAceIndex].OriginalObjectInheritMask;
  5788. #if DBG
  5789. if ( RtlpVerboseConvert ) {
  5790. KdPrint(("New INH MASKs %ld %8.8lX %8.8lX %8.8lX\n", InheritedAceIndex, InheritedEffectiveMask, InheritedContainerInheritMask, InheritedObjectInheritMask ));
  5791. }
  5792. #endif // DBG
  5793. //
  5794. // Match as many access bits in the child ACE as possible.
  5795. //
  5796. // Same reasoning as above.
  5797. //
  5798. ChildAceInfo[ChildAceIndex].EffectiveMask &= ~OriginalInheritedEffectiveMask;
  5799. ChildAceInfo[ChildAceIndex].ContainerInheritMask &= ~OriginalInheritedContainerInheritMask;
  5800. ChildAceInfo[ChildAceIndex].ObjectInheritMask &= ~OriginalInheritedObjectInheritMask;
  5801. #if DBG
  5802. if ( RtlpVerboseConvert ) {
  5803. KdPrint(("New Child MASKs %ld %8.8lX %8.8lX %8.8lX\n", ChildAceIndex, ChildAceInfo[ChildAceIndex].EffectiveMask, ChildAceInfo[ChildAceIndex].ContainerInheritMask, ChildAceInfo[ChildAceIndex].ObjectInheritMask ));
  5804. }
  5805. #endif // DBG
  5806. }
  5807. //
  5808. // If we couldn't process this inherited ACE,
  5809. // then the child ACL wasn't inherited.
  5810. //
  5811. if ( (InheritedEffectiveMask | InheritedContainerInheritMask | InheritedObjectInheritMask) != 0 ) {
  5812. *NewGenericControl |= SEP_ACL_PROTECTED;
  5813. #if DBG
  5814. if ( RtlpVerboseConvert ) {
  5815. KdPrint(("INH ACE not completely matched: %ld %8.8lX %8.8lX %8.8lX\n", InheritedAceIndex, InheritedEffectiveMask, InheritedContainerInheritMask, InheritedObjectInheritMask ));
  5816. }
  5817. #endif // DBG
  5818. Status = STATUS_SUCCESS;
  5819. goto Cleanup;
  5820. }
  5821. }
  5822. //
  5823. // ASSERT: All of the inherited ACEs have been processed.
  5824. //
  5825. //
  5826. // Loop through the Child ACL ensuring we can build a valid auto inherited ACL
  5827. //
  5828. InheritedAllowFound = FALSE;
  5829. InheritedDenyFound = FALSE;
  5830. NonInheritedAclSize = 0;
  5831. for (ChildAceIndex = 0, ChildAce = FirstAce(ChildAcl);
  5832. ChildAceIndex < ChildAcl->AceCount;
  5833. ChildAceIndex += 1, ChildAce = NextAce(ChildAce)) {
  5834. ACCESS_MASK ResultantMask;
  5835. //
  5836. // Any Child ACE access bits not eliminated above required than an
  5837. // explicit non-inherited ACE by built. That ACE will have an
  5838. // access mask that is the combined access mask of the unmatched bit
  5839. // in the effective, container inherit, and object inherit categories.
  5840. // Even though, the combined mask may include access bits not absolutely
  5841. // required (since they were already inherited), this strategy prevents
  5842. // us from having to build multiple ACEs (one for each category) for this
  5843. // single ACE.
  5844. //
  5845. ResultantMask =
  5846. ChildAceInfo[ChildAceIndex].EffectiveMask |
  5847. ChildAceInfo[ChildAceIndex].ContainerInheritMask |
  5848. ChildAceInfo[ChildAceIndex].ObjectInheritMask;
  5849. //
  5850. // Handle an inherited ACE
  5851. //
  5852. if ( ResultantMask == 0 ) {
  5853. //
  5854. // Keep track of whether inherited "allow" and "deny" ACEs are found.
  5855. //
  5856. if ( RtlBaseAceType[ChildAce->Header.AceType] == ACCESS_ALLOWED_ACE_TYPE ) {
  5857. InheritedAllowFound = TRUE;
  5858. }
  5859. if ( RtlBaseAceType[ChildAce->Header.AceType] == ACCESS_DENIED_ACE_TYPE ) {
  5860. InheritedDenyFound = TRUE;
  5861. }
  5862. //
  5863. // Handle a non-inherited ACE
  5864. //
  5865. } else {
  5866. //
  5867. // Keep a running tab of the size of the non-inherited ACEs.
  5868. //
  5869. NonInheritedAclSize += ChildAce->Header.AceSize;
  5870. //
  5871. // Since non-inherited ACEs will be moved to the front of the ACL,
  5872. // we have to be careful that we don't move a deny ACE in front of a
  5873. // previously found inherited allow ACE (and vice-versa). To do so would
  5874. // change the semantics of the ACL.
  5875. //
  5876. if ( RtlBaseAceType[ChildAce->Header.AceType] == ACCESS_ALLOWED_ACE_TYPE && InheritedDenyFound ) {
  5877. *NewGenericControl |= SEP_ACL_PROTECTED;
  5878. #if DBG
  5879. if ( RtlpVerboseConvert ) {
  5880. KdPrint(("Previous deny found Child ACE: %ld\n", ChildAceIndex ));
  5881. }
  5882. #endif // DBG
  5883. Status = STATUS_SUCCESS;
  5884. goto Cleanup;
  5885. }
  5886. if ( RtlBaseAceType[ChildAce->Header.AceType] == ACCESS_DENIED_ACE_TYPE && InheritedAllowFound ) {
  5887. *NewGenericControl |= SEP_ACL_PROTECTED;
  5888. #if DBG
  5889. if ( RtlpVerboseConvert ) {
  5890. KdPrint(("Previous allow found Child ACE: %ld\n", ChildAceIndex ));
  5891. }
  5892. #endif // DBG
  5893. Status = STATUS_SUCCESS;
  5894. goto Cleanup;
  5895. }
  5896. }
  5897. }
  5898. //
  5899. // The resultant ACL is composed of the non-inherited ACEs followed by
  5900. // the inherited ACE. The inherited ACEs are built by running the
  5901. // inheritance algorithm over the Parent ACL.
  5902. //
  5903. // The Inherited ACL computed below is almost identical to InhertedAcl.
  5904. // However, InheritedAcl didn't properly substitute the correct owner and
  5905. // group SID.
  5906. //
  5907. Status = RtlpInheritAcl (
  5908. ParentAcl,
  5909. NULL, // No explicit child ACL
  5910. 0, // No Child Generic Control
  5911. IsDirectoryObject,
  5912. TRUE, // AutoInherit the DACL
  5913. FALSE, // Not default descriptor for object
  5914. OwnerSid, // Subsitute a constant SID
  5915. GroupSid, // Subsitute a constant SID
  5916. OwnerSid, // Server Owner (Technically incorrect, but OK since we don't support compound ACEs)
  5917. GroupSid, // Server Group
  5918. GenericMapping,
  5919. TRUE, // Is a SACL
  5920. ObjectType ? &ObjectType : NULL,
  5921. ObjectType ? 1 : 0,
  5922. &RealInheritedAcl,
  5923. &AclExplicitlyAssigned,
  5924. &GenericControl );
  5925. if ( !NT_SUCCESS(Status) ) {
  5926. #if DBG
  5927. if ( RtlpVerboseConvert ) {
  5928. KdPrint(("Can't build real inherited ACL %lX\n", Status ));
  5929. }
  5930. #endif // DBG
  5931. goto Cleanup;
  5932. }
  5933. //
  5934. // Allocate a buffer for the inherited ACL
  5935. //
  5936. #ifdef NTOS_KERNEL_RUNTIME
  5937. *NewAcl = ExAllocatePoolWithTag(
  5938. PagedPool,
  5939. RealInheritedAcl->AclSize + NonInheritedAclSize,
  5940. 'cAeS' );
  5941. #else // NTOS_KERNEL_RUNTIME
  5942. *NewAcl = RtlAllocateHeap(
  5943. HeapHandle,
  5944. MAKE_TAG(SE_TAG),
  5945. RealInheritedAcl->AclSize + NonInheritedAclSize );
  5946. #endif // NTOS_KERNEL_RUNTIME
  5947. if ( *NewAcl == NULL ) {
  5948. Status = STATUS_NO_MEMORY;
  5949. goto Cleanup;
  5950. }
  5951. //
  5952. // All non-inherited ACEs are copied first.
  5953. // The inherited ACES are grabbed from real inherited ACL.
  5954. //
  5955. // Build an ACL Header.
  5956. //
  5957. Status = RtlCreateAcl( *NewAcl,
  5958. RealInheritedAcl->AclSize + NonInheritedAclSize,
  5959. max( RealInheritedAcl->AclRevision, ChildAcl->AclRevision ) );
  5960. if ( !NT_SUCCESS(Status) ) {
  5961. #if DBG
  5962. if ( RtlpVerboseConvert ) {
  5963. KdPrint(("Can't create final ACL %lX\n", Status ));
  5964. }
  5965. #endif // DBG
  5966. //
  5967. // The only reason for failure would be if the combined ACL is too large.
  5968. // So just create a protected ACL (better than a failure).
  5969. //
  5970. *NewGenericControl |= SEP_ACL_PROTECTED;
  5971. Status = STATUS_SUCCESS;
  5972. goto Cleanup;
  5973. }
  5974. //
  5975. // Copy the non-inherited ACES.
  5976. //
  5977. Where = ((PUCHAR)(*NewAcl)) + sizeof(ACL);
  5978. for (ChildAceIndex = 0, ChildAce = FirstAce(ChildAcl);
  5979. ChildAceIndex < ChildAcl->AceCount;
  5980. ChildAceIndex += 1, ChildAce = NextAce(ChildAce)) {
  5981. ACCESS_MASK ResultantMask;
  5982. //
  5983. // Copy the non-inherited ACE from the Child only if there's a non-zero access mask.
  5984. //
  5985. ResultantMask =
  5986. ChildAceInfo[ChildAceIndex].EffectiveMask |
  5987. ChildAceInfo[ChildAceIndex].ContainerInheritMask |
  5988. ChildAceInfo[ChildAceIndex].ObjectInheritMask;
  5989. if ( ResultantMask != 0 ) {
  5990. PKNOWN_ACE NewAce;
  5991. ULONG GenericBitToTry;
  5992. //
  5993. // Use the original ChildAce as the template.
  5994. //
  5995. RtlCopyMemory( Where, ChildAce, ChildAce->Header.AceSize );
  5996. NewAce = (PKNOWN_ACE)Where;
  5997. NewAce->Header.AceFlags &= ~INHERITED_ACE; // Clear stray bits
  5998. Where += ChildAce->Header.AceSize;
  5999. (*NewAcl)->AceCount ++;
  6000. //
  6001. // The AccessMask on the ACE are those access bits that didn't get matched
  6002. // by inherited ACEs.
  6003. //
  6004. NewAce->Mask = ChildAce->Mask & ResultantMask;
  6005. ResultantMask &= ~ChildAce->Mask;
  6006. #if DBG
  6007. if ( RtlpVerboseConvert ) {
  6008. KdPrint(("Original non-inherited: %ld %8.8lX %8.8lX\n", ChildAceIndex, NewAce->Mask, ResultantMask ));
  6009. }
  6010. #endif // DBG
  6011. //
  6012. // Map any remaining bits back to generic access bits.
  6013. // Doing so might expand the ResultantMask to beyond what was computed above.
  6014. // Doing so will never expand the computed ACE to beyond what the original
  6015. // ChildAce granted.
  6016. //
  6017. ASSERT( GENERIC_WRITE == (GENERIC_READ >> 1));
  6018. ASSERT( GENERIC_EXECUTE == (GENERIC_WRITE >> 1));
  6019. ASSERT( GENERIC_ALL == (GENERIC_EXECUTE >> 1));
  6020. GenericBitToTry = GENERIC_READ;
  6021. while ( ResultantMask && GenericBitToTry >= GENERIC_ALL ) {
  6022. //
  6023. // Only map generic bits that are in the ChildAce.
  6024. //
  6025. if ( GenericBitToTry & ChildAce->Mask ) {
  6026. ACCESS_MASK GenericMask;
  6027. //
  6028. // Compute the real access mask corresponding to the Generic bit.
  6029. //
  6030. GenericMask = GenericBitToTry;
  6031. RtlMapGenericMask( &GenericMask, GenericMapping );
  6032. //
  6033. // If the current generic bit matches any of the bits remaining,
  6034. // set the generic bit in the current ACE.
  6035. //
  6036. if ( (ResultantMask & GenericMask) != 0 ) {
  6037. NewAce->Mask |= GenericBitToTry;
  6038. ResultantMask &= ~GenericMask;
  6039. }
  6040. #if DBG
  6041. if ( RtlpVerboseConvert ) {
  6042. KdPrint(("Generic non-inherited: %ld %8.8lX %8.8lX\n", ChildAceIndex, NewAce->Mask, ResultantMask ));
  6043. }
  6044. #endif // DBG
  6045. }
  6046. //
  6047. // Try the next Generic bit.
  6048. //
  6049. GenericBitToTry >>= 1;
  6050. }
  6051. //
  6052. // This is really an internal error, but press on regardless.
  6053. //
  6054. ASSERT(ResultantMask == 0 );
  6055. NewAce->Mask |= ResultantMask;
  6056. #if DBG
  6057. if ( RtlpVerboseConvert ) {
  6058. KdPrint(("Final non-inherited: %ld %8.8lX %8.8lX\n", ChildAceIndex, NewAce->Mask, ResultantMask ));
  6059. }
  6060. #endif // DBG
  6061. }
  6062. }
  6063. //
  6064. // Copy the inherited ACES.
  6065. // Simply copy computed Inherited ACL.
  6066. //
  6067. RtlCopyMemory( Where,
  6068. FirstAce(RealInheritedAcl),
  6069. RealInheritedAcl->AclSize - (ULONG)(((PUCHAR)FirstAce(RealInheritedAcl)) - (PUCHAR)RealInheritedAcl));
  6070. Where += RealInheritedAcl->AclSize - (ULONG)(((PUCHAR)FirstAce(RealInheritedAcl)) - (PUCHAR)RealInheritedAcl);
  6071. (*NewAcl)->AceCount += RealInheritedAcl->AceCount;
  6072. ASSERT( (*NewAcl)->AclSize == Where - (PUCHAR)(*NewAcl) );
  6073. Status = STATUS_SUCCESS;
  6074. Cleanup:
  6075. //
  6076. // If successful,
  6077. // build the resultant autoinherited ACL.
  6078. //
  6079. if ( NT_SUCCESS(Status) ) {
  6080. //
  6081. // If the Child ACL is protected,
  6082. // just build it as a copy of the original ACL
  6083. //
  6084. if ( *NewGenericControl & SEP_ACL_PROTECTED ) {
  6085. //
  6086. // If we've already allocated a new ACL (and couldn't finish it for some reason),
  6087. // free it.
  6088. if ( *NewAcl != NULL) {
  6089. #ifdef NTOS_KERNEL_RUNTIME
  6090. ExFreePool( *NewAcl );
  6091. #else // NTOS_KERNEL_RUNTIME
  6092. RtlFreeHeap( HeapHandle, 0, *NewAcl );
  6093. #endif // NTOS_KERNEL_RUNTIME
  6094. *NewAcl = NULL;
  6095. }
  6096. //
  6097. // Allocate a buffer for the protected ACL.
  6098. //
  6099. #ifdef NTOS_KERNEL_RUNTIME
  6100. *NewAcl = ExAllocatePoolWithTag(
  6101. PagedPool,
  6102. ChildAcl->AclSize,
  6103. 'cAeS' );
  6104. #else // NTOS_KERNEL_RUNTIME
  6105. *NewAcl = RtlAllocateHeap(
  6106. HeapHandle,
  6107. MAKE_TAG(SE_TAG),
  6108. ChildAcl->AclSize );
  6109. #endif // NTOS_KERNEL_RUNTIME
  6110. if ( *NewAcl == NULL ) {
  6111. Status = STATUS_NO_MEMORY;
  6112. } else {
  6113. RtlCopyMemory( *NewAcl, ChildAcl, ChildAcl->AclSize );
  6114. }
  6115. }
  6116. }
  6117. if ( ChildAceInfo != NULL) {
  6118. #ifdef NTOS_KERNEL_RUNTIME
  6119. ExFreePool( ChildAceInfo );
  6120. #else // NTOS_KERNEL_RUNTIME
  6121. RtlFreeHeap( HeapHandle, 0, ChildAceInfo );
  6122. #endif // NTOS_KERNEL_RUNTIME
  6123. }
  6124. if ( InheritedAcl != NULL) {
  6125. #ifdef NTOS_KERNEL_RUNTIME
  6126. ExFreePool( InheritedAcl );
  6127. #else // NTOS_KERNEL_RUNTIME
  6128. RtlFreeHeap( HeapHandle, 0, InheritedAcl );
  6129. #endif // NTOS_KERNEL_RUNTIME
  6130. }
  6131. if ( RealInheritedAcl != NULL) {
  6132. #ifdef NTOS_KERNEL_RUNTIME
  6133. ExFreePool( RealInheritedAcl );
  6134. #else // NTOS_KERNEL_RUNTIME
  6135. RtlFreeHeap( HeapHandle, 0, RealInheritedAcl );
  6136. #endif // NTOS_KERNEL_RUNTIME
  6137. }
  6138. return Status;
  6139. }
  6140. BOOLEAN
  6141. RtlpIsDuplicateAce(
  6142. IN PACL Acl,
  6143. IN PKNOWN_ACE NewAce
  6144. )
  6145. /*++
  6146. Routine Description:
  6147. This routine determine if an ACE is a duplicate of an ACE already in an
  6148. ACL. If so, the NewAce can be removed from the end of the ACL.
  6149. This routine currently only detects duplicate version 4 ACEs. If the
  6150. ACE isn't version 4, the ACE will be declared to be a non-duplicate.
  6151. This routine only detects duplicate INHERTED ACEs.
  6152. Arguments:
  6153. Acl - Existing ACL
  6154. NewAce - Ace to determine if it is already in Acl.
  6155. NewAce is expected to be the last ACE in "Acl".
  6156. Return Value:
  6157. TRUE - NewAce is a duplicate of another ACE on the Acl
  6158. FALSE - NewAce is NOT a duplicate of another ACE on the Acl
  6159. --*/
  6160. {
  6161. NTSTATUS Status;
  6162. BOOLEAN RetVal = FALSE;
  6163. LONG AceIndex;
  6164. ACCESS_MASK NewAceContainerInheritMask;
  6165. ACCESS_MASK NewAceObjectInheritMask;
  6166. ACCESS_MASK NewAceEffectiveMask;
  6167. ACCESS_MASK LocalMask;
  6168. PKNOWN_ACE AceFromAcl;
  6169. RTL_PAGED_CODE();
  6170. //
  6171. // Ensure the passed in ACE is one this routine understands
  6172. //
  6173. if ( !IsV4AceType(NewAce) || IsCompoundAceType(NewAce)) {
  6174. #if DBG
  6175. if ( RtlpVerboseConvert ) {
  6176. KdPrint(("New Ace type (%ld) not known\n", NewAce->Header.AceType ));
  6177. }
  6178. #endif // DBG
  6179. RetVal = FALSE;
  6180. goto Cleanup;
  6181. }
  6182. //
  6183. // This routine only works for ACEs marked as INHERITED.
  6184. //
  6185. if ( (NewAce->Header.AceFlags & INHERITED_ACE ) == 0 ) {
  6186. #if DBG
  6187. if ( RtlpVerboseConvert ) {
  6188. KdPrint(("New Ace type isn't inherited\n" ));
  6189. }
  6190. #endif // DBG
  6191. RetVal = FALSE;
  6192. goto Cleanup;
  6193. }
  6194. //
  6195. // Break the new ACE into its component parts.
  6196. //
  6197. // All V4 aces have an access mask in the same location.
  6198. //
  6199. LocalMask = ((PKNOWN_ACE)(NewAce))->Mask;
  6200. if ( NewAce->Header.AceFlags & CONTAINER_INHERIT_ACE ) {
  6201. NewAceContainerInheritMask = LocalMask;
  6202. } else {
  6203. NewAceContainerInheritMask = 0;
  6204. }
  6205. if ( NewAce->Header.AceFlags & OBJECT_INHERIT_ACE ) {
  6206. NewAceObjectInheritMask = LocalMask;
  6207. } else {
  6208. NewAceObjectInheritMask = 0;
  6209. }
  6210. if ( (NewAce->Header.AceFlags & INHERIT_ONLY_ACE) == 0 ) {
  6211. NewAceEffectiveMask = LocalMask;
  6212. } else {
  6213. NewAceEffectiveMask = 0;
  6214. }
  6215. #if DBG
  6216. if ( RtlpVerboseConvert ) {
  6217. KdPrint(("Starting MASKs: %8.8lX %8.8lX %8.8lX", NewAceEffectiveMask, NewAceContainerInheritMask, NewAceObjectInheritMask ));
  6218. }
  6219. #endif // DBG
  6220. //
  6221. // Walk through the ACL one ACE at a time.
  6222. //
  6223. for (AceIndex = 0, AceFromAcl = FirstAce(Acl);
  6224. AceIndex < Acl->AceCount-1; // NewAce is the last ACE
  6225. AceIndex += 1, AceFromAcl = NextAce(AceFromAcl)) {
  6226. //
  6227. // If the ACE isn't a valid version 4 ACE,
  6228. // this isn't an ACE we're interested in handling.
  6229. //
  6230. if ( !IsV4AceType(AceFromAcl) || IsCompoundAceType(AceFromAcl)) {
  6231. continue;
  6232. }
  6233. //
  6234. // This routine only works for ACEs marked as INHERITED.
  6235. //
  6236. if ( (AceFromAcl->Header.AceFlags & INHERITED_ACE ) == 0 ) {
  6237. continue;
  6238. }
  6239. //
  6240. // Compare the Ace from the ACL with the New ACE
  6241. //
  6242. // Don't stop simply because we've matched once.
  6243. // Multiple ACEs in the one ACL may have been condensed into a single ACE
  6244. // in the other ACL in any combination (by any of our friendly ACL editors).
  6245. //
  6246. #if DBG
  6247. if ( RtlpVerboseConvert ) {
  6248. KdPrint(("Compare Ace: %ld ", AceIndex ));
  6249. }
  6250. #endif // DBG
  6251. if ( RtlpCompareAces( AceFromAcl,
  6252. NewAce,
  6253. NULL,
  6254. NULL ) ) {
  6255. //
  6256. // Match the bits from the current ACE with bits from the New ACE.
  6257. //
  6258. // All V4 aces have an access mask in the same location.
  6259. //
  6260. LocalMask = ((PKNOWN_ACE)(AceFromAcl))->Mask;
  6261. if ( AceFromAcl->Header.AceFlags & CONTAINER_INHERIT_ACE ) {
  6262. NewAceContainerInheritMask &= ~LocalMask;
  6263. }
  6264. if ( AceFromAcl->Header.AceFlags & OBJECT_INHERIT_ACE ) {
  6265. NewAceObjectInheritMask &= ~LocalMask;
  6266. }
  6267. if ( (AceFromAcl->Header.AceFlags & INHERIT_ONLY_ACE) == 0 ) {
  6268. NewAceEffectiveMask &= ~LocalMask;
  6269. }
  6270. #if DBG
  6271. if ( RtlpVerboseConvert ) {
  6272. KdPrint(("Remaining MASKs: %8.8lX %8.8lX %8.8lX", NewAceEffectiveMask, NewAceContainerInheritMask, NewAceObjectInheritMask ));
  6273. }
  6274. #endif // DBG
  6275. //
  6276. // If all bits have been matched in the New Ace,
  6277. // then this is a duplicate ACE.
  6278. //
  6279. if ( (NewAceEffectiveMask | NewAceContainerInheritMask | NewAceObjectInheritMask) == 0 ) {
  6280. #if DBG
  6281. if ( RtlpVerboseConvert ) {
  6282. KdPrint(("\n"));
  6283. }
  6284. #endif // DBG
  6285. RetVal = TRUE;
  6286. goto Cleanup;
  6287. }
  6288. }
  6289. #if DBG
  6290. if ( RtlpVerboseConvert ) {
  6291. KdPrint(("\n"));
  6292. }
  6293. #endif // DBG
  6294. }
  6295. //
  6296. // All of the ACEs of the ACL have been processed.
  6297. //
  6298. // We haven't matched all of the bits in the New Ace so this is not a duplicate ACE.
  6299. //
  6300. RetVal = FALSE;
  6301. Cleanup:
  6302. return RetVal;
  6303. }
  6304. NTSTATUS
  6305. RtlpCreateServerAcl(
  6306. IN PACL Acl,
  6307. IN BOOLEAN AclUntrusted,
  6308. IN PSID ServerSid,
  6309. OUT PACL *ServerAcl,
  6310. OUT BOOLEAN *ServerAclAllocated
  6311. )
  6312. /*++
  6313. Routine Description:
  6314. This routine takes an ACL and converts it into a server ACL.
  6315. Currently, that means converting all of the GRANT ACEs into
  6316. Compount Grants, and if necessary sanitizing any Compound
  6317. Grants that are encountered.
  6318. Arguments:
  6319. Return Value:
  6320. --*/
  6321. {
  6322. USHORT RequiredSize = sizeof(ACL);
  6323. USHORT AceSizeAdjustment;
  6324. USHORT ServerSidSize;
  6325. PACE_HEADER Ace;
  6326. ULONG i;
  6327. PVOID Target;
  6328. PVOID AcePosition;
  6329. PSID UntrustedSid;
  6330. PSID ClientSid;
  6331. NTSTATUS Status;
  6332. RTL_PAGED_CODE();
  6333. if (Acl == NULL) {
  6334. *ServerAclAllocated = FALSE;
  6335. *ServerAcl = NULL;
  6336. return( STATUS_SUCCESS );
  6337. }
  6338. AceSizeAdjustment = sizeof( KNOWN_COMPOUND_ACE ) - sizeof( KNOWN_ACE );
  6339. ASSERT( sizeof( KNOWN_COMPOUND_ACE ) >= sizeof( KNOWN_ACE ) );
  6340. ServerSidSize = (USHORT)SeLengthSid( ServerSid );
  6341. //
  6342. // Do this in two passes. First, determine how big the final
  6343. // result is going to be, and then allocate the space and make
  6344. // the changes.
  6345. //
  6346. for (i = 0, Ace = FirstAce(Acl);
  6347. i < Acl->AceCount;
  6348. i += 1, Ace = NextAce(Ace)) {
  6349. //
  6350. // If it's an ACCESS_ALLOWED_ACE_TYPE, we'll need to add in the
  6351. // size of the Server SID.
  6352. //
  6353. if (Ace->AceType == ACCESS_ALLOWED_ACE_TYPE) {
  6354. //
  6355. // Simply add the size of the new Server SID plus whatever
  6356. // adjustment needs to be made to increase the size of the ACE.
  6357. //
  6358. RequiredSize += ( ServerSidSize + AceSizeAdjustment );
  6359. } else {
  6360. if (AclUntrusted && Ace->AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE ) {
  6361. //
  6362. // Since the Acl is untrusted, we don't care what is in the
  6363. // server SID, we're going to replace it.
  6364. //
  6365. UntrustedSid = RtlCompoundAceServerSid( Ace );
  6366. if ((USHORT)SeLengthSid(UntrustedSid) > ServerSidSize) {
  6367. RequiredSize += ((USHORT)SeLengthSid(UntrustedSid) - ServerSidSize);
  6368. } else {
  6369. RequiredSize += (ServerSidSize - (USHORT)SeLengthSid(UntrustedSid));
  6370. }
  6371. }
  6372. }
  6373. RequiredSize += Ace->AceSize;
  6374. }
  6375. #ifdef NTOS_KERNEL_RUNTIME
  6376. (*ServerAcl) = (PACL)ExAllocatePoolWithTag( PagedPool, RequiredSize, 'cAeS' );
  6377. #else // NTOS_KERNEL_RUNTIME
  6378. (*ServerAcl) = (PACL)RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( SE_TAG ), RequiredSize );
  6379. #endif // NTOS_KERNEL_RUNTIME
  6380. if ((*ServerAcl) == NULL) {
  6381. return STATUS_INSUFFICIENT_RESOURCES;
  6382. }
  6383. //
  6384. // Mark as allocated so caller knows to free it.
  6385. //
  6386. *ServerAclAllocated = TRUE;
  6387. Status = RtlCreateAcl( (*ServerAcl), RequiredSize, ACL_REVISION3 );
  6388. ASSERT( NT_SUCCESS( Status ));
  6389. for (i = 0, Ace = FirstAce(Acl), Target=FirstAce( *ServerAcl );
  6390. i < Acl->AceCount;
  6391. i += 1, Ace = NextAce(Ace)) {
  6392. //
  6393. // If it's an ACCESS_ALLOWED_ACE_TYPE, convert to a Server ACE.
  6394. //
  6395. if (Ace->AceType == ACCESS_ALLOWED_ACE_TYPE ||
  6396. (AclUntrusted && Ace->AceType == ACCESS_ALLOWED_COMPOUND_ACE_TYPE )) {
  6397. AcePosition = Target;
  6398. if (Ace->AceType == ACCESS_ALLOWED_ACE_TYPE) {
  6399. ClientSid = &((PKNOWN_ACE)Ace)->SidStart;
  6400. } else {
  6401. ClientSid = RtlCompoundAceClientSid( Ace );
  6402. }
  6403. //
  6404. // Copy up to the access mask.
  6405. //
  6406. RtlCopyMemory(
  6407. Target,
  6408. Ace,
  6409. FIELD_OFFSET(KNOWN_ACE, SidStart)
  6410. );
  6411. //
  6412. // Now copy the correct Server SID
  6413. //
  6414. Target = ((PCHAR)Target + (UCHAR)(FIELD_OFFSET(KNOWN_COMPOUND_ACE, SidStart)));
  6415. RtlCopyMemory(
  6416. Target,
  6417. ServerSid,
  6418. SeLengthSid(ServerSid)
  6419. );
  6420. Target = ((PCHAR)Target + (UCHAR)SeLengthSid(ServerSid));
  6421. //
  6422. // Now copy in the correct client SID. We can copy this right out of
  6423. // the original ACE.
  6424. //
  6425. RtlCopyMemory(
  6426. Target,
  6427. ClientSid,
  6428. SeLengthSid(ClientSid)
  6429. );
  6430. Target = ((PCHAR)Target + SeLengthSid(ClientSid));
  6431. //
  6432. // Set the size of the ACE accordingly
  6433. //
  6434. ((PKNOWN_COMPOUND_ACE)AcePosition)->Header.AceSize =
  6435. (USHORT)FIELD_OFFSET(KNOWN_COMPOUND_ACE, SidStart) +
  6436. (USHORT)SeLengthSid(ServerSid) +
  6437. (USHORT)SeLengthSid(ClientSid);
  6438. //
  6439. // Set the type
  6440. //
  6441. ((PKNOWN_COMPOUND_ACE)AcePosition)->Header.AceType = ACCESS_ALLOWED_COMPOUND_ACE_TYPE;
  6442. ((PKNOWN_COMPOUND_ACE)AcePosition)->CompoundAceType = COMPOUND_ACE_IMPERSONATION;
  6443. } else {
  6444. //
  6445. // Just copy the ACE as is.
  6446. //
  6447. RtlCopyMemory( Target, Ace, Ace->AceSize );
  6448. Target = ((PCHAR)Target + Ace->AceSize);
  6449. }
  6450. }
  6451. (*ServerAcl)->AceCount = Acl->AceCount;
  6452. return( STATUS_SUCCESS );
  6453. }
  6454. #ifndef NTOS_KERNEL_RUNTIME
  6455. NTSTATUS
  6456. RtlpGetDefaultsSubjectContext(
  6457. HANDLE ClientToken,
  6458. OUT PTOKEN_OWNER *OwnerInfo,
  6459. OUT PTOKEN_PRIMARY_GROUP *GroupInfo,
  6460. OUT PTOKEN_DEFAULT_DACL *DefaultDaclInfo,
  6461. OUT PTOKEN_OWNER *ServerOwner,
  6462. OUT PTOKEN_PRIMARY_GROUP *ServerGroup
  6463. )
  6464. {
  6465. HANDLE PrimaryToken;
  6466. PVOID HeapHandle;
  6467. NTSTATUS Status;
  6468. ULONG ServerGroupInfoSize;
  6469. ULONG ServerOwnerInfoSize;
  6470. ULONG TokenDaclInfoSize;
  6471. ULONG TokenGroupInfoSize;
  6472. ULONG TokenOwnerInfoSize;
  6473. BOOLEAN ClosePrimaryToken = FALSE;
  6474. *OwnerInfo = NULL;
  6475. *GroupInfo = NULL;
  6476. *DefaultDaclInfo = NULL;
  6477. *ServerOwner = NULL;
  6478. *ServerGroup = NULL;
  6479. HeapHandle = RtlProcessHeap();
  6480. //
  6481. // If the caller doesn't know the client token,
  6482. // simply don't return any information.
  6483. //
  6484. if ( ClientToken != NULL ) {
  6485. //
  6486. // Obtain the default owner from the client.
  6487. //
  6488. Status = NtQueryInformationToken(
  6489. ClientToken, // Handle
  6490. TokenOwner, // TokenInformationClass
  6491. NULL, // TokenInformation
  6492. 0, // TokenInformationLength
  6493. &TokenOwnerInfoSize // ReturnLength
  6494. );
  6495. if ( STATUS_BUFFER_TOO_SMALL != Status ) {
  6496. goto Cleanup;
  6497. }
  6498. *OwnerInfo = RtlAllocateHeap( HeapHandle, MAKE_TAG( SE_TAG ), TokenOwnerInfoSize );
  6499. if ( *OwnerInfo == NULL ) {
  6500. Status = STATUS_NO_MEMORY;
  6501. goto Cleanup;
  6502. }
  6503. Status = NtQueryInformationToken(
  6504. ClientToken, // Handle
  6505. TokenOwner, // TokenInformationClass
  6506. *OwnerInfo, // TokenInformation
  6507. TokenOwnerInfoSize, // TokenInformationLength
  6508. &TokenOwnerInfoSize // ReturnLength
  6509. );
  6510. if (!NT_SUCCESS( Status )) {
  6511. goto Cleanup;
  6512. }
  6513. //
  6514. // Obtain the default group from the client token.
  6515. //
  6516. Status = NtQueryInformationToken(
  6517. ClientToken, // Handle
  6518. TokenPrimaryGroup, // TokenInformationClass
  6519. *GroupInfo, // TokenInformation
  6520. 0, // TokenInformationLength
  6521. &TokenGroupInfoSize // ReturnLength
  6522. );
  6523. if ( STATUS_BUFFER_TOO_SMALL != Status ) {
  6524. goto Cleanup;
  6525. }
  6526. *GroupInfo = RtlAllocateHeap( HeapHandle, MAKE_TAG( SE_TAG ), TokenGroupInfoSize );
  6527. if ( *GroupInfo == NULL ) {
  6528. Status = STATUS_NO_MEMORY;
  6529. goto Cleanup;
  6530. }
  6531. Status = NtQueryInformationToken(
  6532. ClientToken, // Handle
  6533. TokenPrimaryGroup, // TokenInformationClass
  6534. *GroupInfo, // TokenInformation
  6535. TokenGroupInfoSize, // TokenInformationLength
  6536. &TokenGroupInfoSize // ReturnLength
  6537. );
  6538. if (!NT_SUCCESS( Status )) {
  6539. goto Cleanup;
  6540. }
  6541. Status = NtQueryInformationToken(
  6542. ClientToken, // Handle
  6543. TokenDefaultDacl, // TokenInformationClass
  6544. *DefaultDaclInfo, // TokenInformation
  6545. 0, // TokenInformationLength
  6546. &TokenDaclInfoSize // ReturnLength
  6547. );
  6548. if ( STATUS_BUFFER_TOO_SMALL != Status ) {
  6549. goto Cleanup;
  6550. }
  6551. *DefaultDaclInfo = RtlAllocateHeap( HeapHandle, MAKE_TAG( SE_TAG ), TokenDaclInfoSize );
  6552. if ( *DefaultDaclInfo == NULL ) {
  6553. Status = STATUS_NO_MEMORY;
  6554. goto Cleanup;
  6555. }
  6556. Status = NtQueryInformationToken(
  6557. ClientToken, // Handle
  6558. TokenDefaultDacl, // TokenInformationClass
  6559. *DefaultDaclInfo, // TokenInformation
  6560. TokenDaclInfoSize, // TokenInformationLength
  6561. &TokenDaclInfoSize // ReturnLength
  6562. );
  6563. if (!NT_SUCCESS( Status )) {
  6564. goto Cleanup;
  6565. }
  6566. }
  6567. //
  6568. // Now open the primary token to determine how to substitute for
  6569. // ServerOwner and ServerGroup.
  6570. //
  6571. Status = NtOpenProcessToken(
  6572. NtCurrentProcess(),
  6573. TOKEN_QUERY,
  6574. &PrimaryToken
  6575. );
  6576. if (!NT_SUCCESS( Status )) {
  6577. ClosePrimaryToken = FALSE;
  6578. goto Cleanup;
  6579. } else {
  6580. ClosePrimaryToken = TRUE;
  6581. }
  6582. Status = NtQueryInformationToken(
  6583. PrimaryToken, // Handle
  6584. TokenOwner, // TokenInformationClass
  6585. NULL, // TokenInformation
  6586. 0, // TokenInformationLength
  6587. &ServerOwnerInfoSize // ReturnLength
  6588. );
  6589. if ( STATUS_BUFFER_TOO_SMALL != Status ) {
  6590. goto Cleanup;
  6591. }
  6592. *ServerOwner = RtlAllocateHeap( HeapHandle, MAKE_TAG( SE_TAG ), ServerOwnerInfoSize );
  6593. if ( *ServerOwner == NULL ) {
  6594. Status = STATUS_NO_MEMORY;
  6595. goto Cleanup;
  6596. }
  6597. Status = NtQueryInformationToken(
  6598. PrimaryToken, // Handle
  6599. TokenOwner, // TokenInformationClass
  6600. *ServerOwner, // TokenInformation
  6601. ServerOwnerInfoSize, // TokenInformationLength
  6602. &ServerOwnerInfoSize // ReturnLength
  6603. );
  6604. if (!NT_SUCCESS( Status )) {
  6605. goto Cleanup;
  6606. }
  6607. //
  6608. // Find the server group.
  6609. //
  6610. Status = NtQueryInformationToken(
  6611. PrimaryToken, // Handle
  6612. TokenPrimaryGroup, // TokenInformationClass
  6613. *ServerGroup, // TokenInformation
  6614. 0, // TokenInformationLength
  6615. &ServerGroupInfoSize // ReturnLength
  6616. );
  6617. if ( STATUS_BUFFER_TOO_SMALL != Status ) {
  6618. goto Cleanup;
  6619. }
  6620. *ServerGroup = RtlAllocateHeap( HeapHandle, MAKE_TAG( SE_TAG ), ServerGroupInfoSize );
  6621. if ( *ServerGroup == NULL ) {
  6622. goto Cleanup;
  6623. }
  6624. Status = NtQueryInformationToken(
  6625. PrimaryToken, // Handle
  6626. TokenPrimaryGroup, // TokenInformationClass
  6627. *ServerGroup, // TokenInformation
  6628. ServerGroupInfoSize, // TokenInformationLength
  6629. &ServerGroupInfoSize // ReturnLength
  6630. );
  6631. if (!NT_SUCCESS( Status )) {
  6632. goto Cleanup;
  6633. }
  6634. NtClose( PrimaryToken );
  6635. return( STATUS_SUCCESS );
  6636. Cleanup:
  6637. if (*OwnerInfo != NULL) {
  6638. RtlFreeHeap( HeapHandle, 0, (PVOID)*OwnerInfo );
  6639. *OwnerInfo = NULL;
  6640. }
  6641. if (*GroupInfo != NULL) {
  6642. RtlFreeHeap( HeapHandle, 0, (PVOID)*GroupInfo );
  6643. *GroupInfo = NULL;
  6644. }
  6645. if (*DefaultDaclInfo != NULL) {
  6646. RtlFreeHeap( HeapHandle, 0, (PVOID)*DefaultDaclInfo );
  6647. *DefaultDaclInfo = NULL;
  6648. }
  6649. if (*ServerOwner != NULL) {
  6650. RtlFreeHeap( HeapHandle, 0, (PVOID)*ServerOwner );
  6651. *ServerOwner = NULL;
  6652. }
  6653. if (*ServerGroup != NULL) {
  6654. RtlFreeHeap( HeapHandle, 0, (PVOID)*ServerGroup );
  6655. *ServerGroup = NULL;
  6656. }
  6657. if (ClosePrimaryToken == TRUE) {
  6658. NtClose( PrimaryToken );
  6659. }
  6660. return( Status );
  6661. }
  6662. #endif // NTOS_KERNEL_RUNTIME
  6663. NTSTATUS
  6664. RtlpNewSecurityObject (
  6665. IN PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
  6666. IN PSECURITY_DESCRIPTOR CreatorDescriptor OPTIONAL,
  6667. OUT PSECURITY_DESCRIPTOR * NewDescriptor,
  6668. IN GUID **pObjectType OPTIONAL,
  6669. IN ULONG GuidCount,
  6670. IN BOOLEAN IsDirectoryObject,
  6671. IN ULONG AutoInheritFlags,
  6672. IN HANDLE Token OPTIONAL,
  6673. IN PGENERIC_MAPPING GenericMapping
  6674. )
  6675. /*++
  6676. Routine Description:
  6677. The procedure is used to allocate and initialize a self-relative
  6678. Security Descriptor for a new protected server's object. It is called
  6679. when a new protected server object is being created. The generated
  6680. security descriptor will be in self-relative form.
  6681. This procedure, called only from user mode, is used to establish a
  6682. security descriptor for a new protected server's object. Memory is
  6683. allocated to hold each of the security descriptor's components (using
  6684. NtAllocateVirtualMemory()). The final security descriptor generated by
  6685. this procedure is produced according to the rules stated in ???
  6686. System and Discretionary ACL Assignment
  6687. ---------------------------------------
  6688. The assignment of system and discretionary ACLs is governed by the
  6689. logic illustrated in the following table:
  6690. | Explicit | Explicit |
  6691. | (non-default) | Default | No
  6692. | Acl | Acl | Acl
  6693. | Specified | Specified | Specified
  6694. -------------+----------------+---------------+--------------
  6695. | | |
  6696. Inheritable | Assign | Assign | Assign
  6697. Acl From | Specified | Inherited | Inherited
  6698. Parent | Acl(1)(2) | Acl | Acl
  6699. | | |
  6700. -------------+----------------+---------------+--------------
  6701. No | | |
  6702. Inheritable | Assign | Assign | Assign
  6703. Acl From | Specified | Default | No Acl
  6704. Parent | Acl(1) | Acl |
  6705. | | |
  6706. -------------+----------------+---------------+--------------
  6707. (1) Any ACEs with the INHERITED_ACE bit set are NOT copied to the assigned
  6708. security descriptor.
  6709. (2) If the AutoInheritFlags is flagged to automatically inherit ACEs from
  6710. parent (SEF_DACL_AUTO_INHERIT or SEF_SACL_AUTO_INHERIT), inherited
  6711. ACEs from the parent will be appended after explicit ACEs from the
  6712. CreatorDescriptor.
  6713. Note that an explicitly specified ACL, whether a default ACL or
  6714. not, may be empty or null.
  6715. If the caller is explicitly assigning a system acl, default or
  6716. non-default, the caller must either be a kernel mode client or
  6717. must be appropriately privileged.
  6718. Owner and Group Assignment
  6719. --------------------------
  6720. The assignment of the new object's owner and group is governed
  6721. by the following logic:
  6722. 1) If the passed security descriptor includes an owner, it
  6723. is assigned as the new object's owner. Otherwise, the
  6724. caller's token is looked in for the owner. Within the
  6725. token, if there is a default owner, it is assigned.
  6726. Otherwise, the caller's user ID is assigned.
  6727. 2) If the passed security descriptor includes a group, it
  6728. is assigned as the new object's group. Otherwise, the
  6729. caller's token is looked in for the group. Within the
  6730. token, if there is a default group, it is assigned.
  6731. Otherwise, the caller's primary group ID is assigned.
  6732. Arguments:
  6733. ParentDescriptor - Supplies the Security Descriptor for the parent
  6734. directory under which a new object is being created. If there is
  6735. no parent directory, then this argument is specified as NULL.
  6736. CreatorDescriptor - (Optionally) Points to a security descriptor
  6737. presented by the creator of the object. If the creator of the
  6738. object did not explicitly pass security information for the new
  6739. object, then a null pointer should be passed.
  6740. NewDescriptor - Points to a pointer that is to be made to point to the
  6741. newly allocated self-relative security descriptor.
  6742. ObjectType - GUID of the object type being created. If the object being
  6743. created has no GUID associated with it, then this argument is
  6744. specified as NULL.
  6745. IsDirectoryObject - Specifies if the new object is going to be a
  6746. directory object. A value of TRUE indicates the object is a
  6747. container of other objects.
  6748. AutoInheritFlags - Controls automatic inheritance of ACES from the Parent
  6749. Descriptor. Valid values are a bits mask of the logical OR of
  6750. one or more of the following bits:
  6751. SEF_DACL_AUTO_INHERIT - If set, inherit ACEs from the
  6752. DACL ParentDescriptor are inherited to NewDescriptor in addition
  6753. to any explicit ACEs specified by the CreatorDescriptor.
  6754. SEF_SACL_AUTO_INHERIT - If set, inherit ACEs from the
  6755. SACL ParentDescriptor are inherited to NewDescriptor in addition
  6756. to any explicit ACEs specified by the CreatorDescriptor.
  6757. SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT - If set, the CreatorDescriptor
  6758. is the default descriptor for ObjectType. As such, the
  6759. CreatorDescriptor will be ignored if any ObjectType specific
  6760. ACEs are inherited from the parent. If no such ACEs are inherited,
  6761. the CreatorDescriptor is handled as though this flag were not
  6762. specified.
  6763. SEF_AVOID_PRIVILEGE_CHECK - If set, no privilege checking is done by this
  6764. routine. This flag is useful while implementing automatic inheritance
  6765. to avoid checking privileges on each child updated.
  6766. SEF_AVOID_OWNER_CHECK - If set, no owner checking is done by this routine.
  6767. SEF_DEFAULT_OWNER_FROM_PARENT - If set, the owner of NewDescriptor will
  6768. default to the owner from ParentDescriptor. If not set, the owner
  6769. of NewDescriptor will default to the user specified in Token.
  6770. In either case, the owner of NewDescriptor is set to the owner from
  6771. the CreatorDescriptor if that field is specified.
  6772. SEF_DEFAULT_GROUP_FROM_PARENT - If set, the group of NewDescriptor will
  6773. default to the group from ParentDescriptor. If not set, the group
  6774. of NewDescriptor will default to the group specified in Token.
  6775. In either case, the group of NewDescriptor is set to the group from
  6776. the CreatorDescriptor if that field is specified.
  6777. Token - Supplies the token for the client on whose behalf the
  6778. object is being created. If it is an impersonation token,
  6779. then it must be at SecurityIdentification level or higher. If
  6780. it is not an impersonation token, the operation proceeds
  6781. normally.
  6782. A client token is used to retrieve default security
  6783. information for the new object, such as default owner, primary
  6784. group, and discretionary access control. The token must be
  6785. open for TOKEN_QUERY access.
  6786. For calls from the kernel, Supplies the security context of the subject creating the
  6787. object. This is used to retrieve default security information for the
  6788. new object, such as default owner, primary group, and discretionary
  6789. access control.
  6790. If not specified, the Owner and Primary group must be specified in the
  6791. CreatorDescriptor.
  6792. GenericMapping - Supplies a pointer to a generic mapping array denoting
  6793. the mapping between each generic right to specific rights.
  6794. Return Value:
  6795. STATUS_SUCCESS - The operation was successful.
  6796. STATUS_INVALID_OWNER - The owner SID provided as the owner of the
  6797. target security descriptor is not one the subject is authorized to
  6798. assign as the owner of an object.
  6799. STATUS_NO_CLIENT_TOKEN - Indicates a client token was not explicitly
  6800. provided and the caller is not currently impersonating a client.
  6801. STATUS_PRIVILEGE_NOT_HELD - The caller does not have the privilege
  6802. necessary to explicitly assign the specified system ACL.
  6803. SeSecurityPrivilege privilege is needed to explicitly assign
  6804. system ACLs to objects.
  6805. --*/
  6806. {
  6807. SECURITY_DESCRIPTOR *CapturedDescriptor;
  6808. SECURITY_DESCRIPTOR InCaseOneNotPassed;
  6809. BOOLEAN SecurityDescriptorPassed;
  6810. NTSTATUS Status;
  6811. PACL NewSacl = NULL;
  6812. BOOLEAN NewSaclInherited = FALSE;
  6813. PACL NewDacl = NULL;
  6814. PACL ServerDacl = NULL;
  6815. BOOLEAN NewDaclInherited = FALSE;
  6816. PSID NewOwner = NULL;
  6817. PSID NewGroup = NULL;
  6818. BOOLEAN SaclExplicitlyAssigned = FALSE;
  6819. BOOLEAN OwnerExplicitlyAssigned = FALSE;
  6820. BOOLEAN DaclExplicitlyAssigned = FALSE;
  6821. BOOLEAN ServerDaclAllocated = FALSE;
  6822. BOOLEAN ServerObject;
  6823. BOOLEAN DaclUntrusted;
  6824. BOOLEAN HasPrivilege;
  6825. PRIVILEGE_SET PrivilegeSet;
  6826. PSID SubjectContextOwner = NULL;
  6827. PSID SubjectContextGroup = NULL;
  6828. PSID ServerOwner = NULL;
  6829. PSID ServerGroup = NULL;
  6830. PACL SubjectContextDacl = NULL;
  6831. ULONG AllocationSize;
  6832. ULONG NewOwnerSize, OwnerSize;
  6833. ULONG NewGroupSize, GroupSize;
  6834. ULONG NewSaclSize;
  6835. ULONG NewDaclSize;
  6836. PCHAR Field;
  6837. PCHAR Base;
  6838. PISECURITY_DESCRIPTOR_RELATIVE INewDescriptor = NULL;
  6839. NTSTATUS PassedStatus;
  6840. KPROCESSOR_MODE RequestorMode;
  6841. ULONG GenericControl;
  6842. ULONG NewControlBits = SE_SELF_RELATIVE;
  6843. #ifndef NTOS_KERNEL_RUNTIME
  6844. PTOKEN_OWNER TokenOwnerInfo = NULL;
  6845. PTOKEN_PRIMARY_GROUP TokenPrimaryGroupInfo = NULL;
  6846. PTOKEN_DEFAULT_DACL TokenDefaultDaclInfo = NULL;
  6847. PTOKEN_OWNER ServerOwnerInfo = NULL;
  6848. PTOKEN_PRIMARY_GROUP ServerGroupInfo = NULL;
  6849. PVOID HeapHandle;
  6850. #else
  6851. //
  6852. // For kernel mode callers, the Token parameter is really
  6853. // a pointer to a subject context structure.
  6854. //
  6855. PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  6856. PVOID SubjectContextInfo = NULL;
  6857. SubjectSecurityContext = (PSECURITY_SUBJECT_CONTEXT)Token;
  6858. #endif // NTOS_KERNEL_RUNTIME
  6859. RTL_PAGED_CODE();
  6860. #ifdef NTOS_KERNEL_RUNTIME
  6861. //
  6862. // Get the previous mode of the caller
  6863. //
  6864. RequestorMode = KeGetPreviousMode();
  6865. #else // NTOS_KERNEL_RUNTIME
  6866. RequestorMode = UserMode;
  6867. //
  6868. // Get the handle to the current process heap
  6869. //
  6870. HeapHandle = RtlProcessHeap();
  6871. //
  6872. // Ensure the token is an impersonation token.
  6873. //
  6874. if ( Token != NULL ) {
  6875. TOKEN_STATISTICS ThreadTokenStatistics;
  6876. ULONG ReturnLength;
  6877. Status = NtQueryInformationToken(
  6878. Token, // Handle
  6879. TokenStatistics, // TokenInformationClass
  6880. &ThreadTokenStatistics, // TokenInformation
  6881. sizeof(TOKEN_STATISTICS), // TokenInformationLength
  6882. &ReturnLength // ReturnLength
  6883. );
  6884. if (!NT_SUCCESS( Status )) {
  6885. return( Status );
  6886. }
  6887. //
  6888. // If it is an impersonation token, then make sure it is at a
  6889. // high enough level.
  6890. //
  6891. if (ThreadTokenStatistics.TokenType == TokenImpersonation) {
  6892. if (ThreadTokenStatistics.ImpersonationLevel < SecurityIdentification ) {
  6893. return( STATUS_BAD_IMPERSONATION_LEVEL );
  6894. }
  6895. }
  6896. }
  6897. #endif // NTOS_KERNEL_RUNTIME
  6898. //
  6899. // The desired end result is to build a self-relative security descriptor.
  6900. // This means that a single block of memory will be allocated and all
  6901. // security information copied into it. To minimize work along the way,
  6902. // it is desirable to reference (rather than copy) each field as we
  6903. // determine its source. This can not be done with inherited ACLs, however,
  6904. // since they must be built from another ACL. So, explicitly assigned
  6905. // and defaulted SIDs and ACLs are just referenced until they are copied
  6906. // into the self-relative descriptor. Inherited ACLs are built in a
  6907. // temporary buffer which must be deallocated after being copied to the
  6908. // self-relative descriptor.
  6909. //
  6910. //
  6911. // If a security descriptor has been passed, capture it, otherwise
  6912. // cobble up a fake one to simplify the code that follows.
  6913. //
  6914. if (ARGUMENT_PRESENT(CreatorDescriptor)) {
  6915. CapturedDescriptor = CreatorDescriptor;
  6916. SecurityDescriptorPassed = TRUE;
  6917. } else {
  6918. //
  6919. // No descriptor passed, make a fake one
  6920. //
  6921. SecurityDescriptorPassed = FALSE;
  6922. RtlCreateSecurityDescriptor(&InCaseOneNotPassed,
  6923. SECURITY_DESCRIPTOR_REVISION);
  6924. CapturedDescriptor = &InCaseOneNotPassed;
  6925. }
  6926. if ( CapturedDescriptor->Control & SE_SERVER_SECURITY ) {
  6927. ServerObject = TRUE;
  6928. } else {
  6929. ServerObject = FALSE;
  6930. }
  6931. if ( CapturedDescriptor->Control & SE_DACL_UNTRUSTED ) {
  6932. DaclUntrusted = TRUE;
  6933. } else {
  6934. DaclUntrusted = FALSE;
  6935. }
  6936. //
  6937. // Get the required information from the token.
  6938. //
  6939. //
  6940. // Grab pointers to the default owner, primary group, and
  6941. // discretionary ACL.
  6942. //
  6943. if ( Token != NULL || ServerObject ) {
  6944. #ifdef NTOS_KERNEL_RUNTIME
  6945. PSID TmpSubjectContextOwner = NULL;
  6946. PSID TmpSubjectContextGroup = NULL;
  6947. PSID TmpServerOwner = NULL;
  6948. PSID TmpServerGroup = NULL;
  6949. PACL TmpSubjectContextDacl = NULL;
  6950. SIZE_T SubjectContextInfoSize = 0;
  6951. //
  6952. // Lock the subject context for read access so that the pointers
  6953. // we copy out of it don't disappear on us at random
  6954. //
  6955. SeLockSubjectContext( SubjectSecurityContext );
  6956. SepGetDefaultsSubjectContext(
  6957. SubjectSecurityContext,
  6958. &TmpSubjectContextOwner,
  6959. &TmpSubjectContextGroup,
  6960. &TmpServerOwner,
  6961. &TmpServerGroup,
  6962. &TmpSubjectContextDacl
  6963. );
  6964. //
  6965. // We can't keep the subject context locked, because
  6966. // we may have to do a privilege check later, which calls
  6967. // PsLockProcessSecurityFields, which can cause a deadlock
  6968. // with PsImpersonateClient, which takes them in the reverse
  6969. // order.
  6970. //
  6971. // Since we're giving up our read lock on the token, we
  6972. // need to copy all the stuff that we just got back. Since
  6973. // it's not going to change, we can save some cycles and copy
  6974. // it all into a single chunck of memory.
  6975. //
  6976. SubjectContextInfoSize = SeLengthSid( TmpSubjectContextOwner ) +
  6977. SeLengthSid( TmpServerOwner ) +
  6978. (TmpSubjectContextGroup != NULL ? SeLengthSid( TmpSubjectContextGroup ) : 0) +
  6979. (TmpServerGroup != NULL ? SeLengthSid( TmpServerGroup ) : 0) +
  6980. (TmpSubjectContextDacl != NULL ? TmpSubjectContextDacl->AclSize : 0);
  6981. SubjectContextInfo = ExAllocatePoolWithTag( PagedPool, SubjectContextInfoSize, 'dSeS');
  6982. if (SubjectContextInfo) {
  6983. //
  6984. // Copy in the data
  6985. //
  6986. Base = SubjectContextInfo;
  6987. //
  6988. // There will always be an owner.
  6989. //
  6990. SubjectContextOwner = (PSID)Base;
  6991. RtlCopySid( SeLengthSid( TmpSubjectContextOwner), Base, TmpSubjectContextOwner );
  6992. Base += SeLengthSid( TmpSubjectContextOwner);
  6993. //
  6994. // Groups may be NULL
  6995. //
  6996. if (TmpSubjectContextGroup != NULL) {
  6997. SubjectContextGroup = (PSID)Base;
  6998. RtlCopySid( SeLengthSid( TmpSubjectContextGroup), Base, TmpSubjectContextGroup );
  6999. Base += SeLengthSid( TmpSubjectContextGroup );
  7000. } else {
  7001. SubjectContextGroup = NULL;
  7002. }
  7003. ServerOwner = (PSID)Base;
  7004. RtlCopySid( SeLengthSid( TmpServerOwner ), Base, TmpServerOwner );
  7005. Base += SeLengthSid( TmpServerOwner );
  7006. //
  7007. // Groups may be NULL
  7008. //
  7009. if (TmpServerGroup != NULL) {
  7010. ServerGroup = (PSID)Base;
  7011. RtlCopySid( SeLengthSid( TmpServerGroup ), Base, TmpServerGroup );
  7012. Base += SeLengthSid( TmpServerGroup );
  7013. } else {
  7014. ServerGroup = NULL;
  7015. }
  7016. if (TmpSubjectContextDacl != NULL) {
  7017. SubjectContextDacl = (PACL)Base;
  7018. RtlCopyMemory( Base, TmpSubjectContextDacl, TmpSubjectContextDacl->AclSize );
  7019. // Base += TmpSubjectContextDacl->AclSize;
  7020. } else {
  7021. SubjectContextDacl = NULL;
  7022. }
  7023. } else {
  7024. SeUnlockSubjectContext( SubjectSecurityContext );
  7025. return( STATUS_INSUFFICIENT_RESOURCES );
  7026. }
  7027. SeUnlockSubjectContext( SubjectSecurityContext );
  7028. #else // NTOS_KERNEL_RUNTIME
  7029. Status = RtlpGetDefaultsSubjectContext(
  7030. Token,
  7031. &TokenOwnerInfo,
  7032. &TokenPrimaryGroupInfo,
  7033. &TokenDefaultDaclInfo,
  7034. &ServerOwnerInfo,
  7035. &ServerGroupInfo
  7036. );
  7037. if (!NT_SUCCESS( Status )) {
  7038. return( Status );
  7039. }
  7040. SubjectContextOwner = TokenOwnerInfo->Owner;
  7041. SubjectContextGroup = TokenPrimaryGroupInfo->PrimaryGroup;
  7042. SubjectContextDacl = TokenDefaultDaclInfo->DefaultDacl;
  7043. ServerOwner = ServerOwnerInfo->Owner;
  7044. ServerGroup = ServerGroupInfo->PrimaryGroup;
  7045. #endif // NTOS_KERNEL_RUNTIME
  7046. }
  7047. //
  7048. // Establish an owner SID
  7049. //
  7050. NewOwner = RtlpOwnerAddrSecurityDescriptor(CapturedDescriptor);
  7051. if ((NewOwner) != NULL) {
  7052. //
  7053. // Use the specified owner
  7054. //
  7055. OwnerExplicitlyAssigned = TRUE;
  7056. } else {
  7057. //
  7058. // If the caller said to default the owner from the parent descriptor,
  7059. // grab it now.
  7060. //
  7061. if ( AutoInheritFlags & SEF_DEFAULT_OWNER_FROM_PARENT) {
  7062. if ( !ARGUMENT_PRESENT(ParentDescriptor) ) {
  7063. Status = STATUS_INVALID_OWNER;
  7064. goto Cleanup;
  7065. }
  7066. NewOwner = RtlpOwnerAddrSecurityDescriptor((SECURITY_DESCRIPTOR *)ParentDescriptor);
  7067. OwnerExplicitlyAssigned = TRUE;
  7068. if ( NewOwner == NULL ) {
  7069. Status = STATUS_INVALID_OWNER;
  7070. goto Cleanup;
  7071. }
  7072. } else {
  7073. //
  7074. // Pick up the default from the subject's security context.
  7075. //
  7076. // This does NOT constitute explicit assignment of owner
  7077. // and does not have to be checked as an ID that can be
  7078. // assigned as owner. This is because a default can not
  7079. // be established in a token unless the user of the token
  7080. // can assign it as an owner.
  7081. //
  7082. //
  7083. // If we've been asked to create a ServerObject, we need to
  7084. // make sure to pick up the new owner from the Primary token,
  7085. // not the client token. If we're not impersonating, they will
  7086. // end up being the same.
  7087. //
  7088. NewOwner = ServerObject ? ServerOwner : SubjectContextOwner;
  7089. //
  7090. // Ensure an owner is now defined.
  7091. //
  7092. if ( NewOwner == NULL ) {
  7093. Status = STATUS_NO_TOKEN;
  7094. goto Cleanup;
  7095. }
  7096. }
  7097. }
  7098. //
  7099. // Establish a Group SID
  7100. //
  7101. NewGroup = RtlpGroupAddrSecurityDescriptor(CapturedDescriptor);
  7102. if (NewGroup == NULL) {
  7103. //
  7104. // If the caller said to default the group from the parent descriptor,
  7105. // grab it now.
  7106. //
  7107. if ( AutoInheritFlags & SEF_DEFAULT_GROUP_FROM_PARENT) {
  7108. if ( !ARGUMENT_PRESENT(ParentDescriptor) ) {
  7109. Status = STATUS_INVALID_PRIMARY_GROUP;
  7110. goto Cleanup;
  7111. }
  7112. NewGroup = RtlpGroupAddrSecurityDescriptor((SECURITY_DESCRIPTOR *)ParentDescriptor);
  7113. } else {
  7114. //
  7115. // Pick up the primary group from the subject's security context
  7116. //
  7117. // If we're creating a Server object, use the group from the server
  7118. // context.
  7119. //
  7120. NewGroup = ServerObject ? ServerGroup : SubjectContextGroup;
  7121. }
  7122. }
  7123. if (NewGroup != NULL) {
  7124. if (!RtlValidSid( NewGroup )) {
  7125. Status = STATUS_INVALID_PRIMARY_GROUP;
  7126. goto Cleanup;
  7127. }
  7128. } else {
  7129. Status = STATUS_INVALID_PRIMARY_GROUP;
  7130. goto Cleanup;
  7131. }
  7132. //
  7133. // Establish System Acl
  7134. //
  7135. Status = RtlpInheritAcl (
  7136. ARGUMENT_PRESENT(ParentDescriptor) ?
  7137. RtlpSaclAddrSecurityDescriptor(
  7138. ((SECURITY_DESCRIPTOR *)ParentDescriptor)) :
  7139. NULL,
  7140. RtlpSaclAddrSecurityDescriptor(CapturedDescriptor),
  7141. SeControlSaclToGeneric( CapturedDescriptor->Control ),
  7142. IsDirectoryObject,
  7143. (BOOLEAN)((AutoInheritFlags & SEF_SACL_AUTO_INHERIT) != 0),
  7144. (BOOLEAN)((AutoInheritFlags & SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT) != 0),
  7145. NewOwner,
  7146. NewGroup,
  7147. ServerOwner,
  7148. ServerGroup,
  7149. GenericMapping,
  7150. TRUE, // Is a SACL
  7151. pObjectType,
  7152. GuidCount,
  7153. &NewSacl,
  7154. &SaclExplicitlyAssigned,
  7155. &GenericControl );
  7156. if ( NT_SUCCESS(Status) ) {
  7157. NewSaclInherited = TRUE;
  7158. NewControlBits |= SE_SACL_PRESENT | SeControlGenericToSacl( GenericControl );
  7159. } else if ( Status == STATUS_NO_INHERITANCE ) {
  7160. //
  7161. // Always set the auto inherit bit if the caller requested it.
  7162. //
  7163. if ( AutoInheritFlags & SEF_SACL_AUTO_INHERIT) {
  7164. NewControlBits |= SE_SACL_AUTO_INHERITED;
  7165. }
  7166. //
  7167. // No inheritable ACL - check for a defaulted one.
  7168. //
  7169. if ( RtlpAreControlBitsSet( CapturedDescriptor,
  7170. SE_SACL_PRESENT | SE_SACL_DEFAULTED ) ) {
  7171. //
  7172. // Reference the default ACL
  7173. //
  7174. NewSacl = RtlpSaclAddrSecurityDescriptor(CapturedDescriptor);
  7175. NewControlBits |= SE_SACL_PRESENT;
  7176. NewControlBits |= (CapturedDescriptor->Control & SE_SACL_PROTECTED);
  7177. //
  7178. // This counts as an explicit assignment.
  7179. //
  7180. SaclExplicitlyAssigned = TRUE;
  7181. }
  7182. } else {
  7183. //
  7184. // Some unusual error occured
  7185. //
  7186. goto Cleanup;
  7187. }
  7188. //
  7189. // Establish Discretionary Acl
  7190. //
  7191. Status = RtlpInheritAcl (
  7192. ARGUMENT_PRESENT(ParentDescriptor) ?
  7193. RtlpDaclAddrSecurityDescriptor(
  7194. ((SECURITY_DESCRIPTOR *)ParentDescriptor)) :
  7195. NULL,
  7196. RtlpDaclAddrSecurityDescriptor(CapturedDescriptor),
  7197. SeControlDaclToGeneric( CapturedDescriptor->Control ),
  7198. IsDirectoryObject,
  7199. (BOOLEAN)((AutoInheritFlags & SEF_DACL_AUTO_INHERIT) != 0),
  7200. (BOOLEAN)((AutoInheritFlags & SEF_DEFAULT_DESCRIPTOR_FOR_OBJECT) != 0),
  7201. NewOwner,
  7202. NewGroup,
  7203. ServerOwner,
  7204. ServerGroup,
  7205. GenericMapping,
  7206. FALSE, // Is a DACL
  7207. pObjectType,
  7208. GuidCount,
  7209. &NewDacl,
  7210. &DaclExplicitlyAssigned,
  7211. &GenericControl );
  7212. if ( NT_SUCCESS(Status) ) {
  7213. NewDaclInherited = TRUE;
  7214. NewControlBits |= SE_DACL_PRESENT | SeControlGenericToDacl( GenericControl );
  7215. } else if ( Status == STATUS_NO_INHERITANCE ) {
  7216. //
  7217. // Always set the auto inherit bit if the caller requested it.
  7218. //
  7219. if ( AutoInheritFlags & SEF_DACL_AUTO_INHERIT) {
  7220. NewControlBits |= SE_DACL_AUTO_INHERITED;
  7221. }
  7222. //
  7223. // No inheritable ACL - check for a defaulted one.
  7224. //
  7225. if ( RtlpAreControlBitsSet( CapturedDescriptor,
  7226. SE_DACL_PRESENT | SE_DACL_DEFAULTED ) ) {
  7227. //
  7228. // Reference the default ACL
  7229. //
  7230. NewDacl = RtlpDaclAddrSecurityDescriptor(CapturedDescriptor);
  7231. NewControlBits |= SE_DACL_PRESENT;
  7232. NewControlBits |= (CapturedDescriptor->Control & SE_DACL_PROTECTED);
  7233. //
  7234. // This counts as an explicit assignment.
  7235. //
  7236. DaclExplicitlyAssigned = TRUE;
  7237. //
  7238. // Default to the DACL on the token.
  7239. //
  7240. } else if (ARGUMENT_PRESENT(SubjectContextDacl)) {
  7241. NewDacl = SubjectContextDacl;
  7242. NewControlBits |= SE_DACL_PRESENT;
  7243. }
  7244. } else {
  7245. //
  7246. // Some unusual error occured
  7247. //
  7248. goto Cleanup;
  7249. }
  7250. #ifdef ASSERT_ON_NULL_DACL
  7251. //
  7252. // Culprit will probably be the caller NtCreate*, or
  7253. // RtlNewSecurityObject. Note that although this will not always occur
  7254. // because of explicit user action it still must be corrected.
  7255. //
  7256. if (RtlpAssertOnNullDacls) {
  7257. ASSERT(("NULL DACLs are NOT allowed!", NewDacl != NULL));
  7258. }
  7259. #endif // ASSERT_ON_NULL_DACL
  7260. //
  7261. // If auto inheriting and the computed child DACL is NULL,
  7262. // mark it as protected.
  7263. //
  7264. // NULL DACLs are problematic when ACEs are actually inherited from the
  7265. // parent DACL. It is better to mark them as protected NOW (even if we don't
  7266. // end up inheriting any ACEs) to avoid confusion later.
  7267. //
  7268. if ( (AutoInheritFlags & SEF_DACL_AUTO_INHERIT) != 0 &&
  7269. NewDacl == NULL ) {
  7270. NewControlBits |= SE_DACL_PROTECTED;
  7271. }
  7272. //
  7273. // Now make sure that the caller has the right to assign
  7274. // everything in the descriptor. The requestor is subjected
  7275. // to privilege and restriction tests for some assignments.
  7276. //
  7277. if (RequestorMode == UserMode) {
  7278. //
  7279. // Anybody can assign any Discretionary ACL or group that they want to.
  7280. //
  7281. //
  7282. // See if the system ACL was explicitly specified
  7283. //
  7284. if ( SaclExplicitlyAssigned &&
  7285. (AutoInheritFlags & SEF_AVOID_PRIVILEGE_CHECK) == 0 ) {
  7286. //
  7287. // Require a Token if we're to do the privilege check.
  7288. //
  7289. if ( Token == NULL ) {
  7290. Status = STATUS_NO_TOKEN;
  7291. goto Cleanup;
  7292. }
  7293. #ifdef NTOS_KERNEL_RUNTIME
  7294. //
  7295. // Check for appropriate Privileges
  7296. // Audit/Alarm messages need to be generated due to the attempt
  7297. // to perform a privileged operation.
  7298. //
  7299. //
  7300. // Note: be sure to do the privilege check against
  7301. // the passed subject context!
  7302. //
  7303. PrivilegeSet.PrivilegeCount = 1;
  7304. PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
  7305. PrivilegeSet.Privilege[0].Luid = SeSecurityPrivilege;
  7306. PrivilegeSet.Privilege[0].Attributes = 0;
  7307. HasPrivilege = SePrivilegeCheck(
  7308. &PrivilegeSet,
  7309. SubjectSecurityContext,
  7310. RequestorMode
  7311. );
  7312. if ( RequestorMode != KernelMode ) {
  7313. SePrivilegedServiceAuditAlarm (
  7314. NULL,
  7315. SubjectSecurityContext,
  7316. &PrivilegeSet,
  7317. HasPrivilege
  7318. );
  7319. }
  7320. #else // NTOS_KERNEL_RUNTIME
  7321. //
  7322. // Check for appropriate Privileges
  7323. //
  7324. // Audit/Alarm messages need to be generated due to the attempt
  7325. // to perform a privileged operation.
  7326. //
  7327. PrivilegeSet.PrivilegeCount = 1;
  7328. PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
  7329. PrivilegeSet.Privilege[0].Luid = RtlConvertLongToLuid(SE_SECURITY_PRIVILEGE);
  7330. PrivilegeSet.Privilege[0].Attributes = 0;
  7331. Status = NtPrivilegeCheck(
  7332. Token,
  7333. &PrivilegeSet,
  7334. &HasPrivilege
  7335. );
  7336. if (!NT_SUCCESS( Status )) {
  7337. goto Cleanup;
  7338. }
  7339. #endif // NTOS_KERNEL_RUNTIME
  7340. if ( !HasPrivilege ) {
  7341. Status = STATUS_PRIVILEGE_NOT_HELD;
  7342. goto Cleanup;
  7343. }
  7344. }
  7345. //
  7346. // See if the owner field is one the requestor can assign
  7347. //
  7348. if (OwnerExplicitlyAssigned &&
  7349. (AutoInheritFlags & SEF_AVOID_OWNER_CHECK) == 0 ) {
  7350. #ifdef NTOS_KERNEL_RUNTIME
  7351. if (!SepValidOwnerSubjectContext(
  7352. SubjectSecurityContext,
  7353. NewOwner,
  7354. ServerObject)
  7355. ) {
  7356. Status = STATUS_INVALID_OWNER;
  7357. goto Cleanup;
  7358. }
  7359. #else // NTOS_KERNEL_RUNTIME
  7360. //
  7361. // Require a Token if we're to do the privilege check.
  7362. //
  7363. if ( Token == NULL ) {
  7364. Status = STATUS_NO_TOKEN;
  7365. goto Cleanup;
  7366. }
  7367. if (!RtlpValidOwnerSubjectContext(
  7368. Token,
  7369. NewOwner,
  7370. ServerObject,
  7371. &PassedStatus) ) {
  7372. Status = PassedStatus;
  7373. goto Cleanup;
  7374. }
  7375. #endif // NTOS_KERNEL_RUNTIME
  7376. }
  7377. //
  7378. // If the DACL was explictly assigned and this is a server object,
  7379. // convert the DACL to be a server DACL
  7380. //
  7381. if (DaclExplicitlyAssigned && ServerObject) {
  7382. Status = RtlpCreateServerAcl(
  7383. NewDacl,
  7384. DaclUntrusted,
  7385. ServerOwner,
  7386. &ServerDacl,
  7387. &ServerDaclAllocated
  7388. );
  7389. if (!NT_SUCCESS( Status )) {
  7390. goto Cleanup;
  7391. }
  7392. NewDacl = ServerDacl;
  7393. }
  7394. }
  7395. //
  7396. // Everything is assignable by the requestor.
  7397. // Calculate the memory needed to house all the information in
  7398. // a self-relative security descriptor.
  7399. //
  7400. // Also map the ACEs for application to the target object
  7401. // type, if they haven't already been mapped.
  7402. //
  7403. OwnerSize = SeLengthSid(NewOwner);
  7404. NewOwnerSize = LongAlignSize(OwnerSize);
  7405. if (NewGroup != NULL) {
  7406. GroupSize = SeLengthSid(NewGroup);
  7407. NewGroupSize = LongAlignSize(GroupSize);
  7408. }
  7409. if ((NewControlBits & SE_SACL_PRESENT) && (NewSacl != NULL)) {
  7410. NewSaclSize = LongAlignSize(NewSacl->AclSize);
  7411. } else {
  7412. NewSaclSize = 0;
  7413. }
  7414. if ( (NewControlBits & SE_DACL_PRESENT) && (NewDacl != NULL)) {
  7415. NewDaclSize = LongAlignSize(NewDacl->AclSize);
  7416. } else {
  7417. NewDaclSize = 0;
  7418. }
  7419. AllocationSize = LongAlignSize(sizeof(SECURITY_DESCRIPTOR_RELATIVE)) +
  7420. NewOwnerSize +
  7421. NewGroupSize +
  7422. NewSaclSize +
  7423. NewDaclSize;
  7424. //
  7425. // Allocate and initialize the security descriptor as
  7426. // self-relative form.
  7427. //
  7428. #ifdef NTOS_KERNEL_RUNTIME
  7429. INewDescriptor = (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag( PagedPool, AllocationSize, 'dSeS');
  7430. #else // NTOS_KERNEL_RUNTIME
  7431. INewDescriptor = RtlAllocateHeap( HeapHandle, MAKE_TAG( SE_TAG ), AllocationSize );
  7432. #endif // NTOS_KERNEL_RUNTIME
  7433. if ( INewDescriptor == NULL ) {
  7434. #ifdef NTOS_KERNEL_RUNTIME
  7435. Status = STATUS_INSUFFICIENT_RESOURCES;
  7436. #else // NTOS_KERNEL_RUNTIME
  7437. Status = STATUS_NO_MEMORY;
  7438. #endif // NTOS_KERNEL_RUNTIME
  7439. goto Cleanup;
  7440. }
  7441. RtlCreateSecurityDescriptorRelative(
  7442. INewDescriptor,
  7443. SECURITY_DESCRIPTOR_REVISION
  7444. );
  7445. RtlpSetControlBits( INewDescriptor, NewControlBits );
  7446. Base = (PCHAR)(INewDescriptor);
  7447. Field = Base + sizeof(SECURITY_DESCRIPTOR_RELATIVE);
  7448. //
  7449. // Map and Copy in the Sacl
  7450. //
  7451. if (NewControlBits & SE_SACL_PRESENT) {
  7452. if (NewSacl != NULL) {
  7453. RtlCopyMemory( Field, NewSacl, NewSacl->AclSize );
  7454. if (!NewSaclInherited) {
  7455. RtlpApplyAclToObject( (PACL)Field, GenericMapping );
  7456. }
  7457. INewDescriptor->Sacl = RtlPointerToOffset(Base,Field);
  7458. if (NewSaclSize > NewSacl->AclSize) {
  7459. RtlZeroMemory (Field + NewSacl->AclSize, NewSaclSize - NewSacl->AclSize);
  7460. }
  7461. Field += NewSaclSize;
  7462. } else {
  7463. INewDescriptor->Sacl = 0;
  7464. }
  7465. }
  7466. //
  7467. // Map and Copy in the Dacl
  7468. //
  7469. if (NewControlBits & SE_DACL_PRESENT) {
  7470. if (NewDacl != NULL) {
  7471. RtlCopyMemory( Field, NewDacl, NewDacl->AclSize );
  7472. if (!NewDaclInherited) {
  7473. RtlpApplyAclToObject( (PACL)Field, GenericMapping );
  7474. }
  7475. INewDescriptor->Dacl = RtlPointerToOffset(Base,Field);
  7476. if (NewDaclSize > NewDacl->AclSize) {
  7477. RtlZeroMemory (Field + NewDacl->AclSize, NewDaclSize - NewDacl->AclSize);
  7478. }
  7479. Field += NewDaclSize;
  7480. } else {
  7481. INewDescriptor->Dacl = 0;
  7482. }
  7483. }
  7484. //
  7485. // Assign the owner
  7486. //
  7487. RtlCopyMemory( Field, NewOwner, OwnerSize );
  7488. if (NewOwnerSize > OwnerSize) {
  7489. RtlZeroMemory (Field + OwnerSize, NewOwnerSize - OwnerSize);
  7490. }
  7491. INewDescriptor->Owner = RtlPointerToOffset(Base,Field);
  7492. Field += NewOwnerSize;
  7493. if (NewGroup != NULL) {
  7494. RtlCopyMemory( Field, NewGroup, GroupSize );
  7495. if (NewGroupSize > GroupSize) {
  7496. RtlZeroMemory (Field + GroupSize, NewGroupSize - GroupSize);
  7497. }
  7498. INewDescriptor->Group = RtlPointerToOffset(Base,Field);
  7499. }
  7500. Status = STATUS_SUCCESS;
  7501. Cleanup:
  7502. //
  7503. // If we allocated memory for a Server DACL, free it now.
  7504. //
  7505. if (ServerDaclAllocated) {
  7506. #ifdef NTOS_KERNEL_RUNTIME
  7507. ExFreePool( ServerDacl );
  7508. #else // NTOS_KERNEL_RUNTIME
  7509. RtlFreeHeap(RtlProcessHeap(), 0, ServerDacl );
  7510. #endif // NTOS_KERNEL_RUNTIME
  7511. }
  7512. //
  7513. // Either an error was encountered or the assignment has completed
  7514. // successfully. In either case, we have to clean up any memory.
  7515. //
  7516. #ifdef NTOS_KERNEL_RUNTIME
  7517. // if ( SubjectSecurityContext != NULL ) {
  7518. // SeUnlockSubjectContext( SubjectSecurityContext );
  7519. // }
  7520. if (SubjectContextInfo != NULL) {
  7521. ExFreePool( SubjectContextInfo );
  7522. }
  7523. #else // NTOS_KERNEL_RUNTIME
  7524. RtlFreeHeap( HeapHandle, 0, (PVOID)TokenOwnerInfo );
  7525. RtlFreeHeap( HeapHandle, 0, (PVOID)TokenPrimaryGroupInfo );
  7526. RtlFreeHeap( HeapHandle, 0, (PVOID)TokenDefaultDaclInfo );
  7527. RtlFreeHeap( HeapHandle, 0, (PVOID)ServerOwnerInfo );
  7528. RtlFreeHeap( HeapHandle, 0, (PVOID)ServerGroupInfo );
  7529. #endif // NTOS_KERNEL_RUNTIME
  7530. if (NewSaclInherited && NewSacl != NULL ) {
  7531. #ifdef NTOS_KERNEL_RUNTIME
  7532. ExFreePool( NewSacl );
  7533. #else // NTOS_KERNEL_RUNTIME
  7534. RtlFreeHeap( HeapHandle, 0, (PVOID)NewSacl );
  7535. #endif // NTOS_KERNEL_RUNTIME
  7536. }
  7537. if (NewDaclInherited && NewDacl != NULL ) {
  7538. #ifdef NTOS_KERNEL_RUNTIME
  7539. ExFreePool( NewDacl );
  7540. #else // NTOS_KERNEL_RUNTIME
  7541. RtlFreeHeap( HeapHandle, 0, (PVOID)NewDacl );
  7542. #endif // NTOS_KERNEL_RUNTIME
  7543. }
  7544. *NewDescriptor = (PSECURITY_DESCRIPTOR) INewDescriptor;
  7545. return Status;
  7546. }
  7547. NTSTATUS
  7548. RtlpSetSecurityObject (
  7549. IN PVOID Object OPTIONAL,
  7550. IN SECURITY_INFORMATION SecurityInformation,
  7551. IN PSECURITY_DESCRIPTOR ModificationDescriptor,
  7552. IN OUT PSECURITY_DESCRIPTOR *ObjectsSecurityDescriptor,
  7553. IN ULONG AutoInheritFlags,
  7554. IN ULONG PoolType,
  7555. IN PGENERIC_MAPPING GenericMapping,
  7556. IN HANDLE Token OPTIONAL
  7557. )
  7558. /*++
  7559. Routine Description:
  7560. Modify an object's existing self-relative form security descriptor.
  7561. This procedure, called only from user mode, is used to update a
  7562. security descriptor on an existing protected server's object. It
  7563. applies changes requested by a new security descriptor to the existing
  7564. security descriptor. If necessary, this routine will allocate
  7565. additional memory to produce a larger security descriptor. All access
  7566. checking is expected to be done before calling this routine. This
  7567. includes checking for WRITE_OWNER, WRITE_DAC, and privilege to assign a
  7568. system ACL as appropriate.
  7569. The caller of this routine must not be impersonating a client.
  7570. - - WARNING - -
  7571. This service is for use by protected subsystems that project their own
  7572. type of object. This service is explicitly not for use by the
  7573. executive for executive objects and must not be called from kernel
  7574. mode.
  7575. Arguments:
  7576. Object - Optionally supplies the object whose security is
  7577. being adjusted. This is used to update security quota
  7578. information.
  7579. SecurityInformation - Indicates which security information is
  7580. to be applied to the object. The value(s) to be assigned are
  7581. passed in the ModificationDescriptor parameter.
  7582. ModificationDescriptor - Supplies the input security descriptor to be
  7583. applied to the object. The caller of this routine is expected
  7584. to probe and capture the passed security descriptor before calling
  7585. and release it after calling.
  7586. ObjectsSecurityDescriptor - Supplies the address of a pointer to
  7587. the objects security descriptor that is going to be altered by
  7588. this procedure. This security descriptor must be in self-
  7589. relative form or an error will be returned.
  7590. AutoInheritFlags - Controls automatic inheritance of ACES.
  7591. Valid values are a bits mask of the logical OR of
  7592. one or more of the following bits:
  7593. SEF_DACL_AUTO_INHERIT - If set, inherited ACEs from the
  7594. DACL in the ObjectsSecurityDescriptor are preserved and inherited ACEs from
  7595. the ModificationDescriptor are ignored. Inherited ACEs are not supposed
  7596. to be modified; so preserving them across this call is appropriate.
  7597. If a protected server does not itself implement auto inheritance, it should
  7598. not set this bit. The caller of the protected server may implement
  7599. auto inheritance and my indeed be modifying inherited ACEs.
  7600. SEF_SACL_AUTO_INHERIT - If set, inherited ACEs from the
  7601. SACL in the ObjectsSecurityDescriptor are preserved and inherited ACEs from
  7602. the ModificationDescriptor are ignored. Inherited ACEs are not supposed
  7603. to be modified; so preserving them across this call is appropriate.
  7604. If a protected server does not itself implement auto inheritance, it should
  7605. not set this bit. The caller of the protected server may implement
  7606. auto inheritance and my indeed be modifying inherited ACEs.
  7607. SEF_AVOID_PRIVILEGE_CHECK - If set, the Token in not used to ensure the
  7608. Owner passed in ModificationDescriptor is valid.
  7609. PoolType - Specifies the type of pool to allocate for the objects
  7610. security descriptor.
  7611. GenericMapping - This argument provides the mapping of generic to
  7612. specific/standard access types for the object being accessed.
  7613. This mapping structure is expected to be safe to access
  7614. (i.e., captured if necessary) prior to be passed to this routine.
  7615. Token - (optionally) Supplies the token for the client on whose
  7616. behalf the security is being modified. This parameter is only
  7617. required to ensure that the client has provided a legitimate
  7618. value for a new owner SID. The token must be open for
  7619. TOKEN_QUERY access.
  7620. Return Value:
  7621. STATUS_SUCCESS - The operation was successful.
  7622. STATUS_INVALID_OWNER - The owner SID provided as the new owner of the
  7623. target security descriptor is not one the caller is authorized to
  7624. assign as the owner of an object, or the client did not pass
  7625. a token at all.
  7626. STATUS_NO_CLIENT_TOKEN - Indicates a client token was not explicitly
  7627. provided and the caller is not currently impersonating a client.
  7628. STATUS_BAD_DESCRIPTOR_FORMAT - Indicates the provided object's security
  7629. descriptor was not in self-relative format.
  7630. --*/
  7631. {
  7632. BOOLEAN NewGroupPresent = FALSE;
  7633. BOOLEAN NewOwnerPresent = FALSE;
  7634. BOOLEAN ServerAclAllocated = FALSE;
  7635. BOOLEAN LocalDaclAllocated = FALSE;
  7636. BOOLEAN LocalSaclAllocated = FALSE;
  7637. BOOLEAN ServerObject;
  7638. BOOLEAN DaclUntrusted;
  7639. PCHAR Field;
  7640. PCHAR Base;
  7641. PISECURITY_DESCRIPTOR_RELATIVE NewDescriptor = NULL;
  7642. NTSTATUS Status;
  7643. TOKEN_STATISTICS ThreadTokenStatistics;
  7644. ULONG ReturnLength;
  7645. PSID NewGroup;
  7646. PSID NewOwner;
  7647. PACL NewDacl;
  7648. PACL LocalDacl;
  7649. PACL NewSacl;
  7650. PACL LocalSacl;
  7651. ULONG NewDaclSize;
  7652. ULONG NewSaclSize;
  7653. ULONG NewOwnerSize, OwnerSize;
  7654. ULONG NewGroupSize, GroupSize;
  7655. ULONG AllocationSize;
  7656. ULONG ServerOwnerInfoSize;
  7657. HANDLE PrimaryToken;
  7658. ULONG GenericControl;
  7659. ULONG NewControlBits = SE_SELF_RELATIVE;
  7660. PACL ServerDacl;
  7661. SECURITY_SUBJECT_CONTEXT SubjectContext;
  7662. //
  7663. // Typecast to internal representation of security descriptor.
  7664. // Note that the internal one is not a pointer to a pointer.
  7665. // It is just a pointer to a security descriptor.
  7666. //
  7667. PISECURITY_DESCRIPTOR IModificationDescriptor =
  7668. (PISECURITY_DESCRIPTOR)ModificationDescriptor;
  7669. PISECURITY_DESCRIPTOR *IObjectsSecurityDescriptor =
  7670. (PISECURITY_DESCRIPTOR *)(ObjectsSecurityDescriptor);
  7671. #ifndef NTOS_KERNEL_RUNTIME
  7672. PVOID HeapHandle;
  7673. #endif // NTOS_KERNEL_RUNTIME
  7674. RTL_PAGED_CODE();
  7675. //
  7676. // Get the handle to the current process heap
  7677. //
  7678. #ifndef NTOS_KERNEL_RUNTIME
  7679. HeapHandle = RtlProcessHeap();
  7680. #endif // NTOS_KERNEL_RUNTIME
  7681. //
  7682. // Validate that the provided SD is in self-relative form
  7683. //
  7684. if ( !RtlpAreControlBitsSet(*IObjectsSecurityDescriptor, SE_SELF_RELATIVE) ) {
  7685. Status = STATUS_BAD_DESCRIPTOR_FORMAT;
  7686. goto Cleanup;
  7687. }
  7688. //
  7689. // Check to see if we need to edit the passed acl
  7690. // either because we're creating a server object, or because
  7691. // we were passed an untrusted ACL.
  7692. //
  7693. if (ARGUMENT_PRESENT(ModificationDescriptor)) {
  7694. if ( RtlpAreControlBitsSet(IModificationDescriptor, SE_SERVER_SECURITY)) {
  7695. ServerObject = TRUE;
  7696. } else {
  7697. ServerObject = FALSE;
  7698. }
  7699. if ( RtlpAreControlBitsSet(IModificationDescriptor, SE_DACL_UNTRUSTED)) {
  7700. DaclUntrusted = TRUE;
  7701. } else {
  7702. DaclUntrusted = FALSE;
  7703. }
  7704. } else {
  7705. ServerObject = FALSE;
  7706. DaclUntrusted = FALSE;
  7707. }
  7708. //
  7709. // For each item specified in the SecurityInformation, extract it
  7710. // and get it to the point where it can be copied into a new
  7711. // descriptor.
  7712. //
  7713. //
  7714. // if he's setting the owner field, make sure he's
  7715. // allowed to set that value as an owner.
  7716. //
  7717. if (SecurityInformation & OWNER_SECURITY_INFORMATION) {
  7718. NewOwner = RtlpOwnerAddrSecurityDescriptor( IModificationDescriptor );
  7719. NewOwnerPresent = TRUE;
  7720. if ((AutoInheritFlags & SEF_AVOID_PRIVILEGE_CHECK) == 0 ) {
  7721. #ifdef NTOS_KERNEL_RUNTIME
  7722. SeCaptureSubjectContext( &SubjectContext );
  7723. if (!SepValidOwnerSubjectContext( &SubjectContext, NewOwner, ServerObject ) ) {
  7724. SeReleaseSubjectContext( &SubjectContext );
  7725. return( STATUS_INVALID_OWNER );
  7726. } else {
  7727. SeReleaseSubjectContext( &SubjectContext );
  7728. }
  7729. #else // NTOS_KERNEL_RUNTIME
  7730. if ( ARGUMENT_PRESENT( Token )) {
  7731. Status = NtQueryInformationToken(
  7732. Token, // Handle
  7733. TokenStatistics, // TokenInformationClass
  7734. &ThreadTokenStatistics, // TokenInformation
  7735. sizeof(TOKEN_STATISTICS), // TokenInformationLength
  7736. &ReturnLength // ReturnLength
  7737. );
  7738. if (!NT_SUCCESS( Status )) {
  7739. goto Cleanup;
  7740. }
  7741. //
  7742. // If it is an impersonation token, then make sure it is at a
  7743. // high enough level.
  7744. //
  7745. if (ThreadTokenStatistics.TokenType == TokenImpersonation) {
  7746. if (ThreadTokenStatistics.ImpersonationLevel < SecurityIdentification ) {
  7747. Status = STATUS_BAD_IMPERSONATION_LEVEL;
  7748. goto Cleanup;
  7749. }
  7750. }
  7751. } else {
  7752. Status = STATUS_INVALID_OWNER;
  7753. goto Cleanup;
  7754. }
  7755. if (!RtlpValidOwnerSubjectContext(
  7756. Token,
  7757. NewOwner,
  7758. ServerObject,
  7759. &Status) ) {
  7760. Status = STATUS_INVALID_OWNER;
  7761. goto Cleanup;
  7762. }
  7763. #endif // NTOS_KERNEL_RUNTIME
  7764. }
  7765. } else {
  7766. NewOwner = RtlpOwnerAddrSecurityDescriptor ( *IObjectsSecurityDescriptor );
  7767. if (NewOwner == NULL) {
  7768. Status = STATUS_INVALID_OWNER;
  7769. goto Cleanup;
  7770. }
  7771. }
  7772. ASSERT( NewOwner != NULL );
  7773. if (!RtlValidSid( NewOwner )) {
  7774. Status = STATUS_INVALID_OWNER;
  7775. goto Cleanup;
  7776. }
  7777. if (SecurityInformation & GROUP_SECURITY_INFORMATION) {
  7778. NewGroup = RtlpGroupAddrSecurityDescriptor(IModificationDescriptor);
  7779. NewGroupPresent = TRUE;
  7780. } else {
  7781. NewGroup = RtlpGroupAddrSecurityDescriptor( *IObjectsSecurityDescriptor );
  7782. }
  7783. if (NewGroup != NULL) {
  7784. if (!RtlValidSid( NewGroup )) {
  7785. Status = STATUS_INVALID_PRIMARY_GROUP;
  7786. goto Cleanup;
  7787. }
  7788. } else {
  7789. Status = STATUS_INVALID_PRIMARY_GROUP;
  7790. goto Cleanup;
  7791. }
  7792. if (SecurityInformation & DACL_SECURITY_INFORMATION) {
  7793. #ifdef ASSERT_ON_NULL_DACL
  7794. //
  7795. // Culprit will probably be the caller NtSetSecurityObject, or
  7796. // RtlSetSecurityObject.
  7797. //
  7798. if (RtlpAssertOnNullDacls) {
  7799. ASSERT(("NULL DACLs are NOT allowed!",
  7800. RtlpDaclAddrSecurityDescriptor(IModificationDescriptor) != NULL));
  7801. }
  7802. #endif // ASSERT_ON_NULL_DACL
  7803. //
  7804. // If AutoInherit is requested,
  7805. // build a merged ACL.
  7806. //
  7807. if ( AutoInheritFlags & SEF_DACL_AUTO_INHERIT ) {
  7808. Status = RtlpComputeMergedAcl(
  7809. RtlpDaclAddrSecurityDescriptor( *IObjectsSecurityDescriptor ),
  7810. SeControlDaclToGeneric( (*IObjectsSecurityDescriptor)->Control ),
  7811. RtlpDaclAddrSecurityDescriptor( IModificationDescriptor ),
  7812. SeControlDaclToGeneric( IModificationDescriptor->Control ),
  7813. NewOwner,
  7814. NewGroup,
  7815. GenericMapping,
  7816. FALSE, // Not a SACL
  7817. &LocalDacl,
  7818. &GenericControl );
  7819. if ( !NT_SUCCESS(Status)) {
  7820. goto Cleanup;
  7821. }
  7822. LocalDaclAllocated = TRUE;
  7823. NewDacl = LocalDacl;
  7824. NewControlBits |= SE_DACL_PRESENT;
  7825. NewControlBits |= SeControlGenericToDacl( GenericControl );
  7826. //
  7827. // If AutoInherit isn't requested,
  7828. // just grab a copy of the input DACL.
  7829. //
  7830. } else {
  7831. NewDacl = RtlpDaclAddrSecurityDescriptor( IModificationDescriptor );
  7832. NewControlBits |= SE_DACL_PRESENT;
  7833. NewControlBits |= IModificationDescriptor->Control & SE_DACL_PROTECTED;
  7834. //
  7835. // If the original caller claims he understands auto inheritance,
  7836. // preserve the AutoInherited flag.
  7837. //
  7838. if ( RtlpAreControlBitsSet(IModificationDescriptor, SE_DACL_AUTO_INHERIT_REQ|SE_DACL_AUTO_INHERITED) ) {
  7839. NewControlBits |= SE_DACL_AUTO_INHERITED;
  7840. }
  7841. }
  7842. if (ServerObject) {
  7843. #ifdef NTOS_KERNEL_RUNTIME
  7844. PSID SubjectContextOwner;
  7845. PSID SubjectContextGroup;
  7846. PSID SubjectContextServerOwner;
  7847. PSID SubjectContextServerGroup;
  7848. PACL SubjectContextDacl;
  7849. SeCaptureSubjectContext( &SubjectContext );
  7850. SepGetDefaultsSubjectContext(
  7851. &SubjectContext,
  7852. &SubjectContextOwner,
  7853. &SubjectContextGroup,
  7854. &SubjectContextServerOwner,
  7855. &SubjectContextServerGroup,
  7856. &SubjectContextDacl
  7857. );
  7858. Status = RtlpCreateServerAcl(
  7859. NewDacl,
  7860. DaclUntrusted,
  7861. SubjectContextServerOwner,
  7862. &ServerDacl,
  7863. &ServerAclAllocated
  7864. );
  7865. SeReleaseSubjectContext( &SubjectContext );
  7866. #else // NTOS_KERNEL_RUNTIME
  7867. PTOKEN_OWNER ServerSid;
  7868. //
  7869. // Obtain the default Server SID to substitute in the
  7870. // ACL if necessary.
  7871. //
  7872. ServerOwnerInfoSize = RtlLengthRequiredSid( SID_MAX_SUB_AUTHORITIES );
  7873. ServerSid = RtlAllocateHeap( HeapHandle, MAKE_TAG( SE_TAG ), ServerOwnerInfoSize );
  7874. if (ServerSid == NULL) {
  7875. Status = STATUS_NO_MEMORY;
  7876. goto Cleanup;
  7877. }
  7878. Status = NtOpenProcessToken(
  7879. NtCurrentProcess(),
  7880. TOKEN_QUERY,
  7881. &PrimaryToken
  7882. );
  7883. if (!NT_SUCCESS( Status )) {
  7884. RtlFreeHeap( HeapHandle, 0, ServerSid );
  7885. goto Cleanup;
  7886. }
  7887. Status = NtQueryInformationToken(
  7888. PrimaryToken, // Handle
  7889. TokenOwner, // TokenInformationClass
  7890. ServerSid, // TokenInformation
  7891. ServerOwnerInfoSize, // TokenInformationLength
  7892. &ServerOwnerInfoSize // ReturnLength
  7893. );
  7894. NtClose( PrimaryToken );
  7895. if (!NT_SUCCESS( Status )) {
  7896. RtlFreeHeap( HeapHandle, 0, ServerSid );
  7897. goto Cleanup;
  7898. }
  7899. Status = RtlpCreateServerAcl(
  7900. NewDacl,
  7901. DaclUntrusted,
  7902. ServerSid->Owner,
  7903. &ServerDacl,
  7904. &ServerAclAllocated
  7905. );
  7906. RtlFreeHeap( HeapHandle, 0, ServerSid );
  7907. #endif // NTOS_KERNEL_RUNTIME
  7908. if (!NT_SUCCESS( Status )) {
  7909. goto Cleanup;
  7910. }
  7911. NewDacl = ServerDacl;
  7912. }
  7913. } else {
  7914. NewDacl = RtlpDaclAddrSecurityDescriptor( *IObjectsSecurityDescriptor );
  7915. }
  7916. if (SecurityInformation & SACL_SECURITY_INFORMATION) {
  7917. //
  7918. // If AutoInherit is requested,
  7919. // build a merged ACL.
  7920. //
  7921. if ( AutoInheritFlags & SEF_SACL_AUTO_INHERIT ) {
  7922. Status = RtlpComputeMergedAcl(
  7923. RtlpSaclAddrSecurityDescriptor( *IObjectsSecurityDescriptor ),
  7924. SeControlSaclToGeneric( (*IObjectsSecurityDescriptor)->Control ),
  7925. RtlpSaclAddrSecurityDescriptor( IModificationDescriptor ),
  7926. SeControlSaclToGeneric( IModificationDescriptor->Control ),
  7927. NewOwner,
  7928. NewGroup,
  7929. GenericMapping,
  7930. TRUE, // Is a SACL
  7931. &LocalSacl,
  7932. &GenericControl );
  7933. if ( !NT_SUCCESS(Status)) {
  7934. goto Cleanup;
  7935. }
  7936. LocalSaclAllocated = TRUE;
  7937. NewSacl = LocalSacl;
  7938. NewControlBits |= SE_SACL_PRESENT;
  7939. NewControlBits |= SeControlGenericToSacl( GenericControl );
  7940. } else {
  7941. NewSacl = RtlpSaclAddrSecurityDescriptor( IModificationDescriptor );
  7942. NewControlBits |= SE_SACL_PRESENT;
  7943. NewControlBits |= IModificationDescriptor->Control & SE_SACL_PROTECTED;
  7944. //
  7945. // If the original caller claims he understands auto inheritance,
  7946. // preserve the AutoInherited flag.
  7947. //
  7948. if ( RtlpAreControlBitsSet(IModificationDescriptor, SE_SACL_AUTO_INHERIT_REQ|SE_SACL_AUTO_INHERITED) ) {
  7949. NewControlBits |= SE_SACL_AUTO_INHERITED;
  7950. }
  7951. }
  7952. } else {
  7953. NewSacl = RtlpSaclAddrSecurityDescriptor( *IObjectsSecurityDescriptor );
  7954. }
  7955. //
  7956. // Everything is assignable by the requestor.
  7957. // Calculate the memory needed to house all the information in
  7958. // a self-relative security descriptor.
  7959. //
  7960. // Also map the ACEs for application to the target object
  7961. // type, if they haven't already been mapped.
  7962. //
  7963. OwnerSize = SeLengthSid(NewOwner);
  7964. NewOwnerSize = LongAlignSize(OwnerSize);
  7965. if (NewGroup != NULL) {
  7966. GroupSize = SeLengthSid(NewGroup);
  7967. } else {
  7968. GroupSize = 0;
  7969. }
  7970. NewGroupSize = LongAlignSize(GroupSize);
  7971. if (NewSacl != NULL) {
  7972. NewSaclSize = LongAlignSize(NewSacl->AclSize);
  7973. } else {
  7974. NewSaclSize = 0;
  7975. }
  7976. if (NewDacl !=NULL) {
  7977. NewDaclSize = LongAlignSize(NewDacl->AclSize);
  7978. } else {
  7979. NewDaclSize = 0;
  7980. }
  7981. AllocationSize = LongAlignSize(sizeof(SECURITY_DESCRIPTOR_RELATIVE)) +
  7982. NewOwnerSize +
  7983. NewGroupSize +
  7984. NewSaclSize +
  7985. NewDaclSize;
  7986. //
  7987. // Allocate and initialize the security descriptor as
  7988. // self-relative form.
  7989. //
  7990. #ifdef NTOS_KERNEL_RUNTIME
  7991. NewDescriptor = ExAllocatePoolWithTag(PoolType, AllocationSize, 'dSeS');
  7992. #else // NTOS_KERNEL_RUNTIME
  7993. NewDescriptor = RtlAllocateHeap( HeapHandle, MAKE_TAG( SE_TAG ), AllocationSize );
  7994. #endif // NTOS_KERNEL_RUNTIME
  7995. if ( NewDescriptor == NULL ) {
  7996. Status = STATUS_NO_MEMORY;
  7997. goto Cleanup;
  7998. }
  7999. Status = RtlCreateSecurityDescriptorRelative(
  8000. NewDescriptor,
  8001. SECURITY_DESCRIPTOR_REVISION
  8002. );
  8003. ASSERT( NT_SUCCESS( Status ) );
  8004. #ifdef NTOS_KERNEL_RUNTIME
  8005. //
  8006. // We must check to make sure that the Group and Dacl size
  8007. // do not exceed the quota preallocated for this object's
  8008. // security when it was created.
  8009. //
  8010. // Update SeComputeSecurityQuota if this changes.
  8011. //
  8012. if (ARGUMENT_PRESENT( Object )) {
  8013. Status = ObValidateSecurityQuota(
  8014. Object,
  8015. NewGroupSize + NewDaclSize
  8016. );
  8017. if (!NT_SUCCESS( Status )) {
  8018. //
  8019. // The new information is too big.
  8020. //
  8021. ExFreePool( NewDescriptor );
  8022. goto Cleanup;
  8023. }
  8024. }
  8025. #endif // NTOS_KERNEL_RUNTIME
  8026. Base = (PCHAR)NewDescriptor;
  8027. Field = Base + sizeof(SECURITY_DESCRIPTOR_RELATIVE);
  8028. //
  8029. // Map and Copy in the Sacl
  8030. //
  8031. // if new item {
  8032. // PRESENT=TRUE
  8033. // DEFAULTED=FALSE
  8034. // if (NULL) {
  8035. // set new pointer to NULL
  8036. // } else {
  8037. // copy into new SD
  8038. // }
  8039. // } else {
  8040. // copy PRESENT bit
  8041. // copy DEFAULTED bit
  8042. // if (NULL) {
  8043. // set new pointer to NULL
  8044. // } else {
  8045. // copy old one into new SD
  8046. // }
  8047. // }
  8048. RtlpSetControlBits( NewDescriptor, NewControlBits );
  8049. if (IModificationDescriptor->Control & SE_RM_CONTROL_VALID) {
  8050. NewDescriptor->Sbz1 = IModificationDescriptor->Sbz1;
  8051. NewDescriptor->Control |= SE_RM_CONTROL_VALID;
  8052. }
  8053. if (NewSacl == NULL) {
  8054. NewDescriptor->Sacl = 0;
  8055. } else {
  8056. RtlCopyMemory( Field, NewSacl, NewSacl->AclSize );
  8057. RtlpApplyAclToObject( (PACL)Field, GenericMapping );
  8058. NewDescriptor->Sacl = RtlPointerToOffset(Base,Field);
  8059. if (NewSaclSize > NewSacl->AclSize) {
  8060. RtlZeroMemory( Field + NewSacl->AclSize, NewSaclSize - NewSacl->AclSize);
  8061. }
  8062. Field += NewSaclSize;
  8063. }
  8064. if ( (NewControlBits & SE_SACL_PRESENT) == 0 ) {
  8065. //
  8066. // Propagate the SE_SACL_DEFAULTED and SE_SACL_PRESENT
  8067. // bits from the old security descriptor into the new
  8068. // one.
  8069. //
  8070. RtlpPropagateControlBits(
  8071. NewDescriptor,
  8072. *IObjectsSecurityDescriptor,
  8073. SE_SACL_DEFAULTED | SE_SACL_PRESENT | SE_SACL_PROTECTED
  8074. );
  8075. }
  8076. //
  8077. // Fill in Dacl field in new SD
  8078. //
  8079. if (NewDacl == NULL) {
  8080. NewDescriptor->Dacl = 0;
  8081. } else {
  8082. RtlCopyMemory( Field, NewDacl, NewDacl->AclSize );
  8083. RtlpApplyAclToObject( (PACL)Field, GenericMapping );
  8084. NewDescriptor->Dacl = RtlPointerToOffset(Base,Field);
  8085. if (NewDaclSize > NewDacl->AclSize) {
  8086. RtlZeroMemory( Field + NewDacl->AclSize, NewDaclSize - NewDacl->AclSize);
  8087. }
  8088. Field += NewDaclSize;
  8089. }
  8090. if ( (NewControlBits & SE_DACL_PRESENT) == 0 ) {
  8091. //
  8092. // Propagate the SE_DACL_DEFAULTED and SE_DACL_PRESENT
  8093. // bits from the old security descriptor into the new
  8094. // one.
  8095. //
  8096. RtlpPropagateControlBits(
  8097. NewDescriptor,
  8098. *IObjectsSecurityDescriptor,
  8099. SE_DACL_DEFAULTED | SE_DACL_PRESENT | SE_DACL_PROTECTED
  8100. );
  8101. }
  8102. // if new item {
  8103. // PRESENT=TRUE
  8104. // DEFAULTED=FALSE
  8105. // if (NULL) {
  8106. // set new pointer to NULL
  8107. // } else {
  8108. // copy into new SD
  8109. // }
  8110. // } else {
  8111. // copy PRESENT bit
  8112. // copy DEFAULTED bit
  8113. // if (NULL) {
  8114. // set new pointer to NULL
  8115. // } else {
  8116. // copy old one into new SD
  8117. // }
  8118. // }
  8119. //
  8120. // Fill in Owner field in new SD
  8121. //
  8122. RtlCopyMemory( Field, NewOwner, OwnerSize );
  8123. if (OwnerSize < NewOwnerSize) {
  8124. RtlZeroMemory( Field + OwnerSize, NewOwnerSize - OwnerSize );
  8125. }
  8126. NewDescriptor->Owner = RtlPointerToOffset(Base,Field);
  8127. Field += NewOwnerSize;
  8128. if (!NewOwnerPresent) {
  8129. //
  8130. // Propagate the SE_OWNER_DEFAULTED bit from the old SD.
  8131. // If a new owner is being assigned, we want to leave
  8132. // SE_OWNER_DEFAULTED off, which means leave it alone.
  8133. //
  8134. RtlpPropagateControlBits(
  8135. NewDescriptor,
  8136. *IObjectsSecurityDescriptor,
  8137. SE_OWNER_DEFAULTED
  8138. );
  8139. } else {
  8140. ASSERT( !RtlpAreControlBitsSet( NewDescriptor, SE_OWNER_DEFAULTED ) );
  8141. }
  8142. //
  8143. // Fill in Group field in new SD
  8144. //
  8145. if ( NewGroup != NULL) {
  8146. RtlCopyMemory( Field, NewGroup, GroupSize );
  8147. if (GroupSize < NewGroupSize) {
  8148. RtlZeroMemory( Field + GroupSize, NewGroupSize - GroupSize);
  8149. }
  8150. NewDescriptor->Group = RtlPointerToOffset(Base,Field);
  8151. }
  8152. if (!NewGroupPresent) {
  8153. //
  8154. // Propagate the SE_GROUP_DEFAULTED bit from the old SD
  8155. // If a new owner is being assigned, we want to leave
  8156. // SE_GROUP_DEFAULTED off, which means leave it alone.
  8157. //
  8158. RtlpPropagateControlBits(
  8159. NewDescriptor,
  8160. *IObjectsSecurityDescriptor,
  8161. SE_GROUP_DEFAULTED
  8162. );
  8163. } else {
  8164. ASSERT( !RtlpAreControlBitsSet( NewDescriptor, SE_GROUP_DEFAULTED ) );
  8165. }
  8166. //
  8167. // Free old descriptor
  8168. //
  8169. // Kernel version doesn't free the old descriptor
  8170. #ifndef NTOS_KERNEL_RUNTIME
  8171. RtlFreeHeap( HeapHandle, 0, (PVOID) *IObjectsSecurityDescriptor );
  8172. #endif // NTOS_KERNEL_RUNTIME
  8173. *ObjectsSecurityDescriptor = (PSECURITY_DESCRIPTOR)NewDescriptor;
  8174. Status = STATUS_SUCCESS;
  8175. Cleanup:
  8176. if ( LocalDaclAllocated ) {
  8177. #ifdef NTOS_KERNEL_RUNTIME
  8178. ExFreePool( LocalDacl );
  8179. #else // NTOS_KERNEL_RUNTIME
  8180. RtlFreeHeap( HeapHandle, 0, LocalDacl );
  8181. #endif // NTOS_KERNEL_RUNTIME
  8182. }
  8183. if ( LocalSaclAllocated ) {
  8184. #ifdef NTOS_KERNEL_RUNTIME
  8185. ExFreePool( LocalSacl );
  8186. #else // NTOS_KERNEL_RUNTIME
  8187. RtlFreeHeap( HeapHandle, 0, LocalSacl );
  8188. #endif // NTOS_KERNEL_RUNTIME
  8189. }
  8190. if (ServerAclAllocated) {
  8191. #ifdef NTOS_KERNEL_RUNTIME
  8192. ExFreePool( ServerDacl );
  8193. #else // NTOS_KERNEL_RUNTIME
  8194. RtlFreeHeap( HeapHandle, 0, ServerDacl );
  8195. #endif // NTOS_KERNEL_RUNTIME
  8196. }
  8197. return( Status );
  8198. }
  8199. BOOLEAN RtlpValidateSDOffsetAndSize (
  8200. IN ULONG Offset,
  8201. IN ULONG Length,
  8202. IN ULONG MinLength,
  8203. OUT PULONG MaxLength
  8204. )
  8205. /*++
  8206. Routine Description:
  8207. This procedure validates offsets within a SecurityDescriptor.
  8208. It checks that the structure can have the minimum length,
  8209. not overlap with the fixed header and returns the maximum size
  8210. of the item and longword alignment.
  8211. Arguments:
  8212. Offset - Offset from start of SD of structure to validate
  8213. Length - Total size of SD
  8214. MinLength - Minimum size this structure can be
  8215. MaxLength - Retuns the maximum length this item can be given by
  8216. the enclosing structure.
  8217. Return Value:
  8218. BOOLEAN - TRUE if the item is valid
  8219. --*/
  8220. {
  8221. ULONG Left;
  8222. *MaxLength = 0;
  8223. //
  8224. // Don't allow overlap with header just in case caller modifies control bits etc
  8225. //
  8226. if (Offset < sizeof (SECURITY_DESCRIPTOR_RELATIVE)) {
  8227. return FALSE;
  8228. }
  8229. //
  8230. // Don't allow offsets beyond the end of the buffer
  8231. //
  8232. if (Offset >= Length) {
  8233. return FALSE;
  8234. }
  8235. //
  8236. // Calculate maximim size of segment and check its limits
  8237. //
  8238. Left = Length - Offset;
  8239. if (Left < MinLength) {
  8240. return FALSE;
  8241. }
  8242. //
  8243. // Reject unaligned offsets
  8244. //
  8245. if (Offset & (sizeof (ULONG) - 1)) {
  8246. return FALSE;
  8247. }
  8248. *MaxLength = Left;
  8249. return TRUE;
  8250. }
  8251. BOOLEAN
  8252. RtlValidRelativeSecurityDescriptor (
  8253. IN PSECURITY_DESCRIPTOR SecurityDescriptorInput,
  8254. IN ULONG SecurityDescriptorLength,
  8255. IN SECURITY_INFORMATION RequiredInformation
  8256. )
  8257. /*++
  8258. Routine Description:
  8259. This procedure validates a SecurityDescriptor's structure
  8260. contained within a flat buffer. This involves validating
  8261. the revision levels of each component of the security
  8262. descriptor.
  8263. Arguments:
  8264. SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
  8265. to validate.
  8266. SecurityDescriptorLength - Size of flat buffer containing the security
  8267. descriptor.
  8268. RequiredInformation - Which SD components must be present to be valid.
  8269. OWNER_SECURITY_INFORMATION etc as a bit mask.
  8270. OWNER_SECURITY_INFORMATION - There must be a valid owner SID
  8271. GROUP_SECURITY_INFORMATION - There must be a valid group SID
  8272. DACL_SECURITY_INFORMATION - Ignored
  8273. SACL_SECURITY_INFORMATION - Ignored
  8274. Return Value:
  8275. BOOLEAN - TRUE if the structure of SecurityDescriptor is valid.
  8276. --*/
  8277. {
  8278. PISECURITY_DESCRIPTOR_RELATIVE SecurityDescriptor;
  8279. PISID OwnerSid;
  8280. PISID GroupSid;
  8281. PACE_HEADER Ace;
  8282. PACL Dacl;
  8283. PACL Sacl;
  8284. ULONG MaxOwnerSidLength;
  8285. ULONG MaxGroupSidLength;
  8286. ULONG MaxDaclLength;
  8287. ULONG MaxSaclLength;
  8288. if (SecurityDescriptorLength < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) {
  8289. return FALSE;
  8290. }
  8291. //
  8292. // Check the revision information.
  8293. //
  8294. if (((PISECURITY_DESCRIPTOR) SecurityDescriptorInput)->Revision !=
  8295. SECURITY_DESCRIPTOR_REVISION) {
  8296. return FALSE;
  8297. }
  8298. //
  8299. // Make sure the passed SecurityDescriptor is in self-relative form
  8300. //
  8301. if (!(((PISECURITY_DESCRIPTOR) SecurityDescriptorInput)->Control & SE_SELF_RELATIVE)) {
  8302. return FALSE;
  8303. }
  8304. SecurityDescriptor = (PISECURITY_DESCRIPTOR_RELATIVE) SecurityDescriptorInput;
  8305. //
  8306. // Validate the owner if it's there and see if its allowed to be missing
  8307. //
  8308. if (SecurityDescriptor->Owner == 0) {
  8309. if (RequiredInformation & OWNER_SECURITY_INFORMATION) {
  8310. return FALSE;
  8311. }
  8312. } else {
  8313. if (!RtlpValidateSDOffsetAndSize (SecurityDescriptor->Owner,
  8314. SecurityDescriptorLength,
  8315. sizeof (SID),
  8316. &MaxOwnerSidLength)) {
  8317. return FALSE;
  8318. }
  8319. //
  8320. // It is safe to reference the owner's SubAuthorityCount, compute the
  8321. // expected length of the SID
  8322. //
  8323. OwnerSid = (PSID)RtlOffsetToPointer (SecurityDescriptor,
  8324. SecurityDescriptor->Owner);
  8325. if (OwnerSid->Revision != SID_REVISION) {
  8326. return FALSE;
  8327. }
  8328. if (OwnerSid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  8329. return FALSE;
  8330. }
  8331. if (MaxOwnerSidLength < (ULONG) SeLengthSid (OwnerSid)) {
  8332. return FALSE;
  8333. }
  8334. }
  8335. //
  8336. // The owner appears to be a structurally valid SID that lies within
  8337. // the bounds of the security descriptor. Do the same for the Group
  8338. // if there is one.
  8339. //
  8340. //
  8341. // Validate the group if it's there and see if its allowed to be missing
  8342. //
  8343. if (SecurityDescriptor->Group == 0) {
  8344. if (RequiredInformation & GROUP_SECURITY_INFORMATION) {
  8345. return FALSE;
  8346. }
  8347. } else {
  8348. if (!RtlpValidateSDOffsetAndSize (SecurityDescriptor->Group,
  8349. SecurityDescriptorLength,
  8350. sizeof (SID),
  8351. &MaxGroupSidLength)) {
  8352. return FALSE;
  8353. }
  8354. //
  8355. // It is safe to reference the group's SubAuthorityCount, compute the
  8356. // expected length of the SID
  8357. //
  8358. GroupSid = (PSID)RtlOffsetToPointer (SecurityDescriptor,
  8359. SecurityDescriptor->Group);
  8360. if (GroupSid->Revision != SID_REVISION) {
  8361. return FALSE;
  8362. }
  8363. if (GroupSid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  8364. return FALSE;
  8365. }
  8366. if (MaxGroupSidLength < (ULONG) SeLengthSid (GroupSid)) {
  8367. return FALSE;
  8368. }
  8369. }
  8370. //
  8371. // Validate the DACL if it's there and check if its allowed to be missing.
  8372. //
  8373. if (!RtlpAreControlBitsSet (SecurityDescriptor, SE_DACL_PRESENT)) {
  8374. //
  8375. // Some code does this kind of thing:
  8376. //
  8377. // InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION);
  8378. // RegSetKeySecurity(hKey, DACL_SECURITY_INFORMATION, &sd) )
  8379. //
  8380. // With the current system this works the same as passing in a NULL DACL but it looks
  8381. // almost by accident
  8382. //
  8383. // if (RequiredInformation & DACL_SECURITY_INFORMATION) {
  8384. // return FALSE;
  8385. // }
  8386. } else if (SecurityDescriptor->Dacl) {
  8387. if (!RtlpValidateSDOffsetAndSize (SecurityDescriptor->Dacl,
  8388. SecurityDescriptorLength,
  8389. sizeof (ACL),
  8390. &MaxDaclLength)) {
  8391. return FALSE;
  8392. }
  8393. Dacl = (PACL) RtlOffsetToPointer (SecurityDescriptor,
  8394. SecurityDescriptor->Dacl);
  8395. //
  8396. // Make sure the DACL length fits within the bounds of the security descriptor.
  8397. //
  8398. if (MaxDaclLength < Dacl->AclSize) {
  8399. return FALSE;
  8400. }
  8401. //
  8402. // Make sure the ACL is structurally valid.
  8403. //
  8404. if (!RtlValidAcl (Dacl)) {
  8405. return FALSE;
  8406. }
  8407. }
  8408. //
  8409. // Validate the SACL if it's there and check if its allowed to be missing.
  8410. //
  8411. if (!RtlpAreControlBitsSet (SecurityDescriptor, SE_SACL_PRESENT)) {
  8412. // if (RequiredInformation & SACL_SECURITY_INFORMATION) {
  8413. // return FALSE;
  8414. // }
  8415. } else if (SecurityDescriptor->Sacl) {
  8416. if (!RtlpValidateSDOffsetAndSize (SecurityDescriptor->Sacl,
  8417. SecurityDescriptorLength,
  8418. sizeof (ACL),
  8419. &MaxSaclLength)) {
  8420. return FALSE;
  8421. }
  8422. Sacl = (PACL) RtlOffsetToPointer (SecurityDescriptor,
  8423. SecurityDescriptor->Sacl);
  8424. //
  8425. // Make sure the SACL length fits within the bounds of the security descriptor.
  8426. //
  8427. if (MaxSaclLength < Sacl->AclSize) {
  8428. return FALSE;
  8429. }
  8430. //
  8431. // Make sure the ACL is structurally valid.
  8432. //
  8433. if (!RtlValidAcl (Sacl)) {
  8434. return FALSE;
  8435. }
  8436. }
  8437. return TRUE;
  8438. }
  8439. BOOLEAN
  8440. RtlGetSecurityDescriptorRMControl(
  8441. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  8442. OUT PUCHAR RMControl
  8443. )
  8444. /*++
  8445. Routine Description:
  8446. This procedure returns the RM Control flags from a SecurityDescriptor if
  8447. SE_RM_CONTROL_VALID flags is present in the control field.
  8448. Arguments:
  8449. SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
  8450. RMControl - Returns the flags in the SecurityDescriptor if
  8451. SE_RM_CONTROL_VALID is set in the control bits of the
  8452. SecurityDescriptor.
  8453. Return Value:
  8454. BOOLEAN - TRUE if SE_RM_CONTROL_VALID is set in the Control bits of the
  8455. SecurityDescriptor.
  8456. Note:
  8457. Parameter validation has already been done in Advapi.
  8458. --*/
  8459. {
  8460. PISECURITY_DESCRIPTOR ISecurityDescriptor = (PISECURITY_DESCRIPTOR) SecurityDescriptor;
  8461. if (!(ISecurityDescriptor->Control & SE_RM_CONTROL_VALID))
  8462. {
  8463. *RMControl = 0;
  8464. return FALSE;
  8465. }
  8466. *RMControl = ISecurityDescriptor->Sbz1;
  8467. return TRUE;
  8468. }
  8469. BOOLEAN
  8470. RtlpGuidPresentInGuidList(
  8471. IN GUID *InheritedObjectType,
  8472. IN GUID **pNewObjectType,
  8473. IN ULONG GuidCount
  8474. )
  8475. /*++
  8476. Routine Description:
  8477. This routine returns whether a given guid is present in a list of guids.
  8478. Arguments:
  8479. InheritedObjectType - Guid from the ace that will be compared against
  8480. the object types for the object.
  8481. pNewObjectType - List of types of object being inherited to.
  8482. GuidCount - Number of object types in the list.
  8483. Return Value:
  8484. Returns TRUE if the given guid is present in the list of guids.
  8485. FALSE otherwise.
  8486. --*/
  8487. {
  8488. ULONG i;
  8489. for (i = 0; i < GuidCount; i++) {
  8490. if (RtlEqualMemory(
  8491. InheritedObjectType,
  8492. pNewObjectType[i],
  8493. sizeof(GUID) ) ) {
  8494. return TRUE;
  8495. }
  8496. }
  8497. return FALSE;
  8498. }
  8499. VOID
  8500. RtlSetSecurityDescriptorRMControl(
  8501. IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor,
  8502. IN PUCHAR RMControl OPTIONAL
  8503. )
  8504. /*++
  8505. Routine Description:
  8506. This procedure sets the RM Control flag in the control field of
  8507. SecurityDescriptor and sets Sbz1 to the the byte to which RMContol points.
  8508. If RMControl is NULL then the bits are cleared.
  8509. Arguments:
  8510. SecurityDescriptor - Pointer to the SECURITY_DESCRIPTOR structure
  8511. RMControl - Pointer to the flags to set. If NULL then the bits
  8512. are cleared.
  8513. Note:
  8514. Parameter validation has already been done in Advapi.
  8515. --*/
  8516. {
  8517. PISECURITY_DESCRIPTOR ISecurityDescriptor = (PISECURITY_DESCRIPTOR) SecurityDescriptor;
  8518. if (ARGUMENT_PRESENT(RMControl)) {
  8519. ISecurityDescriptor->Control |= SE_RM_CONTROL_VALID;
  8520. ISecurityDescriptor->Sbz1 = *RMControl;
  8521. } else {
  8522. ISecurityDescriptor->Control &= ~SE_RM_CONTROL_VALID;
  8523. ISecurityDescriptor->Sbz1 = 0;
  8524. }
  8525. }
  8526. #endif // #ifndef BLDR_KERNEL_RUNTIME
  8527. NTSTATUS
  8528. RtlMapSecurityErrorToNtStatus(
  8529. IN SECURITY_STATUS Error
  8530. )
  8531. /*++
  8532. Routine Description:
  8533. This procedure maps a security HRESULT to the proper NTSTATUS code.
  8534. Arguments:
  8535. Error - a security HRESULT
  8536. Return Value: The NTSTATUS code corresponding to the HRESULT. If no
  8537. status code can be mapped, the original error is returned.
  8538. Note:
  8539. --*/
  8540. {
  8541. NTSTATUS Status;
  8542. switch(Error) {
  8543. case SEC_E_INSUFFICIENT_MEMORY : Status = STATUS_INSUFFICIENT_RESOURCES; break;
  8544. case SEC_E_INVALID_HANDLE : Status = STATUS_INVALID_HANDLE; break;
  8545. case SEC_E_UNSUPPORTED_FUNCTION : Status = STATUS_NOT_SUPPORTED; break;
  8546. case SEC_E_TARGET_UNKNOWN : Status = STATUS_BAD_NETWORK_PATH; break;
  8547. case SEC_E_INTERNAL_ERROR : Status = STATUS_INTERNAL_ERROR; break;
  8548. case SEC_E_SECPKG_NOT_FOUND : Status = STATUS_NO_SUCH_PACKAGE; break;
  8549. case SEC_E_NOT_OWNER : Status = STATUS_PRIVILEGE_NOT_HELD; break;
  8550. case SEC_E_CANNOT_INSTALL : Status = STATUS_NO_SUCH_PACKAGE; break;
  8551. case SEC_E_INVALID_TOKEN : Status = STATUS_INVALID_PARAMETER; break;
  8552. case SEC_E_CANNOT_PACK : Status = STATUS_INVALID_PARAMETER; break;
  8553. case SEC_E_QOP_NOT_SUPPORTED : Status = STATUS_NOT_SUPPORTED; break;
  8554. case SEC_E_NO_IMPERSONATION : Status = STATUS_CANNOT_IMPERSONATE; break;
  8555. case SEC_E_LOGON_DENIED : Status = STATUS_LOGON_FAILURE; break;
  8556. case SEC_E_UNKNOWN_CREDENTIALS : Status = STATUS_NO_SUCH_LOGON_SESSION; break;
  8557. case SEC_E_NO_CREDENTIALS : Status = STATUS_NO_SUCH_LOGON_SESSION; break;
  8558. case SEC_E_MESSAGE_ALTERED : Status = STATUS_ACCESS_DENIED; break;
  8559. case SEC_E_OUT_OF_SEQUENCE : Status = STATUS_ACCESS_DENIED; break;
  8560. case SEC_E_NO_AUTHENTICATING_AUTHORITY : Status = STATUS_NO_LOGON_SERVERS; break;
  8561. case SEC_E_BAD_PKGID : Status = STATUS_NO_SUCH_PACKAGE; break;
  8562. case SEC_E_TIME_SKEW : Status = STATUS_TIME_DIFFERENCE_AT_DC; break;
  8563. default: Status = (NTSTATUS) Error;
  8564. }
  8565. return(Status);
  8566. }