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

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