Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2671 lines
66 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Capture.c
  5. Abstract:
  6. This Module implements the security data structure capturing routines.
  7. There are corresponding Release routines for the data structures that
  8. are captured into allocated pool.
  9. Author:
  10. Gary Kimura (GaryKi) 9-Nov-1989
  11. Jim Kelly (JimK) 1-Feb-1990
  12. Environment:
  13. Kernel Mode
  14. Revision History:
  15. --*/
  16. #include "pch.h"
  17. #pragma hdrstop
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE,SeCaptureSecurityDescriptor)
  20. #pragma alloc_text(PAGE,SeReleaseSecurityDescriptor)
  21. #pragma alloc_text(PAGE,SepCopyProxyData)
  22. #pragma alloc_text(PAGE,SepFreeProxyData)
  23. #pragma alloc_text(PAGE,SepProbeAndCaptureQosData)
  24. #pragma alloc_text(PAGE,SeFreeCapturedSecurityQos)
  25. #pragma alloc_text(PAGE,SeCaptureSecurityQos)
  26. #pragma alloc_text(PAGE,SeCaptureSid)
  27. #pragma alloc_text(PAGE,SeReleaseSid)
  28. #pragma alloc_text(PAGE,SeCaptureAcl)
  29. #pragma alloc_text(PAGE,SeReleaseAcl)
  30. #pragma alloc_text(PAGE,SeCaptureLuidAndAttributesArray)
  31. #pragma alloc_text(PAGE,SeReleaseLuidAndAttributesArray)
  32. #pragma alloc_text(PAGE,SeCaptureSidAndAttributesArray)
  33. #pragma alloc_text(PAGE,SeReleaseSidAndAttributesArray)
  34. #pragma alloc_text(PAGE,SeComputeQuotaInformationSize)
  35. #pragma alloc_text(PAGE,SeValidSecurityDescriptor)
  36. #endif
  37. #define LongAligned( ptr ) (LongAlignPtr(ptr) == (ptr))
  38. NTSTATUS
  39. SeCaptureSecurityDescriptor (
  40. IN PSECURITY_DESCRIPTOR InputSecurityDescriptor,
  41. IN KPROCESSOR_MODE RequestorMode,
  42. IN POOL_TYPE PoolType,
  43. IN BOOLEAN ForceCapture,
  44. OUT PSECURITY_DESCRIPTOR *OutputSecurityDescriptor
  45. )
  46. /*++
  47. Routine Description:
  48. This routine probes and captures a copy of the security descriptor based
  49. upon the following tests.
  50. if the requestor mode is not kernel mode then
  51. probe and capture the input descriptor
  52. (the captured descriptor is self-relative)
  53. if the requstor mode is kernel mode then
  54. if force capture is true then
  55. do not probe the input descriptor, but do capture it.
  56. (the captured descriptor is self-relative)
  57. else
  58. do nothing
  59. (the input descriptor is expected to be self-relative)
  60. Arguments:
  61. InputSecurityDescriptor - Supplies the security descriptor to capture.
  62. This parameter is assumed to have been provided by the mode specified
  63. in RequestorMode.
  64. RequestorMode - Specifies the caller's access mode.
  65. PoolType - Specifies which pool type to allocate the captured
  66. descriptor from
  67. ForceCapture - Specifies whether the input descriptor should always be
  68. captured
  69. OutputSecurityDescriptor - Supplies the address of a pointer to the
  70. output security descriptor. The captured descriptor will be
  71. self-relative format.
  72. Return Value:
  73. STATUS_SUCCESS if the operation is successful.
  74. STATUS_INVALID_SID - An SID within the security descriptor is not
  75. a valid SID.
  76. STATUS_INVALID_ACL - An ACL within the security descriptor is not
  77. a valid ACL.
  78. STATUS_UNKNOWN_REVISION - The revision level of the security descriptor
  79. is not one known to this revision of the capture routine.
  80. --*/
  81. {
  82. #define SEP_USHORT_OVERFLOW ((ULONG) ((USHORT) -1))
  83. SECURITY_DESCRIPTOR Captured;
  84. SECURITY_DESCRIPTOR_RELATIVE *PIOutputSecurityDescriptor;
  85. PCHAR DescriptorOffset;
  86. ULONG SaclSize;
  87. ULONG NewSaclSize;
  88. ULONG DaclSize;
  89. ULONG NewDaclSize;
  90. ULONG OwnerSubAuthorityCount=0;
  91. ULONG OwnerSize=0;
  92. ULONG NewOwnerSize;
  93. ULONG GroupSubAuthorityCount=0;
  94. ULONG GroupSize=0;
  95. ULONG NewGroupSize;
  96. ULONG Size;
  97. PAGED_CODE();
  98. //
  99. // if the security descriptor is null then there is really nothing to
  100. // capture
  101. //
  102. if (InputSecurityDescriptor == NULL) {
  103. (*OutputSecurityDescriptor) = NULL;
  104. return STATUS_SUCCESS;
  105. }
  106. //
  107. // check if the requestors mode is kernel mode and we are not
  108. // to force a capture
  109. //
  110. if ((RequestorMode == KernelMode) && (ForceCapture == FALSE)) {
  111. //
  112. // Yes it is so we don't need to do any work and can simply
  113. // return a pointer to the input descriptor
  114. //
  115. (*OutputSecurityDescriptor) = InputSecurityDescriptor;
  116. return STATUS_SUCCESS;
  117. }
  118. //
  119. // We need to probe and capture the descriptor.
  120. // To do this we need to probe the main security descriptor record
  121. // first.
  122. //
  123. if (RequestorMode != KernelMode) {
  124. //
  125. // Capture of UserMode SecurityDescriptor.
  126. //
  127. try {
  128. //
  129. // Probe the main record of the input SecurityDescriptor
  130. //
  131. ProbeForReadSmallStructure( InputSecurityDescriptor,
  132. sizeof(SECURITY_DESCRIPTOR_RELATIVE),
  133. sizeof(ULONG) );
  134. //
  135. // Capture the SecurityDescriptor main record.
  136. //
  137. RtlCopyMemory( (&Captured),
  138. InputSecurityDescriptor,
  139. sizeof(SECURITY_DESCRIPTOR_RELATIVE) );
  140. //
  141. // Verify the alignment is correct for absolute case. This is
  142. // only needed when pointer are 64 bits.
  143. //
  144. if (!(Captured.Control & SE_SELF_RELATIVE)) {
  145. if ((ULONG_PTR) InputSecurityDescriptor & (sizeof(ULONG_PTR) - 1)) {
  146. ExRaiseDatatypeMisalignment();
  147. }
  148. }
  149. } except(EXCEPTION_EXECUTE_HANDLER) {
  150. return GetExceptionCode();
  151. }
  152. } else {
  153. //
  154. // Force capture of kernel mode SecurityDescriptor.
  155. //
  156. // Capture the SecurityDescriptor main record.
  157. // It doesn't need probing because requestor mode is kernel.
  158. //
  159. RtlCopyMemory( (&Captured),
  160. InputSecurityDescriptor,
  161. sizeof(SECURITY_DESCRIPTOR_RELATIVE) );
  162. }
  163. //
  164. // Make sure it is a revision we recognize
  165. //
  166. if (Captured.Revision != SECURITY_DESCRIPTOR_REVISION) {
  167. return STATUS_UNKNOWN_REVISION;
  168. }
  169. //
  170. // In case the input security descriptor is self-relative, change the
  171. // captured main record to appear as an absolute form so we can use
  172. // common code for both cases below.
  173. //
  174. // Note that the fields of Captured are left pointing to user
  175. // space addresses. Treat them carefully.
  176. //
  177. try {
  178. Captured.Owner = RtlpOwnerAddrSecurityDescriptor(
  179. (SECURITY_DESCRIPTOR *)InputSecurityDescriptor
  180. );
  181. Captured.Group = RtlpGroupAddrSecurityDescriptor(
  182. (SECURITY_DESCRIPTOR *)InputSecurityDescriptor
  183. );
  184. Captured.Sacl = RtlpSaclAddrSecurityDescriptor (
  185. (SECURITY_DESCRIPTOR *)InputSecurityDescriptor
  186. );
  187. Captured.Dacl = RtlpDaclAddrSecurityDescriptor (
  188. (SECURITY_DESCRIPTOR *)InputSecurityDescriptor
  189. );
  190. Captured.Control &= ~SE_SELF_RELATIVE;
  191. } except(EXCEPTION_EXECUTE_HANDLER) {
  192. return GetExceptionCode();
  193. }
  194. //
  195. // Indicate the size we are going to need to allocate for the captured
  196. // acls
  197. //
  198. SaclSize = 0;
  199. DaclSize = 0;
  200. NewSaclSize = 0;
  201. NewDaclSize = 0;
  202. NewGroupSize = 0;
  203. NewOwnerSize = 0;
  204. //
  205. // Probe (if necessary) and capture each of the components of a
  206. // SECURITY_DESCRIPTOR.
  207. //
  208. //
  209. // System ACL first
  210. //
  211. if ((Captured.Control & SE_SACL_PRESENT) &&
  212. (Captured.Sacl != NULL) ) {
  213. if (RequestorMode != KernelMode) {
  214. try {
  215. SaclSize = ProbeAndReadUshort( &(Captured.Sacl->AclSize) );
  216. ProbeForRead( Captured.Sacl,
  217. SaclSize,
  218. sizeof(ULONG) );
  219. } except(EXCEPTION_EXECUTE_HANDLER) {
  220. return GetExceptionCode();
  221. }
  222. } else {
  223. SaclSize = Captured.Sacl->AclSize;
  224. }
  225. NewSaclSize = (ULONG)LongAlignSize( SaclSize );
  226. //
  227. // Make sure that we do not have an overflow.
  228. //
  229. if (NewSaclSize > SEP_USHORT_OVERFLOW) {
  230. return STATUS_INVALID_ACL;
  231. }
  232. } else {
  233. //
  234. // Force the SACL to null if the bit is off
  235. //
  236. Captured.Sacl = NULL;
  237. }
  238. //
  239. // Discretionary ACL
  240. //
  241. if ((Captured.Control & SE_DACL_PRESENT) &&
  242. (Captured.Dacl != NULL) ) {
  243. if (RequestorMode != KernelMode) {
  244. try {
  245. DaclSize = ProbeAndReadUshort( &(Captured.Dacl->AclSize) );
  246. ProbeForRead( Captured.Dacl,
  247. DaclSize,
  248. sizeof(ULONG) );
  249. } except(EXCEPTION_EXECUTE_HANDLER) {
  250. return GetExceptionCode();
  251. }
  252. } else {
  253. DaclSize = Captured.Dacl->AclSize;
  254. }
  255. NewDaclSize = (ULONG)LongAlignSize( DaclSize );
  256. //
  257. // Make sure that we do not have an overflow.
  258. //
  259. if (NewDaclSize > SEP_USHORT_OVERFLOW) {
  260. return STATUS_INVALID_ACL;
  261. }
  262. } else {
  263. //
  264. // Force the DACL to null if it is not present
  265. //
  266. Captured.Dacl = NULL;
  267. }
  268. //
  269. // Owner SID
  270. //
  271. if (Captured.Owner != NULL) {
  272. if (RequestorMode != KernelMode) {
  273. try {
  274. OwnerSubAuthorityCount =
  275. ProbeAndReadUchar( &(((SID *)(Captured.Owner))->SubAuthorityCount) );
  276. OwnerSize = RtlLengthRequiredSid( OwnerSubAuthorityCount );
  277. ProbeForRead( Captured.Owner,
  278. OwnerSize,
  279. sizeof(ULONG) );
  280. } except(EXCEPTION_EXECUTE_HANDLER) {
  281. return GetExceptionCode();
  282. }
  283. } else {
  284. OwnerSubAuthorityCount = ((SID *)(Captured.Owner))->SubAuthorityCount;
  285. OwnerSize = RtlLengthRequiredSid( OwnerSubAuthorityCount );
  286. }
  287. NewOwnerSize = (ULONG)LongAlignSize( OwnerSize );
  288. }
  289. //
  290. // Group SID
  291. //
  292. if (Captured.Group != NULL) {
  293. if (RequestorMode != KernelMode) {
  294. try {
  295. GroupSubAuthorityCount =
  296. ProbeAndReadUchar( &(((SID *)(Captured.Group))->SubAuthorityCount) );
  297. GroupSize = RtlLengthRequiredSid( GroupSubAuthorityCount );
  298. ProbeForRead( Captured.Group,
  299. GroupSize,
  300. sizeof(ULONG) );
  301. } except(EXCEPTION_EXECUTE_HANDLER) {
  302. return GetExceptionCode();
  303. }
  304. } else {
  305. GroupSubAuthorityCount = ((SID *)(Captured.Group))->SubAuthorityCount;
  306. GroupSize = RtlLengthRequiredSid( GroupSubAuthorityCount );
  307. }
  308. NewGroupSize = (ULONG)LongAlignSize( GroupSize );
  309. }
  310. //
  311. // Now allocate enough pool to hold the descriptor
  312. //
  313. Size = sizeof(SECURITY_DESCRIPTOR_RELATIVE) +
  314. NewSaclSize +
  315. NewDaclSize +
  316. NewOwnerSize +
  317. NewGroupSize;
  318. (PIOutputSecurityDescriptor) = (SECURITY_DESCRIPTOR_RELATIVE *)ExAllocatePoolWithTag( PoolType,
  319. Size,
  320. 'cSeS' );
  321. if ( PIOutputSecurityDescriptor == NULL ) {
  322. return( STATUS_INSUFFICIENT_RESOURCES );
  323. }
  324. (*OutputSecurityDescriptor) = (PSECURITY_DESCRIPTOR)PIOutputSecurityDescriptor;
  325. DescriptorOffset = (PCHAR)(PIOutputSecurityDescriptor);
  326. //
  327. // Copy the main security descriptor record over
  328. //
  329. RtlCopyMemory( DescriptorOffset,
  330. &Captured,
  331. sizeof(SECURITY_DESCRIPTOR_RELATIVE) );
  332. DescriptorOffset += sizeof(SECURITY_DESCRIPTOR_RELATIVE);
  333. //
  334. // Indicate the output descriptor is self-relative
  335. //
  336. PIOutputSecurityDescriptor->Control |= SE_SELF_RELATIVE;
  337. //
  338. // If there is a System Acl, copy it over and set
  339. // the output descriptor's offset to point to the newly captured copy.
  340. //
  341. if ((Captured.Control & SE_SACL_PRESENT) && (Captured.Sacl != NULL)) {
  342. try {
  343. RtlCopyMemory( DescriptorOffset,
  344. Captured.Sacl,
  345. SaclSize );
  346. } except(EXCEPTION_EXECUTE_HANDLER) {
  347. ExFreePool( PIOutputSecurityDescriptor );
  348. return GetExceptionCode();
  349. }
  350. if ((RequestorMode != KernelMode) &&
  351. (!SepCheckAcl( (PACL) DescriptorOffset, SaclSize )) ) {
  352. ExFreePool( PIOutputSecurityDescriptor );
  353. return STATUS_INVALID_ACL;
  354. }
  355. //
  356. // Change pointer to offset
  357. //
  358. PIOutputSecurityDescriptor->Sacl =
  359. RtlPointerToOffset( PIOutputSecurityDescriptor,
  360. DescriptorOffset,
  361. );
  362. ((PACL) DescriptorOffset)->AclSize = (USHORT) NewSaclSize;
  363. DescriptorOffset += NewSaclSize;
  364. } else {
  365. PIOutputSecurityDescriptor->Sacl = 0;
  366. }
  367. //
  368. // If there is a Discretionary Acl, copy it over and set
  369. // the output descriptor's offset to point to the newly captured copy.
  370. //
  371. if ((Captured.Control & SE_DACL_PRESENT) && (Captured.Dacl != NULL)) {
  372. try {
  373. RtlCopyMemory( DescriptorOffset,
  374. Captured.Dacl,
  375. DaclSize );
  376. } except(EXCEPTION_EXECUTE_HANDLER) {
  377. ExFreePool( PIOutputSecurityDescriptor );
  378. return GetExceptionCode();
  379. }
  380. if ((RequestorMode != KernelMode) &&
  381. (!SepCheckAcl( (PACL) DescriptorOffset, DaclSize )) ) {
  382. ExFreePool( PIOutputSecurityDescriptor );
  383. return STATUS_INVALID_ACL;
  384. }
  385. //
  386. // Change pointer to offset
  387. //
  388. PIOutputSecurityDescriptor->Dacl =
  389. RtlPointerToOffset(
  390. PIOutputSecurityDescriptor,
  391. DescriptorOffset
  392. );
  393. ((PACL) DescriptorOffset)->AclSize = (USHORT) NewDaclSize;
  394. DescriptorOffset += NewDaclSize;
  395. } else {
  396. PIOutputSecurityDescriptor->Dacl = 0;
  397. }
  398. //
  399. // If there is an Owner SID, copy it over and set
  400. // the output descriptor's offset to point to the newly captured copy.
  401. //
  402. if (Captured.Owner != NULL) {
  403. try {
  404. RtlCopyMemory( DescriptorOffset,
  405. Captured.Owner,
  406. OwnerSize );
  407. ((SID *) (DescriptorOffset))->SubAuthorityCount = (UCHAR) OwnerSubAuthorityCount;
  408. } except(EXCEPTION_EXECUTE_HANDLER) {
  409. ExFreePool( PIOutputSecurityDescriptor );
  410. return GetExceptionCode();
  411. }
  412. if ((RequestorMode != KernelMode) &&
  413. (!RtlValidSid( (PSID) DescriptorOffset )) ) {
  414. ExFreePool( PIOutputSecurityDescriptor );
  415. return STATUS_INVALID_SID;
  416. }
  417. //
  418. // Change pointer to offset
  419. //
  420. PIOutputSecurityDescriptor->Owner =
  421. RtlPointerToOffset(
  422. PIOutputSecurityDescriptor,
  423. DescriptorOffset
  424. );
  425. DescriptorOffset += NewOwnerSize;
  426. } else {
  427. PIOutputSecurityDescriptor->Owner = 0;
  428. }
  429. //
  430. // If there is a group SID, copy it over and set
  431. // the output descriptor's offset to point to the newly captured copy.
  432. //
  433. if (Captured.Group != NULL) {
  434. try {
  435. RtlCopyMemory( DescriptorOffset,
  436. Captured.Group,
  437. GroupSize );
  438. ((SID *) DescriptorOffset)->SubAuthorityCount = (UCHAR) GroupSubAuthorityCount;
  439. } except(EXCEPTION_EXECUTE_HANDLER) {
  440. ExFreePool( PIOutputSecurityDescriptor );
  441. return GetExceptionCode();
  442. }
  443. if ((RequestorMode != KernelMode) &&
  444. (!RtlValidSid( (PSID) DescriptorOffset )) ) {
  445. ExFreePool( PIOutputSecurityDescriptor );
  446. return STATUS_INVALID_SID;
  447. }
  448. //
  449. // Change pointer to offset
  450. //
  451. PIOutputSecurityDescriptor->Group =
  452. RtlPointerToOffset(
  453. PIOutputSecurityDescriptor,
  454. DescriptorOffset
  455. );
  456. DescriptorOffset += NewGroupSize;
  457. } else {
  458. PIOutputSecurityDescriptor->Group = 0;
  459. }
  460. //
  461. // And return to our caller
  462. //
  463. return STATUS_SUCCESS;
  464. }
  465. VOID
  466. SeReleaseSecurityDescriptor (
  467. IN PSECURITY_DESCRIPTOR CapturedSecurityDescriptor,
  468. IN KPROCESSOR_MODE RequestorMode,
  469. IN BOOLEAN ForceCapture
  470. )
  471. /*++
  472. Routine Description:
  473. This routine releases a previously captured security descriptor.
  474. Only
  475. Arguments:
  476. CapturedSecurityDescriptor - Supplies the security descriptor to release.
  477. RequestorMode - The processor mode specified when the descriptor was
  478. captured.
  479. ForceCapture - The ForceCapture value specified when the descriptor was
  480. captured.
  481. Return Value:
  482. None.
  483. --*/
  484. {
  485. //
  486. // We only have something to deallocate if the requestor was user
  487. // mode or kernel mode requesting ForceCapture.
  488. //
  489. PAGED_CODE();
  490. if ( ((RequestorMode == KernelMode) && (ForceCapture == TRUE)) ||
  491. (RequestorMode == UserMode ) ) {
  492. if ( CapturedSecurityDescriptor ) {
  493. ExFreePool(CapturedSecurityDescriptor);
  494. }
  495. }
  496. return;
  497. }
  498. NTSTATUS
  499. SepCopyProxyData (
  500. OUT PSECURITY_TOKEN_PROXY_DATA * DestProxyData,
  501. IN PSECURITY_TOKEN_PROXY_DATA SourceProxyData
  502. )
  503. /*++
  504. Routine Description:
  505. This routine copies a token proxy data structure from one token to another.
  506. Arguments:
  507. DestProxyData - Receives a pointer to a new proxy data structure.
  508. SourceProxyData - Supplies a pointer to an already existing proxy data structure.
  509. Return Value:
  510. STATUS_INSUFFICIENT_RESOURCES on failure.
  511. --*/
  512. {
  513. PAGED_CODE();
  514. *DestProxyData = ExAllocatePoolWithTag( PagedPool, sizeof( SECURITY_TOKEN_PROXY_DATA ), 'dPoT' );
  515. if (*DestProxyData == NULL) {
  516. return( STATUS_INSUFFICIENT_RESOURCES );
  517. }
  518. (*DestProxyData)->PathInfo.Buffer = ExAllocatePoolWithTag( PagedPool, SourceProxyData->PathInfo.Length, 'dPoT' );
  519. if ((*DestProxyData)->PathInfo.Buffer == NULL) {
  520. ExFreePool( *DestProxyData );
  521. *DestProxyData = NULL;
  522. return( STATUS_INSUFFICIENT_RESOURCES );
  523. }
  524. (*DestProxyData)->Length = SourceProxyData->Length;
  525. (*DestProxyData)->ProxyClass = SourceProxyData->ProxyClass;
  526. (*DestProxyData)->PathInfo.MaximumLength =
  527. (*DestProxyData)->PathInfo.Length = SourceProxyData->PathInfo.Length;
  528. (*DestProxyData)->ContainerMask = SourceProxyData->ContainerMask;
  529. (*DestProxyData)->ObjectMask = SourceProxyData->ObjectMask;
  530. RtlCopyUnicodeString( &(*DestProxyData)->PathInfo, &SourceProxyData->PathInfo );
  531. return( STATUS_SUCCESS );
  532. }
  533. VOID
  534. SepFreeProxyData (
  535. IN PSECURITY_TOKEN_PROXY_DATA ProxyData
  536. )
  537. /*++
  538. Routine Description:
  539. This routine frees a SECURITY_TOKEN_PROXY_DATA structure and all sub structures.
  540. Arguments:
  541. ProxyData - Supplies a pointer to an existing proxy data structure.
  542. Return Value:
  543. None.
  544. --*/
  545. {
  546. PAGED_CODE();
  547. if (ProxyData != NULL) {
  548. if (ProxyData->PathInfo.Buffer != NULL) {
  549. ExFreePool( ProxyData->PathInfo.Buffer );
  550. }
  551. ExFreePool( ProxyData );
  552. }
  553. }
  554. NTSTATUS
  555. SepProbeAndCaptureQosData(
  556. IN PSECURITY_ADVANCED_QUALITY_OF_SERVICE CapturedSecurityQos
  557. )
  558. /*++
  559. Routine Description:
  560. This routine probes and captures the imbedded structures in a
  561. Security Quality of Service structure.
  562. This routine assumes that it is being called under an existing
  563. try-except clause.
  564. Arguments:
  565. CapturedSecurityQos - Points to the captured body of a QOS
  566. structure. The pointers in this structure are presumed
  567. not to be probed or captured at this point.
  568. Return Value:
  569. STATUS_SUCCESS indicates no exceptions were encountered.
  570. Any access violations encountered will be returned.
  571. --*/
  572. {
  573. NTSTATUS Status;
  574. PSECURITY_TOKEN_PROXY_DATA CapturedProxyData;
  575. PSECURITY_TOKEN_AUDIT_DATA CapturedAuditData;
  576. SECURITY_TOKEN_PROXY_DATA StackProxyData;
  577. PAGED_CODE();
  578. CapturedProxyData = CapturedSecurityQos->ProxyData;
  579. CapturedSecurityQos->ProxyData = NULL;
  580. CapturedAuditData = CapturedSecurityQos->AuditData;
  581. CapturedSecurityQos->AuditData = NULL;
  582. if (ARGUMENT_PRESENT( CapturedProxyData )) {
  583. //
  584. // Make sure the body of the proxy data is ok to read.
  585. //
  586. ProbeForReadSmallStructure(
  587. CapturedProxyData,
  588. sizeof(SECURITY_TOKEN_PROXY_DATA),
  589. sizeof(ULONG)
  590. );
  591. StackProxyData = *CapturedProxyData;
  592. if (StackProxyData.Length != sizeof( SECURITY_TOKEN_PROXY_DATA )) {
  593. return( STATUS_INVALID_PARAMETER );
  594. }
  595. //
  596. // Probe the passed pathinfo buffer
  597. //
  598. ProbeForRead(
  599. StackProxyData.PathInfo.Buffer,
  600. StackProxyData.PathInfo.Length,
  601. sizeof( UCHAR )
  602. );
  603. Status = SepCopyProxyData( &CapturedSecurityQos->ProxyData, &StackProxyData );
  604. if (!NT_SUCCESS(Status)) {
  605. if (CapturedSecurityQos->ProxyData != NULL) {
  606. SepFreeProxyData( CapturedSecurityQos->ProxyData );
  607. CapturedSecurityQos->ProxyData = NULL;
  608. }
  609. return( Status );
  610. }
  611. }
  612. if (ARGUMENT_PRESENT( CapturedAuditData )) {
  613. PSECURITY_TOKEN_AUDIT_DATA LocalAuditData;
  614. //
  615. // Probe the audit data structure and make sure it looks ok
  616. //
  617. ProbeForReadSmallStructure(
  618. CapturedAuditData,
  619. sizeof( SECURITY_TOKEN_AUDIT_DATA ),
  620. sizeof( ULONG )
  621. );
  622. LocalAuditData = ExAllocatePool( PagedPool, sizeof( SECURITY_TOKEN_AUDIT_DATA ));
  623. if (LocalAuditData == NULL) {
  624. //
  625. // Cleanup any proxy data we may have allocated.
  626. //
  627. SepFreeProxyData( CapturedSecurityQos->ProxyData );
  628. CapturedSecurityQos->ProxyData = NULL;
  629. return( STATUS_INSUFFICIENT_RESOURCES );
  630. }
  631. //
  632. // Copy the data to the local buffer. Note: we do this in this
  633. // order so that if the final assignment fails the caller will
  634. // still be able to free the allocated pool.
  635. //
  636. CapturedSecurityQos->AuditData = LocalAuditData;
  637. *CapturedSecurityQos->AuditData = *CapturedAuditData;
  638. if ( LocalAuditData->Length != sizeof( SECURITY_TOKEN_AUDIT_DATA ) ) {
  639. SepFreeProxyData( CapturedSecurityQos->ProxyData );
  640. CapturedSecurityQos->ProxyData = NULL;
  641. ExFreePool(CapturedSecurityQos->AuditData);
  642. CapturedSecurityQos->AuditData = NULL;
  643. return( STATUS_INVALID_PARAMETER );
  644. }
  645. }
  646. return( STATUS_SUCCESS );
  647. }
  648. VOID
  649. SeFreeCapturedSecurityQos(
  650. IN PVOID SecurityQos
  651. )
  652. /*++
  653. Routine Description:
  654. This routine frees the data associated with a captured SecurityQos
  655. structure. It does not free the body of the structure, just whatever
  656. its internal fields point to.
  657. Arguments:
  658. SecurityQos - Points to a captured security QOS structure.
  659. Return Value:
  660. None.
  661. --*/
  662. {
  663. PSECURITY_ADVANCED_QUALITY_OF_SERVICE IAdvancedSecurityQos;
  664. PAGED_CODE();
  665. IAdvancedSecurityQos = (PSECURITY_ADVANCED_QUALITY_OF_SERVICE)SecurityQos;
  666. if (IAdvancedSecurityQos->Length == sizeof( SECURITY_ADVANCED_QUALITY_OF_SERVICE )) {
  667. if (IAdvancedSecurityQos->AuditData != NULL) {
  668. ExFreePool( IAdvancedSecurityQos->AuditData );
  669. }
  670. SepFreeProxyData( IAdvancedSecurityQos->ProxyData );
  671. }
  672. return;
  673. }
  674. NTSTATUS
  675. SeCaptureSecurityQos (
  676. IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
  677. IN KPROCESSOR_MODE RequestorMode,
  678. OUT PBOOLEAN SecurityQosPresent,
  679. OUT PSECURITY_ADVANCED_QUALITY_OF_SERVICE CapturedSecurityQos
  680. )
  681. /*++
  682. Routine Description:
  683. This routine probes and captures a copy of any security quality
  684. of service parameters that might have been provided via the
  685. ObjectAttributes argument.
  686. Arguments:
  687. ObjectAttributes - The object attributes from which the QOS
  688. information is to be retrieved.
  689. RequestorMode - Indicates the processor mode by which the access
  690. is being requested.
  691. SecurityQosPresent - Receives a boolean value indicating whether
  692. or not the optional security QOS information was available
  693. and copied.
  694. CapturedSecurityQos - Receives the security QOS information if available.
  695. Return Value:
  696. STATUS_SUCCESS indicates no exceptions were encountered.
  697. Any access violations encountered will be returned.
  698. --*/
  699. {
  700. PSECURITY_QUALITY_OF_SERVICE LocalSecurityQos;
  701. ULONG LocalQosLength;
  702. PSECURITY_ADVANCED_QUALITY_OF_SERVICE LocalAdvancedSecurityQos;
  703. NTSTATUS Status;
  704. BOOLEAN CapturedQos;
  705. PAGED_CODE();
  706. CapturedQos = FALSE;
  707. //
  708. // Set default return
  709. //
  710. (*SecurityQosPresent) = FALSE;
  711. //
  712. // check if the requestors mode is kernel mode
  713. //
  714. if (RequestorMode != KernelMode) {
  715. try {
  716. if ( ARGUMENT_PRESENT(ObjectAttributes) ) {
  717. ProbeForReadSmallStructure( ObjectAttributes,
  718. sizeof(OBJECT_ATTRIBUTES),
  719. sizeof(ULONG)
  720. );
  721. LocalSecurityQos =
  722. (PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService;
  723. if ( ARGUMENT_PRESENT(LocalSecurityQos) ) {
  724. ProbeForReadSmallStructure(
  725. LocalSecurityQos,
  726. sizeof(SECURITY_QUALITY_OF_SERVICE),
  727. sizeof(ULONG)
  728. );
  729. LocalQosLength = LocalSecurityQos->Length;
  730. //
  731. // Check the length and see if this is a QOS or Advanced QOS
  732. // structure.
  733. //
  734. if (LocalQosLength == sizeof( SECURITY_QUALITY_OF_SERVICE )) {
  735. //
  736. // It's a downlevel QOS, copy what's there and leave.
  737. //
  738. (*SecurityQosPresent) = TRUE;
  739. RtlCopyMemory( CapturedSecurityQos, LocalSecurityQos, sizeof( SECURITY_QUALITY_OF_SERVICE ));
  740. CapturedSecurityQos->ProxyData = NULL;
  741. CapturedSecurityQos->AuditData = NULL;
  742. CapturedSecurityQos->Length = LocalQosLength;
  743. } else {
  744. if (LocalQosLength == sizeof( SECURITY_ADVANCED_QUALITY_OF_SERVICE )) {
  745. LocalAdvancedSecurityQos =
  746. (PSECURITY_ADVANCED_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService;
  747. ProbeForReadSmallStructure(
  748. LocalAdvancedSecurityQos,
  749. sizeof(SECURITY_ADVANCED_QUALITY_OF_SERVICE),
  750. sizeof(ULONG)
  751. );
  752. (*SecurityQosPresent) = TRUE;
  753. *CapturedSecurityQos = *LocalAdvancedSecurityQos;
  754. CapturedSecurityQos->Length = LocalQosLength;
  755. //
  756. // Capture the proxy and audit data, if necessary.
  757. //
  758. if ( ARGUMENT_PRESENT(CapturedSecurityQos->ProxyData) || ARGUMENT_PRESENT( CapturedSecurityQos->AuditData ) ) {
  759. CapturedQos = TRUE;
  760. Status = SepProbeAndCaptureQosData( CapturedSecurityQos );
  761. if (!NT_SUCCESS( Status )) {
  762. return( Status );
  763. }
  764. }
  765. } else {
  766. return( STATUS_INVALID_PARAMETER );
  767. }
  768. }
  769. } // end_if
  770. } // end_if
  771. } except(EXCEPTION_EXECUTE_HANDLER) {
  772. //
  773. // If we captured any proxy data, we need to free it now.
  774. //
  775. if ( CapturedQos ) {
  776. SepFreeProxyData( CapturedSecurityQos->ProxyData );
  777. if ( CapturedSecurityQos->AuditData != NULL ) {
  778. ExFreePool( CapturedSecurityQos->AuditData );
  779. }
  780. }
  781. return GetExceptionCode();
  782. } // end_try
  783. } else {
  784. if ( ARGUMENT_PRESENT(ObjectAttributes) ) {
  785. if ( ARGUMENT_PRESENT(ObjectAttributes->SecurityQualityOfService) ) {
  786. (*SecurityQosPresent) = TRUE;
  787. if (((PSECURITY_QUALITY_OF_SERVICE)(ObjectAttributes->SecurityQualityOfService))->Length == sizeof( SECURITY_QUALITY_OF_SERVICE )) {
  788. RtlCopyMemory( CapturedSecurityQos, ObjectAttributes->SecurityQualityOfService, sizeof( SECURITY_QUALITY_OF_SERVICE ));
  789. CapturedSecurityQos->ProxyData = NULL;
  790. CapturedSecurityQos->AuditData = NULL;
  791. } else {
  792. (*CapturedSecurityQos) =
  793. (*(SECURITY_ADVANCED_QUALITY_OF_SERVICE *)(ObjectAttributes->SecurityQualityOfService));
  794. }
  795. } // end_if
  796. } // end_if
  797. } // end_if
  798. return STATUS_SUCCESS;
  799. }
  800. NTSTATUS
  801. SeCaptureSid (
  802. IN PSID InputSid,
  803. IN KPROCESSOR_MODE RequestorMode,
  804. IN PVOID CaptureBuffer OPTIONAL,
  805. IN ULONG CaptureBufferLength,
  806. IN POOL_TYPE PoolType,
  807. IN BOOLEAN ForceCapture,
  808. OUT PSID *CapturedSid
  809. )
  810. /*++
  811. Routine Description:
  812. This routine probes and captures a copy of the specified SID.
  813. The SID is either captured into a provided buffer, or pool
  814. allocated to receive the SID.
  815. if the requestor mode is not kernel mode then
  816. probe and capture the input SID
  817. if the requstor mode is kernel mode then
  818. if force capture is true then
  819. do not probe the input SID, but do capture it
  820. else
  821. return address of original, but don't copy
  822. Arguments:
  823. InputSid - Supplies the SID to capture. This parameter is assumed
  824. to have been provided by the mode specified in RequestorMode.
  825. RequestorMode - Specifies the caller's access mode.
  826. CaptureBuffer - Specifies a buffer into which the SID is to be
  827. captured. If this parameter is not provided, pool will be allocated
  828. to hold the captured data.
  829. CaptureBufferLength - Indicates the length, in bytes, of the capture
  830. buffer.
  831. PoolType - Specifies which pool type to allocate to capture the
  832. SID into. This parameter is ignored if CaptureBuffer is provided.
  833. ForceCapture - Specifies whether the SID should be captured even if
  834. requestor mode is kernel.
  835. CapturedSid - Supplies the address of a pointer to an SID.
  836. The pointer will be set to point to the captured (or uncaptured) SID.
  837. AlignedSidSize - Supplies the address of a ULONG to receive the length
  838. of the SID rounded up to the next longword boundary.
  839. Return Value:
  840. STATUS_SUCCESS indicates the capture was successful.
  841. STATUS_BUFFER_TOO_SMALL - indicates the buffer provided to capture the SID
  842. into wasn't large enough to hold the SID.
  843. Any access violations encountered will be returned.
  844. --*/
  845. {
  846. ULONG GetSidSubAuthorityCount;
  847. ULONG SidSize;
  848. PAGED_CODE();
  849. //
  850. // check if the requestors mode is kernel mode and we are not
  851. // to force a capture.
  852. //
  853. if ((RequestorMode == KernelMode) && (ForceCapture == FALSE)) {
  854. //
  855. // We don't need to do any work and can simply
  856. // return a pointer to the input SID
  857. //
  858. (*CapturedSid) = InputSid;
  859. return STATUS_SUCCESS;
  860. }
  861. //
  862. // Get the length needed to hold the SID
  863. //
  864. if (RequestorMode != KernelMode) {
  865. try {
  866. GetSidSubAuthorityCount =
  867. ProbeAndReadUchar( &(((SID *)(InputSid))->SubAuthorityCount) );
  868. SidSize = RtlLengthRequiredSid( GetSidSubAuthorityCount );
  869. ProbeForRead( InputSid,
  870. SidSize,
  871. sizeof(ULONG) );
  872. } except(EXCEPTION_EXECUTE_HANDLER) {
  873. return GetExceptionCode();
  874. }
  875. } else {
  876. GetSidSubAuthorityCount = ((SID *)(InputSid))->SubAuthorityCount;
  877. SidSize = RtlLengthRequiredSid( GetSidSubAuthorityCount );
  878. }
  879. //
  880. // If a buffer was provided, compare lengths.
  881. // Otherwise, allocate a buffer.
  882. //
  883. if (ARGUMENT_PRESENT(CaptureBuffer)) {
  884. if (SidSize > CaptureBufferLength) {
  885. return STATUS_BUFFER_TOO_SMALL;
  886. } else {
  887. (*CapturedSid) = CaptureBuffer;
  888. }
  889. } else {
  890. (*CapturedSid) = (PSID)ExAllocatePoolWithTag(PoolType, SidSize, 'iSeS');
  891. if ( *CapturedSid == NULL ) {
  892. return( STATUS_INSUFFICIENT_RESOURCES );
  893. }
  894. }
  895. //
  896. // Now copy the SID and validate it
  897. //
  898. try {
  899. RtlCopyMemory( (*CapturedSid), InputSid, SidSize );
  900. ((SID *)(*CapturedSid))->SubAuthorityCount = (UCHAR) GetSidSubAuthorityCount;
  901. } except(EXCEPTION_EXECUTE_HANDLER) {
  902. if (!ARGUMENT_PRESENT(CaptureBuffer)) {
  903. ExFreePool( (*CapturedSid) );
  904. *CapturedSid = NULL;
  905. }
  906. return GetExceptionCode();
  907. }
  908. if ((!RtlValidSid( (*CapturedSid) )) ) {
  909. if (!ARGUMENT_PRESENT(CaptureBuffer)) {
  910. ExFreePool( (*CapturedSid) );
  911. *CapturedSid = NULL;
  912. }
  913. return STATUS_INVALID_SID;
  914. }
  915. return STATUS_SUCCESS;
  916. }
  917. VOID
  918. SeReleaseSid (
  919. IN PSID CapturedSid,
  920. IN KPROCESSOR_MODE RequestorMode,
  921. IN BOOLEAN ForceCapture
  922. )
  923. /*++
  924. Routine Description:
  925. This routine releases a previously captured SID.
  926. This routine should NOT be called if the SID was captured into a
  927. provided CaptureBuffer (see SeCaptureSid).
  928. Arguments:
  929. CapturedSid - Supplies the SID to release.
  930. RequestorMode - The processor mode specified when the SID was captured.
  931. ForceCapture - The ForceCapture value specified when the SID was
  932. captured.
  933. Return Value:
  934. None.
  935. --*/
  936. {
  937. //
  938. // We only have something to deallocate if the requestor was user
  939. // mode or kernel mode requesting ForceCapture.
  940. //
  941. PAGED_CODE();
  942. if ( ((RequestorMode == KernelMode) && (ForceCapture == TRUE)) ||
  943. (RequestorMode == UserMode ) ) {
  944. ExFreePool(CapturedSid);
  945. }
  946. return;
  947. }
  948. NTSTATUS
  949. SeCaptureAcl (
  950. IN PACL InputAcl,
  951. IN KPROCESSOR_MODE RequestorMode,
  952. IN PVOID CaptureBuffer OPTIONAL,
  953. IN ULONG CaptureBufferLength,
  954. IN POOL_TYPE PoolType,
  955. IN BOOLEAN ForceCapture,
  956. OUT PACL *CapturedAcl,
  957. OUT PULONG AlignedAclSize
  958. )
  959. /*++
  960. Routine Description:
  961. This routine probes and captures a copy of the specified ACL.
  962. The ACL is either captured into a provided buffer, or pool
  963. allocated to receive the ACL.
  964. Any ACL captured will have its structure validated.
  965. if the requestor mode is not kernel mode then
  966. probe and capture the input ACL
  967. if the requstor mode is kernel mode then
  968. if force capture is true then
  969. do not probe the input ACL, but do capture it
  970. else
  971. return address of original, but don't copy
  972. Arguments:
  973. InputAcl - Supplies the ACL to capture. This parameter is assumed
  974. to have been provided by the mode specified in RequestorMode.
  975. RequestorMode - Specifies the caller's access mode.
  976. CaptureBuffer - Specifies a buffer into which the ACL is to be
  977. captured. If this parameter is not provided, pool will be allocated
  978. to hold the captured data.
  979. CaptureBufferLength - Indicates the length, in bytes, of the capture
  980. buffer.
  981. PoolType - Specifies which pool type to allocate to capture the
  982. ACL into. This parameter is ignored if CaptureBuffer is provided.
  983. ForceCapture - Specifies whether the ACL should be captured even if
  984. requestor mode is kernel.
  985. CapturedAcl - Supplies the address of a pointer to an ACL.
  986. The pointer will be set to point to the captured (or uncaptured) ACL.
  987. AlignedAclSize - Supplies the address of a ULONG to receive the length
  988. of the ACL rounded up to the next longword boundary.
  989. Return Value:
  990. STATUS_SUCCESS indicates the capture was successful.
  991. STATUS_BUFFER_TOO_SMALL - indicates the buffer provided to capture the ACL
  992. into wasn't large enough to hold the ACL.
  993. Any access violations encountered will be returned.
  994. --*/
  995. {
  996. ULONG AclSize;
  997. PAGED_CODE();
  998. //
  999. // check if the requestors mode is kernel mode and we are not
  1000. // to force a capture.
  1001. //
  1002. if ((RequestorMode == KernelMode) && (ForceCapture == FALSE)) {
  1003. //
  1004. // We don't need to do any work and can simply
  1005. // return a pointer to the input ACL
  1006. //
  1007. (*CapturedAcl) = InputAcl;
  1008. return STATUS_SUCCESS;
  1009. }
  1010. //
  1011. // Get the length needed to hold the ACL
  1012. //
  1013. if (RequestorMode != KernelMode) {
  1014. try {
  1015. AclSize = ProbeAndReadUshort( &(InputAcl->AclSize) );
  1016. ProbeForRead( InputAcl,
  1017. AclSize,
  1018. sizeof(ULONG) );
  1019. } except(EXCEPTION_EXECUTE_HANDLER) {
  1020. return GetExceptionCode();
  1021. }
  1022. } else {
  1023. AclSize = InputAcl->AclSize;
  1024. }
  1025. //
  1026. // If the passed pointer is non-null, it has better at least
  1027. // point to a well formed ACL
  1028. //
  1029. if (AclSize < sizeof(ACL)) {
  1030. return( STATUS_INVALID_ACL );
  1031. }
  1032. (*AlignedAclSize) = (ULONG)LongAlignSize( AclSize );
  1033. //
  1034. // If a buffer was provided, compare lengths.
  1035. // Otherwise, allocate a buffer.
  1036. //
  1037. if (ARGUMENT_PRESENT(CaptureBuffer)) {
  1038. if (AclSize > CaptureBufferLength) {
  1039. return STATUS_BUFFER_TOO_SMALL;
  1040. } else {
  1041. (*CapturedAcl) = CaptureBuffer;
  1042. }
  1043. } else {
  1044. (*CapturedAcl) = (PACL)ExAllocatePoolWithTag(PoolType, AclSize, 'cAeS');
  1045. if ( *CapturedAcl == NULL ) {
  1046. return( STATUS_INSUFFICIENT_RESOURCES );
  1047. }
  1048. }
  1049. //
  1050. // Now copy the ACL and validate it
  1051. //
  1052. try {
  1053. RtlCopyMemory( (*CapturedAcl), InputAcl, AclSize );
  1054. } except(EXCEPTION_EXECUTE_HANDLER) {
  1055. if (!ARGUMENT_PRESENT(CaptureBuffer)) {
  1056. ExFreePool( (*CapturedAcl) );
  1057. }
  1058. *CapturedAcl = NULL;
  1059. return GetExceptionCode();
  1060. }
  1061. if ( (!SepCheckAcl( (*CapturedAcl), AclSize )) ) {
  1062. if (!ARGUMENT_PRESENT(CaptureBuffer)) {
  1063. ExFreePool( (*CapturedAcl) );
  1064. }
  1065. *CapturedAcl = NULL;
  1066. return STATUS_INVALID_ACL;
  1067. }
  1068. return STATUS_SUCCESS;
  1069. }
  1070. VOID
  1071. SeReleaseAcl (
  1072. IN PACL CapturedAcl,
  1073. IN KPROCESSOR_MODE RequestorMode,
  1074. IN BOOLEAN ForceCapture
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This routine releases a previously captured ACL.
  1079. This routine should NOT be called if the ACL was captured into a
  1080. provided CaptureBuffer (see SeCaptureAcl).
  1081. Arguments:
  1082. CapturedAcl - Supplies the ACL to release.
  1083. RequestorMode - The processor mode specified when the ACL was captured.
  1084. ForceCapture - The ForceCapture value specified when the ACL was
  1085. captured.
  1086. Return Value:
  1087. None.
  1088. --*/
  1089. {
  1090. //
  1091. // We only have something to deallocate if the requestor was user
  1092. // mode or kernel mode requesting ForceCapture.
  1093. //
  1094. PAGED_CODE();
  1095. if ( ((RequestorMode == KernelMode) && (ForceCapture == TRUE)) ||
  1096. (RequestorMode == UserMode ) ) {
  1097. ExFreePool(CapturedAcl);
  1098. }
  1099. }
  1100. NTSTATUS
  1101. SeCaptureLuidAndAttributesArray (
  1102. IN PLUID_AND_ATTRIBUTES InputArray,
  1103. IN ULONG ArrayCount,
  1104. IN KPROCESSOR_MODE RequestorMode,
  1105. IN PVOID CaptureBuffer OPTIONAL,
  1106. IN ULONG CaptureBufferLength,
  1107. IN POOL_TYPE PoolType,
  1108. IN BOOLEAN ForceCapture,
  1109. OUT PLUID_AND_ATTRIBUTES *CapturedArray,
  1110. OUT PULONG AlignedArraySize
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. This routine probes and captures a copy of the specified
  1115. LUID_AND_ATTRIBUTES array.
  1116. The array is either captured into a provided buffer, or pool
  1117. allocated to receive the array.
  1118. if the requestor mode is not kernel mode then
  1119. probe and capture the input array
  1120. if the requstor mode is kernel mode then
  1121. if force capture is true then
  1122. do not probe the input array, but do capture it
  1123. else
  1124. return address of original, but don't copy
  1125. Arguments:
  1126. InputArray - Supplies the array to capture. This parameter is assumed
  1127. to have been provided by the mode specified in RequestorMode.
  1128. ArrayCount - Indicates the number of elements in the array to capture.
  1129. RequestorMode - Specifies the caller's access mode.
  1130. CaptureBuffer - Specifies a buffer into which the array is to be
  1131. captured. If this parameter is not provided, pool will be allocated
  1132. to hold the captured data.
  1133. CaptureBufferLength - Indicates the length, in bytes, of the capture
  1134. buffer.
  1135. PoolType - Specifies which pool type to allocate to capture the
  1136. array into. This parameter is ignored if CaptureBuffer is provided.
  1137. ForceCapture - Specifies whether the array should be captured even if
  1138. requestor mode is kernel.
  1139. CapturedArray - Supplies the address of a pointer to an array.
  1140. The pointer will be set to point to the captured (or uncaptured) array.
  1141. AlignedArraySize - Supplies the address of a ULONG to receive the length
  1142. of the array rounded up to the next longword boundary.
  1143. Return Value:
  1144. STATUS_SUCCESS indicates the capture was successful.
  1145. STATUS_BUFFER_TOO_SMALL - indicates the buffer provided to capture the array
  1146. into wasn't large enough to hold the array.
  1147. Any access violations encountered will be returned.
  1148. --*/
  1149. {
  1150. ULONG ArraySize;
  1151. PAGED_CODE();
  1152. //
  1153. // Make sure the array isn't empty
  1154. //
  1155. if (ArrayCount == 0) {
  1156. (*CapturedArray) = NULL;
  1157. (*AlignedArraySize) = 0;
  1158. return STATUS_SUCCESS;
  1159. }
  1160. //
  1161. // If there are too many LUIDs, return failure
  1162. //
  1163. if (ArrayCount > SEP_MAX_PRIVILEGE_COUNT) {
  1164. return(STATUS_INVALID_PARAMETER);
  1165. }
  1166. //
  1167. // check if the requestors mode is kernel mode and we are not
  1168. // to force a capture.
  1169. //
  1170. if ((RequestorMode == KernelMode) && (ForceCapture == FALSE)) {
  1171. //
  1172. // We don't need to do any work and can simply
  1173. // return a pointer to the input array
  1174. //
  1175. (*CapturedArray) = InputArray;
  1176. return STATUS_SUCCESS;
  1177. }
  1178. //
  1179. // Get the length needed to hold the array
  1180. //
  1181. ArraySize = ArrayCount * (ULONG)sizeof(LUID_AND_ATTRIBUTES);
  1182. (*AlignedArraySize) = (ULONG)LongAlignSize( ArraySize );
  1183. if (RequestorMode != KernelMode) {
  1184. try {
  1185. ProbeForRead( InputArray,
  1186. ArraySize,
  1187. sizeof(ULONG) );
  1188. } except(EXCEPTION_EXECUTE_HANDLER) {
  1189. return GetExceptionCode();
  1190. }
  1191. }
  1192. //
  1193. // If a buffer was provided, compare lengths.
  1194. // Otherwise, allocate a buffer.
  1195. //
  1196. if (ARGUMENT_PRESENT(CaptureBuffer)) {
  1197. if (ArraySize > CaptureBufferLength) {
  1198. return STATUS_BUFFER_TOO_SMALL;
  1199. } else {
  1200. (*CapturedArray) = CaptureBuffer;
  1201. }
  1202. } else {
  1203. (*CapturedArray) =
  1204. (PLUID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PoolType, ArraySize, 'uLeS');
  1205. if ( *CapturedArray == NULL ) {
  1206. return( STATUS_INSUFFICIENT_RESOURCES );
  1207. }
  1208. }
  1209. //
  1210. // Now copy the array
  1211. //
  1212. try {
  1213. RtlCopyMemory( (*CapturedArray), InputArray, ArraySize );
  1214. } except(EXCEPTION_EXECUTE_HANDLER) {
  1215. if (!ARGUMENT_PRESENT(CaptureBuffer)) {
  1216. ExFreePool( (*CapturedArray) );
  1217. }
  1218. return GetExceptionCode();
  1219. }
  1220. return STATUS_SUCCESS;
  1221. }
  1222. VOID
  1223. SeReleaseLuidAndAttributesArray (
  1224. IN PLUID_AND_ATTRIBUTES CapturedArray,
  1225. IN KPROCESSOR_MODE RequestorMode,
  1226. IN BOOLEAN ForceCapture
  1227. )
  1228. /*++
  1229. Routine Description:
  1230. This routine releases a previously captured array of LUID_AND_ATTRIBUTES.
  1231. This routine should NOT be called if the array was captured into a
  1232. provided CaptureBuffer (see SeCaptureLuidAndAttributesArray).
  1233. Arguments:
  1234. CapturedArray - Supplies the array to release.
  1235. RequestorMode - The processor mode specified when the array was captured.
  1236. ForceCapture - The ForceCapture value specified when the array was
  1237. captured.
  1238. Return Value:
  1239. None.
  1240. --*/
  1241. {
  1242. //
  1243. // We only have something to deallocate if the requestor was user
  1244. // mode or kernel mode requesting ForceCapture.
  1245. //
  1246. PAGED_CODE();
  1247. if ( ((RequestorMode == KernelMode) && (ForceCapture == TRUE)) ||
  1248. (RequestorMode == UserMode )) {
  1249. //
  1250. // the capture routine returns success with a null pointer for zero elements.
  1251. //
  1252. if (CapturedArray != NULL)
  1253. ExFreePool(CapturedArray);
  1254. }
  1255. return;
  1256. }
  1257. NTSTATUS
  1258. SeCaptureSidAndAttributesArray (
  1259. IN PSID_AND_ATTRIBUTES InputArray,
  1260. IN ULONG ArrayCount,
  1261. IN KPROCESSOR_MODE RequestorMode,
  1262. IN PVOID CaptureBuffer OPTIONAL,
  1263. IN ULONG CaptureBufferLength,
  1264. IN POOL_TYPE PoolType,
  1265. IN BOOLEAN ForceCapture,
  1266. OUT PSID_AND_ATTRIBUTES *CapturedArray,
  1267. OUT PULONG AlignedArraySize
  1268. )
  1269. /*++
  1270. Routine Description:
  1271. This routine probes and captures a copy of the specified
  1272. SID_AND_ATTRIBUTES array, along with the SID values pointed
  1273. to.
  1274. The array is either captured into a provided buffer, or pool
  1275. allocated to receive the array.
  1276. The format of the captured information is an array of SID_AND_ATTRIBUTES
  1277. data structures followed by the SID values. THIS MAY NOT BE THE CASE
  1278. FOR KERNEL MODE UNLESS A FORCE CAPTURE IS SPECIFIED.
  1279. if the requestor mode is not kernel mode then
  1280. probe and capture the input array
  1281. if the requstor mode is kernel mode then
  1282. if force capture is true then
  1283. do not probe the input array, but do capture it
  1284. else
  1285. return address of original, but don't copy
  1286. Arguments:
  1287. InputArray - Supplies the array to capture. This parameter is assumed
  1288. to have been provided by the mode specified in RequestorMode.
  1289. ArrayCount - Indicates the number of elements in the array to capture.
  1290. RequestorMode - Specifies the caller's access mode.
  1291. CaptureBuffer - Specifies a buffer into which the array is to be
  1292. captured. If this parameter is not provided, pool will be allocated
  1293. to hold the captured data.
  1294. CaptureBufferLength - Indicates the length, in bytes, of the capture
  1295. buffer.
  1296. PoolType - Specifies which pool type to allocate to capture the
  1297. array into. This parameter is ignored if CaptureBuffer is provided.
  1298. ForceCapture - Specifies whether the array should be captured even if
  1299. requestor mode is kernel.
  1300. CapturedArray - Supplies the address of a pointer to an array.
  1301. The pointer will be set to point to the captured (or uncaptured) array.
  1302. AlignedArraySize - Supplies the address of a ULONG to receive the length
  1303. of the array rounded up to the next longword boundary.
  1304. Return Value:
  1305. STATUS_SUCCESS indicates the capture was successful.
  1306. STATUS_BUFFER_TOO_SMALL - indicates the buffer provided to capture the array
  1307. into wasn't large enough to hold the array.
  1308. Any access violations encountered will be returned.
  1309. --*/
  1310. {
  1311. typedef struct _TEMP_ARRAY_ELEMENT {
  1312. PISID Sid;
  1313. ULONG SidLength;
  1314. } TEMP_ARRAY_ELEMENT;
  1315. TEMP_ARRAY_ELEMENT *TempArray = NULL;
  1316. NTSTATUS CompletionStatus = STATUS_SUCCESS;
  1317. ULONG ArraySize;
  1318. ULONG AlignedLengthRequired;
  1319. ULONG NextIndex;
  1320. PSID_AND_ATTRIBUTES NextElement;
  1321. PVOID NextBufferLocation;
  1322. ULONG GetSidSubAuthorityCount;
  1323. ULONG SidSize;
  1324. ULONG AlignedSidSize;
  1325. PAGED_CODE();
  1326. //
  1327. // Make sure the array isn't empty
  1328. //
  1329. if (ArrayCount == 0) {
  1330. (*CapturedArray) = NULL;
  1331. (*AlignedArraySize) = 0;
  1332. return STATUS_SUCCESS;
  1333. }
  1334. //
  1335. // Check there aren't too many SIDs
  1336. //
  1337. if (ArrayCount > SEP_MAX_GROUP_COUNT) {
  1338. return(STATUS_INVALID_PARAMETER);
  1339. }
  1340. //
  1341. // check if the requestor's mode is kernel mode and we are not
  1342. // to force a capture.
  1343. //
  1344. if ((RequestorMode == KernelMode) && (ForceCapture == FALSE)) {
  1345. //
  1346. // We don't need to do any work and can simply
  1347. // return a pointer to the input array
  1348. //
  1349. (*CapturedArray) = InputArray;
  1350. return STATUS_SUCCESS;
  1351. }
  1352. //
  1353. // ---------- For RequestorMode == UserMode ----------------------
  1354. //
  1355. // the algorithm for capturing an SID_AND_ATTRIBUTES array is somewhat
  1356. // convoluted to avoid problems that could occur if the data is
  1357. // being changed while being captured.
  1358. //
  1359. // The algorithm uses two loops.
  1360. //
  1361. // Allocate a temporary buffer to house the fixed length data.
  1362. //
  1363. // 1st loop:
  1364. // For each SID:
  1365. // Capture the Pointers to the SID and the length of the SID.
  1366. //
  1367. // Allocate a buffer large enough to hold all of the data.
  1368. //
  1369. // 2nd loop:
  1370. // For each SID:
  1371. // Capture the Attributes.
  1372. // Capture the SID.
  1373. // Set the pointer to the SID.
  1374. //
  1375. // Deallocate temporary buffer.
  1376. //
  1377. // ------------ For RequestorMode == KernelMode --------------------
  1378. //
  1379. // There is no need to capture the length and address of the SIDs
  1380. // in the first loop (since the kernel can be trusted not to change
  1381. // them while they are being copied.) So for kernel mode, the first
  1382. // loop just adds up the length needed. Kernel mode, thus, avoids
  1383. // having to allocate a temporary buffer.
  1384. //
  1385. //
  1386. // Get the length needed to hold the array elements.
  1387. //
  1388. ArraySize = ArrayCount * (ULONG)sizeof(SID_AND_ATTRIBUTES);
  1389. AlignedLengthRequired = (ULONG)LongAlignSize( ArraySize );
  1390. if (RequestorMode != KernelMode) {
  1391. //
  1392. // Allocate a temporary array to capture the array elements into
  1393. //
  1394. TempArray =
  1395. (TEMP_ARRAY_ELEMENT *)ExAllocatePoolWithTag(PoolType, AlignedLengthRequired, 'aTeS');
  1396. if ( TempArray == NULL ) {
  1397. return( STATUS_INSUFFICIENT_RESOURCES );
  1398. }
  1399. try {
  1400. //
  1401. // Make sure we can read each SID_AND_ATTRIBUTE
  1402. //
  1403. ProbeForRead( InputArray,
  1404. ArraySize,
  1405. sizeof(ULONG) );
  1406. //
  1407. // Probe and capture the length and address of each SID
  1408. //
  1409. NextIndex = 0;
  1410. while (NextIndex < ArrayCount) {
  1411. PSID TempSid;
  1412. TempSid = InputArray[NextIndex].Sid;
  1413. GetSidSubAuthorityCount =
  1414. ProbeAndReadUchar( &((PISID)TempSid)->SubAuthorityCount);
  1415. if (GetSidSubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  1416. CompletionStatus = STATUS_INVALID_SID;
  1417. break;
  1418. }
  1419. TempArray[NextIndex].Sid = ((PISID)(TempSid));
  1420. TempArray[NextIndex].SidLength =
  1421. RtlLengthRequiredSid( GetSidSubAuthorityCount );
  1422. ProbeForRead( TempArray[NextIndex].Sid,
  1423. TempArray[NextIndex].SidLength,
  1424. sizeof(ULONG) );
  1425. AlignedLengthRequired +=
  1426. (ULONG)LongAlignSize( TempArray[NextIndex].SidLength );
  1427. NextIndex += 1;
  1428. } //end while
  1429. } except(EXCEPTION_EXECUTE_HANDLER) {
  1430. ExFreePool( TempArray );
  1431. return GetExceptionCode();
  1432. }
  1433. if (!NT_SUCCESS(CompletionStatus)) {
  1434. ExFreePool( TempArray );
  1435. return(CompletionStatus);
  1436. }
  1437. } else {
  1438. //
  1439. // No need to capture anything.
  1440. // But, we do need to add up the lengths of the SIDs
  1441. // so we can allocate a buffer (or check the size of one provided).
  1442. //
  1443. NextIndex = 0;
  1444. while (NextIndex < ArrayCount) {
  1445. GetSidSubAuthorityCount =
  1446. ((PISID)(InputArray[NextIndex].Sid))->SubAuthorityCount;
  1447. AlignedLengthRequired +=
  1448. (ULONG)LongAlignSize(RtlLengthRequiredSid(GetSidSubAuthorityCount));
  1449. NextIndex += 1;
  1450. } //end while
  1451. }
  1452. //
  1453. // Now we know how much memory we need.
  1454. // Return this value in the output parameter.
  1455. //
  1456. (*AlignedArraySize) = AlignedLengthRequired;
  1457. //
  1458. // If a buffer was provided, make sure it is long enough.
  1459. // Otherwise, allocate a buffer.
  1460. //
  1461. if (ARGUMENT_PRESENT(CaptureBuffer)) {
  1462. if (AlignedLengthRequired > CaptureBufferLength) {
  1463. if (RequestorMode != KernelMode) {
  1464. ExFreePool( TempArray );
  1465. }
  1466. return STATUS_BUFFER_TOO_SMALL;
  1467. } else {
  1468. (*CapturedArray) = CaptureBuffer;
  1469. }
  1470. } else {
  1471. (*CapturedArray) =
  1472. (PSID_AND_ATTRIBUTES)ExAllocatePoolWithTag(PoolType, AlignedLengthRequired, 'aSeS');
  1473. if ( *CapturedArray == NULL ) {
  1474. if (RequestorMode != KernelMode) {
  1475. ExFreePool( TempArray );
  1476. }
  1477. return( STATUS_INSUFFICIENT_RESOURCES );
  1478. }
  1479. }
  1480. //
  1481. // Now copy everything.
  1482. // This is done by copying all the SID_AND_ATTRIBUTES and then
  1483. // copying each individual SID.
  1484. //
  1485. // All SIDs have already been probed for READ access. We just
  1486. // need to copy them.
  1487. //
  1488. //
  1489. if (RequestorMode != KernelMode) {
  1490. try {
  1491. //
  1492. // Copy the SID_AND_ATTRIBUTES array elements
  1493. // This really only sets the attributes, since we
  1494. // over-write the SID pointer field later on.
  1495. //
  1496. NextBufferLocation = (*CapturedArray);
  1497. RtlCopyMemory( NextBufferLocation, InputArray, ArraySize );
  1498. NextBufferLocation = (PVOID)((ULONG_PTR)NextBufferLocation +
  1499. (ULONG)LongAlignSize(ArraySize) );
  1500. //
  1501. // Now go through and copy each referenced SID.
  1502. // Validate each SID as it is copied.
  1503. //
  1504. NextIndex = 0;
  1505. NextElement = (*CapturedArray);
  1506. while ( (NextIndex < ArrayCount) &&
  1507. (CompletionStatus == STATUS_SUCCESS) ) {
  1508. RtlCopyMemory( NextBufferLocation,
  1509. TempArray[NextIndex].Sid,
  1510. TempArray[NextIndex].SidLength );
  1511. NextElement[NextIndex].Sid = (PSID)NextBufferLocation;
  1512. NextBufferLocation =
  1513. (PVOID)((ULONG_PTR)NextBufferLocation +
  1514. (ULONG)LongAlignSize(TempArray[NextIndex].SidLength));
  1515. //
  1516. // Verify the sid is valid and its length didn't change
  1517. //
  1518. if (!RtlValidSid(NextElement[NextIndex].Sid) ) {
  1519. CompletionStatus = STATUS_INVALID_SID;
  1520. } else if (RtlLengthSid(NextElement[NextIndex].Sid) != TempArray[NextIndex].SidLength) {
  1521. CompletionStatus = STATUS_INVALID_SID;
  1522. }
  1523. NextIndex += 1;
  1524. } //end while
  1525. } except(EXCEPTION_EXECUTE_HANDLER) {
  1526. if (!ARGUMENT_PRESENT(CaptureBuffer)) {
  1527. ExFreePool( (*CapturedArray) );
  1528. }
  1529. ExFreePool( TempArray );
  1530. return GetExceptionCode();
  1531. }
  1532. } else {
  1533. //
  1534. // Requestor mode is kernel mode -
  1535. // don't need protection, probing, and validating
  1536. //
  1537. //
  1538. // Copy the SID_AND_ATTRIBUTES array elements
  1539. // This really only sets the attributes, since we
  1540. // over-write the SID pointer field later on.
  1541. //
  1542. NextBufferLocation = (*CapturedArray);
  1543. RtlCopyMemory( NextBufferLocation, InputArray, ArraySize );
  1544. NextBufferLocation = (PVOID)( (ULONG_PTR)NextBufferLocation +
  1545. (ULONG)LongAlignSize(ArraySize));
  1546. //
  1547. // Now go through and copy each referenced SID
  1548. //
  1549. NextIndex = 0;
  1550. NextElement = (*CapturedArray);
  1551. while (NextIndex < ArrayCount) {
  1552. GetSidSubAuthorityCount =
  1553. ((PISID)(NextElement[NextIndex].Sid))->SubAuthorityCount;
  1554. RtlCopyMemory(
  1555. NextBufferLocation,
  1556. NextElement[NextIndex].Sid,
  1557. RtlLengthRequiredSid(GetSidSubAuthorityCount) );
  1558. SidSize = RtlLengthRequiredSid( GetSidSubAuthorityCount );
  1559. AlignedSidSize = (ULONG)LongAlignSize(SidSize);
  1560. NextElement[NextIndex].Sid = (PSID)NextBufferLocation;
  1561. NextIndex += 1;
  1562. NextBufferLocation = (PVOID)((ULONG_PTR)NextBufferLocation +
  1563. AlignedSidSize);
  1564. } //end while
  1565. }
  1566. if (RequestorMode != KernelMode) {
  1567. ExFreePool( TempArray );
  1568. }
  1569. if (!ARGUMENT_PRESENT(CaptureBuffer) && !NT_SUCCESS(CompletionStatus)) {
  1570. ExFreePool( (*CapturedArray) );
  1571. *CapturedArray = NULL ;
  1572. }
  1573. return CompletionStatus;
  1574. }
  1575. VOID
  1576. SeReleaseSidAndAttributesArray (
  1577. IN PSID_AND_ATTRIBUTES CapturedArray,
  1578. IN KPROCESSOR_MODE RequestorMode,
  1579. IN BOOLEAN ForceCapture
  1580. )
  1581. /*++
  1582. Routine Description:
  1583. This routine releases a previously captured array of SID_AND_ATTRIBUTES.
  1584. This routine should NOT be called if the array was captured into a
  1585. provided CaptureBuffer (see SeCaptureSidAndAttributesArray).
  1586. Arguments:
  1587. CapturedArray - Supplies the array to release.
  1588. RequestorMode - The processor mode specified when the array was captured.
  1589. ForceCapture - The ForceCapture value specified when the array was
  1590. captured.
  1591. Return Value:
  1592. None.
  1593. --*/
  1594. {
  1595. //
  1596. // We only have something to deallocate if the requestor was user
  1597. // mode or kernel mode requesting ForceCapture.
  1598. //
  1599. PAGED_CODE();
  1600. if ( ((RequestorMode == KernelMode) && (ForceCapture == TRUE)) ||
  1601. (RequestorMode == UserMode ) ) {
  1602. ExFreePool(CapturedArray);
  1603. }
  1604. return;
  1605. }
  1606. NTSTATUS
  1607. SeComputeQuotaInformationSize(
  1608. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1609. OUT PULONG Size
  1610. )
  1611. /*++
  1612. Routine Description:
  1613. This routine computes the size of the Group and DACL for the
  1614. passed security descriptor.
  1615. This quantity will later be used in calculating the amount
  1616. of quota to charge for this object.
  1617. Arguments:
  1618. SecurityDescriptor - Supplies a pointer to the security descriptor
  1619. to be examined.
  1620. Size - Returns the size in bytes of the sum of the Group and Dacl
  1621. fields of the security descriptor.
  1622. Return Value:
  1623. STATUS_SUCCESS - The operation was successful.
  1624. STATUS_INVALID_REVISION - The passed security descriptor was of
  1625. an unknown revision.
  1626. --*/
  1627. {
  1628. PISECURITY_DESCRIPTOR ISecurityDescriptor;
  1629. PSID Group;
  1630. PACL Dacl;
  1631. PAGED_CODE();
  1632. ISecurityDescriptor = (PISECURITY_DESCRIPTOR)SecurityDescriptor;
  1633. *Size = 0;
  1634. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  1635. return( STATUS_UNKNOWN_REVISION );
  1636. }
  1637. Group = RtlpGroupAddrSecurityDescriptor( ISecurityDescriptor );
  1638. Dacl = RtlpDaclAddrSecurityDescriptor( ISecurityDescriptor );
  1639. if (Group != NULL) {
  1640. *Size += (ULONG)LongAlignSize(SeLengthSid( Group ));
  1641. }
  1642. if (Dacl != NULL) {
  1643. *Size += (ULONG)LongAlignSize(Dacl->AclSize);
  1644. }
  1645. return( STATUS_SUCCESS );
  1646. }
  1647. BOOLEAN
  1648. SeValidSecurityDescriptor(
  1649. IN ULONG Length,
  1650. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  1651. )
  1652. /*++
  1653. Routine Description:
  1654. Validates a security descriptor for structural correctness. The idea is to make
  1655. sure that the security descriptor may be passed to other kernel callers, without
  1656. fear that they're going to choke while manipulating it.
  1657. This routine does not enforce policy (e.g., ACL/ACE revision information). It is
  1658. entirely possible for a security descriptor to be approved by this routine, only
  1659. to be later found to be invalid by some later routine.
  1660. This routine is designed to be used by callers who have a security descriptor in
  1661. kernel memory. Callers wishing to validate a security descriptor passed from user
  1662. mode should call RtlValidSecurityDescriptor.
  1663. Arguments:
  1664. Length - Length in bytes of passed Security Descriptor.
  1665. SecurityDescriptor - Points to the Security Descriptor (in kernel memory) to be
  1666. validatated.
  1667. Return Value:
  1668. TRUE - The passed security descriptor is correctly structured
  1669. FALSE - The passed security descriptor is badly formed
  1670. --*/
  1671. {
  1672. PISECURITY_DESCRIPTOR_RELATIVE ISecurityDescriptor =
  1673. (PISECURITY_DESCRIPTOR_RELATIVE)SecurityDescriptor;
  1674. PISID OwnerSid;
  1675. PISID GroupSid;
  1676. PACE_HEADER Ace;
  1677. PISID Sid;
  1678. PISID Sid2;
  1679. PACL Dacl;
  1680. PACL Sacl;
  1681. ULONG i;
  1682. PAGED_CODE();
  1683. if (Length < sizeof(SECURITY_DESCRIPTOR_RELATIVE)) {
  1684. return(FALSE);
  1685. }
  1686. //
  1687. // Check the revision information.
  1688. //
  1689. if (ISecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
  1690. return(FALSE);
  1691. }
  1692. //
  1693. // Make sure the passed SecurityDescriptor is in self-relative form
  1694. //
  1695. if (!(ISecurityDescriptor->Control & SE_SELF_RELATIVE)) {
  1696. return(FALSE);
  1697. }
  1698. //
  1699. // Check the owner. A valid SecurityDescriptor must have an owner.
  1700. // It must also be long aligned.
  1701. //
  1702. if ((ISecurityDescriptor->Owner == 0) ||
  1703. (!LongAligned((PVOID)(ULONG_PTR)(ULONG)ISecurityDescriptor->Owner)) ||
  1704. (ISecurityDescriptor->Owner > Length) ||
  1705. (Length - ISecurityDescriptor->Owner < sizeof(SID))) {
  1706. return(FALSE);
  1707. }
  1708. //
  1709. // It is safe to reference the owner's SubAuthorityCount, compute the
  1710. // expected length of the SID
  1711. //
  1712. OwnerSid = (PSID)RtlOffsetToPointer( ISecurityDescriptor, ISecurityDescriptor->Owner );
  1713. if (OwnerSid->Revision != SID_REVISION) {
  1714. return(FALSE);
  1715. }
  1716. if (OwnerSid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  1717. return(FALSE);
  1718. }
  1719. if (Length - ISecurityDescriptor->Owner < (ULONG) SeLengthSid(OwnerSid)) {
  1720. return(FALSE);
  1721. }
  1722. //
  1723. // The owner appears to be a structurally valid SID that lies within
  1724. // the bounds of the security descriptor. Do the same for the Group
  1725. // if there is one.
  1726. //
  1727. if (ISecurityDescriptor->Group != 0) {
  1728. //
  1729. // Check alignment
  1730. //
  1731. if (!LongAligned( (PVOID)(ULONG_PTR)(ULONG)ISecurityDescriptor->Group)) {
  1732. return(FALSE);
  1733. }
  1734. if (ISecurityDescriptor->Group > Length) {
  1735. return(FALSE);
  1736. }
  1737. if (Length - ISecurityDescriptor->Group < sizeof (SID)) {
  1738. return(FALSE);
  1739. }
  1740. //
  1741. // It is safe to reference the Group's SubAuthorityCount, compute the
  1742. // expected length of the SID
  1743. //
  1744. GroupSid = (PSID)RtlOffsetToPointer( ISecurityDescriptor, ISecurityDescriptor->Group );
  1745. if (GroupSid->Revision != SID_REVISION) {
  1746. return(FALSE);
  1747. }
  1748. if (GroupSid->SubAuthorityCount > SID_MAX_SUB_AUTHORITIES) {
  1749. return(FALSE);
  1750. }
  1751. if (Length - ISecurityDescriptor->Group < (ULONG) SeLengthSid(GroupSid)) {
  1752. return(FALSE);
  1753. }
  1754. }
  1755. //
  1756. // Validate the DACL. A structurally valid SecurityDescriptor may not necessarily
  1757. // have a DACL.
  1758. //
  1759. if (ISecurityDescriptor->Dacl != 0) {
  1760. //
  1761. // Check alignment
  1762. //
  1763. if (!LongAligned( (PVOID)(ULONG_PTR)(ULONG)ISecurityDescriptor->Dacl)) {
  1764. return(FALSE);
  1765. }
  1766. //
  1767. // Make sure the DACL structure is within the bounds of the security descriptor.
  1768. //
  1769. if ((ISecurityDescriptor->Dacl > Length) ||
  1770. (Length - ISecurityDescriptor->Dacl < sizeof(ACL))) {
  1771. return(FALSE);
  1772. }
  1773. Dacl = (PACL) RtlOffsetToPointer( ISecurityDescriptor, ISecurityDescriptor->Dacl );
  1774. //
  1775. // Make sure the DACL length fits within the bounds of the security descriptor.
  1776. //
  1777. if (Length - ISecurityDescriptor->Dacl < Dacl->AclSize) {
  1778. return(FALSE);
  1779. }
  1780. //
  1781. // Make sure the ACL is structurally valid.
  1782. //
  1783. if (!RtlValidAcl( Dacl )) {
  1784. return(FALSE);
  1785. }
  1786. }
  1787. //
  1788. // Validate the SACL. A structurally valid SecurityDescriptor may not
  1789. // have a SACL.
  1790. //
  1791. if (ISecurityDescriptor->Sacl != 0) {
  1792. //
  1793. // Check alignment
  1794. //
  1795. if (!LongAligned( (PVOID)(ULONG_PTR)(ULONG)ISecurityDescriptor->Sacl)) {
  1796. return(FALSE);
  1797. }
  1798. //
  1799. // Make sure the SACL structure is within the bounds of the security descriptor.
  1800. //
  1801. if ((ISecurityDescriptor->Sacl > Length) ||
  1802. (Length - ISecurityDescriptor->Sacl < sizeof(ACL))) {
  1803. return(FALSE);
  1804. }
  1805. //
  1806. // Make sure the Sacl structure is within the bounds of the security descriptor.
  1807. //
  1808. Sacl = (PACL)RtlOffsetToPointer( ISecurityDescriptor, ISecurityDescriptor->Sacl );
  1809. if (Length - ISecurityDescriptor->Sacl < Sacl->AclSize) {
  1810. return(FALSE);
  1811. }
  1812. //
  1813. // Make sure the ACL is structurally valid.
  1814. //
  1815. if (!RtlValidAcl( Sacl )) {
  1816. return(FALSE);
  1817. }
  1818. }
  1819. return(TRUE);
  1820. }