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.

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