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.

4595 lines
135 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. seaudit.c
  5. Abstract:
  6. This Module implements the audit and alarm procedures.
  7. Author:
  8. Robert Reichel (robertre) 26-Nov-90
  9. Scott Birrell (ScottBi) 17-Jan-92
  10. Environment:
  11. Kernel Mode
  12. Revision History:
  13. Richard Ward (richardw) 14-Apr-92
  14. --*/
  15. #include "pch.h"
  16. #pragma hdrstop
  17. VOID
  18. SepProbeAndCaptureString_U (
  19. IN PUNICODE_STRING SourceString,
  20. OUT PUNICODE_STRING *DestString
  21. );
  22. VOID
  23. SepFreeCapturedString(
  24. IN PUNICODE_STRING CapturedString
  25. );
  26. VOID
  27. SepAuditTypeList (
  28. IN PIOBJECT_TYPE_LIST ObjectTypeList,
  29. IN ULONG ObjectTypeListLength,
  30. IN PNTSTATUS AccessStatus,
  31. IN ULONG StartIndex,
  32. OUT PBOOLEAN GenerateSuccessAudit,
  33. OUT PBOOLEAN GenerateFailureAudit
  34. );
  35. VOID
  36. SepExamineSaclEx(
  37. IN PACL Sacl,
  38. IN PACCESS_TOKEN Token,
  39. IN ACCESS_MASK DesiredAccess,
  40. IN PIOBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
  41. IN ULONG ObjectTypeListLength,
  42. IN BOOLEAN ReturnResultList,
  43. IN PNTSTATUS AccessStatus,
  44. IN PACCESS_MASK GrantedAccess,
  45. IN PSID PrincipalSelfSid,
  46. OUT PBOOLEAN GenerateSuccessAudit,
  47. OUT PBOOLEAN GenerateFailureAudit
  48. );
  49. NTSTATUS
  50. SepAccessCheckAndAuditAlarm (
  51. IN PUNICODE_STRING SubsystemName,
  52. IN PVOID HandleId,
  53. IN PHANDLE ClientToken OPTIONAL,
  54. IN PUNICODE_STRING ObjectTypeName,
  55. IN PUNICODE_STRING ObjectName,
  56. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  57. IN PSID PrincipalSelfSid,
  58. IN ACCESS_MASK DesiredAccess,
  59. IN AUDIT_EVENT_TYPE AuditType,
  60. IN ULONG Flags,
  61. IN POBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
  62. IN ULONG ObjectTypeListLength,
  63. IN PGENERIC_MAPPING GenericMapping,
  64. OUT PACCESS_MASK GrantedAccess,
  65. OUT PNTSTATUS AccessStatus,
  66. OUT PBOOLEAN GenerateOnClose,
  67. IN BOOLEAN ReturnResultList
  68. );
  69. #ifdef ALLOC_PRAGMA
  70. VOID
  71. SepSetAuditInfoForObjectType(
  72. IN UCHAR AceFlags,
  73. IN ACCESS_MASK AccessMask,
  74. IN ACCESS_MASK DesiredAccess,
  75. IN PIOBJECT_TYPE_LIST ObjectTypeList,
  76. IN ULONG ObjectTypeListLength,
  77. IN BOOLEAN ReturnResultList,
  78. IN ULONG ObjectTypeIndex,
  79. IN PNTSTATUS AccessStatus,
  80. IN PACCESS_MASK GrantedAccess,
  81. IN BOOLEAN FailedMaximumAllowed,
  82. OUT PBOOLEAN GenerateSuccessAudit,
  83. OUT PBOOLEAN GenerateFailureAudit
  84. );
  85. #pragma alloc_text(PAGE,SepSinglePrivilegeCheck)
  86. #pragma alloc_text(PAGE,SeCheckAuditPrivilege)
  87. #pragma alloc_text(PAGE,SepProbeAndCaptureString_U)
  88. #pragma alloc_text(PAGE,SepFreeCapturedString)
  89. #pragma alloc_text(PAGE,NtPrivilegeObjectAuditAlarm)
  90. #pragma alloc_text(PAGE,SePrivilegeObjectAuditAlarm)
  91. #pragma alloc_text(PAGE,NtPrivilegedServiceAuditAlarm)
  92. #pragma alloc_text(PAGE,SePrivilegedServiceAuditAlarm)
  93. #pragma alloc_text(PAGE,SepAccessCheckAndAuditAlarm)
  94. #pragma alloc_text(PAGE,NtAccessCheckAndAuditAlarm)
  95. #pragma alloc_text(PAGE,NtAccessCheckByTypeAndAuditAlarm)
  96. #pragma alloc_text(PAGE,NtAccessCheckByTypeResultListAndAuditAlarm)
  97. #pragma alloc_text(PAGE,NtAccessCheckByTypeResultListAndAuditAlarmByHandle)
  98. #pragma alloc_text(PAGE,NtOpenObjectAuditAlarm)
  99. #pragma alloc_text(PAGE,NtCloseObjectAuditAlarm)
  100. #pragma alloc_text(PAGE,NtDeleteObjectAuditAlarm)
  101. #pragma alloc_text(PAGE,SeOpenObjectAuditAlarm)
  102. #pragma alloc_text(PAGE,SeOpenObjectForDeleteAuditAlarm)
  103. #pragma alloc_text(PAGE,SeObjectReferenceAuditAlarm)
  104. #pragma alloc_text(PAGE,SeAuditHandleCreation)
  105. #pragma alloc_text(PAGE,SeCloseObjectAuditAlarm)
  106. #pragma alloc_text(PAGE,SeDeleteObjectAuditAlarm)
  107. #pragma alloc_text(PAGE,SepExamineSacl)
  108. #pragma alloc_text(PAGE,SepAuditTypeList)
  109. #pragma alloc_text(PAGE,SepSetAuditInfoForObjectType)
  110. #pragma alloc_text(PAGE,SepExamineSaclEx)
  111. #pragma alloc_text(INIT,SepInitializePrivilegeFilter)
  112. #pragma alloc_text(PAGE,SepFilterPrivilegeAudits)
  113. #pragma alloc_text(PAGE,SeAuditingFileOrGlobalEvents)
  114. #pragma alloc_text(PAGE,SeAuditingFileEvents)
  115. #pragma alloc_text(PAGE,SeAuditingHardLinkEvents)
  116. #endif
  117. //
  118. // Flag to tell us if we are auditing shutdown events.
  119. //
  120. // Move this to seglobal.c
  121. //
  122. //BOOLEAN SepAuditShutdownEvents = FALSE;
  123. //
  124. // Private useful routines
  125. //
  126. //
  127. // This routine is to be called to do simple checks of single privileges
  128. // against the passed token.
  129. //
  130. // DO NOT CALL THIS TO CHECK FOR SeTcbPrivilege SINCE THAT MUST
  131. // BE CHECKED AGAINST THE PRIMARY TOKEN ONLY!
  132. //
  133. BOOLEAN
  134. SepSinglePrivilegeCheck (
  135. LUID DesiredPrivilege,
  136. IN PACCESS_TOKEN Token,
  137. IN KPROCESSOR_MODE PreviousMode
  138. )
  139. /*++
  140. Routine Description:
  141. Determines if the passed token has the passed privilege.
  142. Arguments:
  143. DesiredPrivilege - The privilege to be tested for.
  144. Token - The token being examined.
  145. PreviousMode - The previous processor mode.
  146. Return Value:
  147. Returns TRUE of the subject has the passed privilege, FALSE otherwise.
  148. --*/
  149. {
  150. LUID_AND_ATTRIBUTES Privilege;
  151. BOOLEAN Result;
  152. PAGED_CODE();
  153. //
  154. // Don't let anyone call this to test for SeTcbPrivilege
  155. //
  156. ASSERT(!((DesiredPrivilege.LowPart == SeTcbPrivilege.LowPart) &&
  157. (DesiredPrivilege.HighPart == SeTcbPrivilege.HighPart)));
  158. Privilege.Luid = DesiredPrivilege;
  159. Privilege.Attributes = 0;
  160. Result = SepPrivilegeCheck(
  161. Token,
  162. &Privilege,
  163. 1,
  164. PRIVILEGE_SET_ALL_NECESSARY,
  165. PreviousMode
  166. );
  167. return(Result);
  168. }
  169. BOOLEAN
  170. SeCheckAuditPrivilege (
  171. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
  172. IN KPROCESSOR_MODE PreviousMode
  173. )
  174. /*++
  175. Routine Description:
  176. This routine specifically searches the primary token (rather than
  177. the effective token) of the calling process for SeAuditPrivilege.
  178. In order to do this it must call the underlying worker
  179. SepPrivilegeCheck directly, to ensure that the correct token is
  180. searched
  181. Arguments:
  182. SubjectSecurityContext - The subject being examined.
  183. PreviousMode - The previous processor mode.
  184. Return Value:
  185. Returns TRUE if the subject has SeAuditPrivilege, FALSE otherwise.
  186. --*/
  187. {
  188. PRIVILEGE_SET RequiredPrivileges;
  189. BOOLEAN AccessGranted;
  190. PAGED_CODE();
  191. RequiredPrivileges.PrivilegeCount = 1;
  192. RequiredPrivileges.Control = PRIVILEGE_SET_ALL_NECESSARY;
  193. RequiredPrivileges.Privilege[0].Luid = SeAuditPrivilege;
  194. RequiredPrivileges.Privilege[0].Attributes = 0;
  195. AccessGranted = SepPrivilegeCheck(
  196. SubjectSecurityContext->PrimaryToken, // token
  197. RequiredPrivileges.Privilege, // privilege set
  198. RequiredPrivileges.PrivilegeCount, // privilege count
  199. PRIVILEGE_SET_ALL_NECESSARY, // privilege control
  200. PreviousMode // previous mode
  201. );
  202. if ( PreviousMode != KernelMode ) {
  203. SePrivilegedServiceAuditAlarm (
  204. NULL,
  205. SubjectSecurityContext,
  206. &RequiredPrivileges,
  207. AccessGranted
  208. );
  209. }
  210. return( AccessGranted );
  211. }
  212. VOID
  213. SepProbeAndCaptureString_U (
  214. IN PUNICODE_STRING SourceString,
  215. OUT PUNICODE_STRING *DestString
  216. )
  217. /*++
  218. Routine Description:
  219. Helper routine to probe and capture a Unicode string argument.
  220. This routine may fail due to lack of memory, in which case,
  221. it will return a NULL pointer in the output parameter.
  222. Arguments:
  223. SourceString - Pointer to a Unicode string to be captured.
  224. DestString - Returns a pointer to a captured Unicode string. This
  225. will be one contiguous structure, and thus may be freed by
  226. a single call to ExFreePool().
  227. Return Value:
  228. None.
  229. --*/
  230. {
  231. UNICODE_STRING InputString;
  232. ULONG Length;
  233. NTSTATUS Status;
  234. PAGED_CODE();
  235. //
  236. // Initialize the object name descriptor and capture the specified name
  237. // string.
  238. //
  239. *DestString = NULL;
  240. Status = STATUS_SUCCESS;
  241. try {
  242. //
  243. // Probe and capture the name string descriptor and probe the
  244. // name string, if necessary.
  245. //
  246. InputString = ProbeAndReadUnicodeString(SourceString);
  247. ProbeForRead(InputString.Buffer,
  248. InputString.Length,
  249. sizeof(WCHAR));
  250. //
  251. // If the length of the string is not an even multiple of the
  252. // size of a UNICODE character or cannot be zero terminated,
  253. // then return an error.
  254. //
  255. Length = InputString.Length;
  256. if (((Length & (sizeof(WCHAR) - 1)) != 0) ||
  257. (Length == (MAXUSHORT - sizeof(WCHAR) + 1))) {
  258. Status = STATUS_INVALID_PARAMETER;
  259. } else {
  260. //
  261. // Allocate a buffer for the specified name string.
  262. //
  263. *DestString = ExAllocatePoolWithTag(
  264. PagedPool,
  265. InputString.Length + sizeof(UNICODE_STRING),
  266. 'sUeS');
  267. if (*DestString == NULL) {
  268. Status = STATUS_INSUFFICIENT_RESOURCES;
  269. } else {
  270. (*DestString)->Length = InputString.Length;
  271. (*DestString)->MaximumLength = InputString.Length;
  272. (*DestString)->Buffer = (PWSTR) ((*DestString) + 1);
  273. if (InputString.Length != 0) {
  274. RtlCopyMemory(
  275. (*DestString)->Buffer,
  276. InputString.Buffer,
  277. InputString.Length);
  278. }
  279. }
  280. }
  281. } except(ExSystemExceptionFilter()) {
  282. Status = GetExceptionCode();
  283. if (*DestString != NULL) {
  284. ExFreePool(*DestString);
  285. *DestString = NULL;
  286. }
  287. }
  288. return;
  289. }
  290. VOID
  291. SepFreeCapturedString(
  292. IN PUNICODE_STRING CapturedString
  293. )
  294. /*++
  295. Routine Description:
  296. Frees a string captured by SepProbeAndCaptureString.
  297. Arguments:
  298. CapturedString - Supplies a pointer to a string previously captured
  299. by SepProbeAndCaptureString.
  300. Return Value:
  301. None.
  302. --*/
  303. {
  304. PAGED_CODE();
  305. ExFreePool( CapturedString );
  306. return;
  307. }
  308. ////////////////////////////////////////////////////////////////////////
  309. // //
  310. // Privileged Object Audit Alarms //
  311. // //
  312. ////////////////////////////////////////////////////////////////////////
  313. NTSTATUS
  314. NtPrivilegeObjectAuditAlarm (
  315. IN PUNICODE_STRING SubsystemName,
  316. IN PVOID HandleId,
  317. IN HANDLE ClientToken,
  318. IN ACCESS_MASK DesiredAccess,
  319. IN PPRIVILEGE_SET Privileges,
  320. IN BOOLEAN AccessGranted
  321. )
  322. /*++
  323. Routine Description:
  324. This routine is used to generate audit and alarm messages when an
  325. attempt is made to perform privileged operations on a protected
  326. subsystem object after the object is already opened. This routine may
  327. result in several messages being generated and sent to Port objects.
  328. This may result in a significant latency before returning. Design of
  329. routines that must call this routine must take this potential latency
  330. into account. This may have an impact on the approach taken for data
  331. structure mutex locking, for example.
  332. This API requires the caller have SeAuditPrivilege privilege. The test
  333. for this privilege is always against the primary token of the calling
  334. process, allowing the caller to be impersonating a client during the
  335. call with no ill effects.
  336. Arguments:
  337. SubsystemName - Supplies a name string identifying the subsystem
  338. calling the routine.
  339. HandleId - A unique value representing the client's handle to the
  340. object.
  341. ClientToken - A handle to a token object representing the client that
  342. requested the operation. This handle must be obtained from a
  343. communication session layer, such as from an LPC Port or Local
  344. Named Pipe, to prevent possible security policy violations.
  345. DesiredAccess - The desired access mask. This mask must have been
  346. previously mapped to contain no generic accesses.
  347. Privileges - The set of privileges required for the requested
  348. operation. Those privileges that were held by the subject are
  349. marked using the UsedForAccess flag of the attributes
  350. associated with each privilege.
  351. AccessGranted - Indicates whether the requested access was granted or
  352. not. A value of TRUE indicates the access was granted. A value of
  353. FALSE indicates the access was not granted.
  354. Return value:
  355. --*/
  356. {
  357. KPROCESSOR_MODE PreviousMode;
  358. PUNICODE_STRING CapturedSubsystemName = NULL;
  359. PPRIVILEGE_SET CapturedPrivileges = NULL;
  360. ULONG PrivilegeParameterLength;
  361. ULONG PrivilegeCount;
  362. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  363. BOOLEAN Result;
  364. PTOKEN Token;
  365. NTSTATUS Status;
  366. BOOLEAN AuditPerformed;
  367. PAGED_CODE();
  368. PreviousMode = KeGetPreviousMode();
  369. ASSERT(PreviousMode != KernelMode);
  370. Status = ObReferenceObjectByHandle(
  371. ClientToken, // Handle
  372. TOKEN_QUERY, // DesiredAccess
  373. SeTokenObjectType, // ObjectType
  374. PreviousMode, // AccessMode
  375. (PVOID *)&Token, // Object
  376. NULL // GrantedAccess
  377. );
  378. if (!NT_SUCCESS( Status )) {
  379. return( Status );
  380. }
  381. //
  382. // If the passed token is an impersonation token, make sure
  383. // it is at SecurityIdentification or above.
  384. //
  385. if (Token->TokenType == TokenImpersonation) {
  386. if (Token->ImpersonationLevel < SecurityIdentification) {
  387. ObDereferenceObject( (PVOID)Token );
  388. return( STATUS_BAD_IMPERSONATION_LEVEL );
  389. }
  390. }
  391. // //
  392. // // Make sure the passed token is an impersonation token...
  393. // //
  394. //
  395. // if (Token->TokenType != TokenImpersonation) {
  396. //
  397. // ObDereferenceObject( (PVOID)Token );
  398. //
  399. // return( STATUS_NO_IMPERSONATION_TOKEN );
  400. //
  401. // }
  402. //
  403. // //
  404. // // ...and at a high enough impersonation level
  405. // //
  406. //
  407. // if (Token->ImpersonationLevel < SecurityIdentification) {
  408. //
  409. // ObDereferenceObject( (PVOID)Token );
  410. //
  411. // return( STATUS_BAD_IMPERSONATION_LEVEL );
  412. //
  413. // }
  414. //
  415. // Check for SeAuditPrivilege
  416. //
  417. SeCaptureSubjectContext ( &SubjectSecurityContext );
  418. Result = SeCheckAuditPrivilege (
  419. &SubjectSecurityContext,
  420. PreviousMode
  421. );
  422. if (!Result) {
  423. ObDereferenceObject( (PVOID)Token );
  424. SeReleaseSubjectContext ( &SubjectSecurityContext );
  425. return(STATUS_PRIVILEGE_NOT_HELD);
  426. }
  427. try {
  428. SepProbeAndCaptureString_U ( SubsystemName,
  429. &CapturedSubsystemName );
  430. ProbeForReadSmallStructure(
  431. Privileges,
  432. sizeof(PRIVILEGE_SET),
  433. sizeof(ULONG)
  434. );
  435. PrivilegeCount = Privileges->PrivilegeCount;
  436. if (!IsValidElementCount(PrivilegeCount, LUID_AND_ATTRIBUTES)) {
  437. Status= STATUS_INVALID_PARAMETER;
  438. leave ;
  439. }
  440. PrivilegeParameterLength = (ULONG)sizeof(PRIVILEGE_SET) +
  441. ((PrivilegeCount - ANYSIZE_ARRAY) *
  442. (ULONG)sizeof(LUID_AND_ATTRIBUTES) );
  443. ProbeForRead(
  444. Privileges,
  445. PrivilegeParameterLength,
  446. sizeof(ULONG)
  447. );
  448. CapturedPrivileges = ExAllocatePoolWithTag( PagedPool,
  449. PrivilegeParameterLength,
  450. 'rPeS'
  451. );
  452. if (CapturedPrivileges != NULL) {
  453. RtlCopyMemory ( CapturedPrivileges,
  454. Privileges,
  455. PrivilegeParameterLength );
  456. CapturedPrivileges->PrivilegeCount = PrivilegeCount;
  457. }
  458. } except (EXCEPTION_EXECUTE_HANDLER) {
  459. Status = GetExceptionCode();
  460. }
  461. if (!NT_SUCCESS(Status)) {
  462. if (CapturedPrivileges != NULL) {
  463. ExFreePool( CapturedPrivileges );
  464. }
  465. if (CapturedSubsystemName != NULL) {
  466. SepFreeCapturedString ( CapturedSubsystemName );
  467. }
  468. SeReleaseSubjectContext ( &SubjectSecurityContext );
  469. ObDereferenceObject( (PVOID)Token );
  470. return Status;
  471. }
  472. //
  473. // No need to lock the token, because the only thing we're going
  474. // to reference in it is the User's Sid, which cannot be changed.
  475. //
  476. //
  477. // SepPrivilegeObjectAuditAlarm will check the global flags
  478. // to determine if we're supposed to be auditing here.
  479. //
  480. AuditPerformed = SepAdtPrivilegeObjectAuditAlarm (
  481. CapturedSubsystemName,
  482. HandleId,
  483. Token, // ClientToken
  484. SubjectSecurityContext.PrimaryToken, // PrimaryToken
  485. SubjectSecurityContext.ProcessAuditId,
  486. DesiredAccess,
  487. CapturedPrivileges,
  488. AccessGranted
  489. );
  490. if (CapturedPrivileges != NULL) {
  491. ExFreePool( CapturedPrivileges );
  492. }
  493. if (CapturedSubsystemName != NULL) {
  494. SepFreeCapturedString ( CapturedSubsystemName );
  495. }
  496. SeReleaseSubjectContext ( &SubjectSecurityContext );
  497. ObDereferenceObject( (PVOID)Token );
  498. return(STATUS_SUCCESS);
  499. }
  500. VOID
  501. SePrivilegeObjectAuditAlarm(
  502. IN HANDLE Handle,
  503. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
  504. IN ACCESS_MASK DesiredAccess,
  505. IN PPRIVILEGE_SET Privileges,
  506. IN BOOLEAN AccessGranted,
  507. IN KPROCESSOR_MODE AccessMode
  508. )
  509. /*++
  510. Routine Description:
  511. This routine is used by object methods that perform privileged
  512. operations to generate audit and alarm messages related to the use
  513. of privileges, or attempts to use privileges.
  514. Arguments:
  515. Object - Address of the object accessed. This value will not be
  516. used as a pointer (referenced). It is necessary only to enter
  517. into log messages.
  518. Handle - Provides the handle value assigned for the open.
  519. SecurityDescriptor - A pointer to the security descriptor of the
  520. object being accessed.
  521. SubjectSecurityContext - A pointer to the captured security
  522. context of the subject attempting to open the object.
  523. DesiredAccess - The desired access mask. This mask must have been
  524. previously mapped to contain no generic accesses.
  525. Privileges - Points to a set of privileges required for the access
  526. attempt. Those privileges that were held by the subject are
  527. marked using the UsedForAccess flag of the PRIVILEGE_ATTRIBUTES
  528. associated with each privilege.
  529. AccessGranted - Indicates whether the access was granted or
  530. denied. A value of TRUE indicates the access was allowed. A
  531. value of FALSE indicates the access was denied.
  532. AccessMode - Indicates the access mode used for the access check.
  533. Messages will not be generated by kernel mode accesses.
  534. Return Value:
  535. None.
  536. --*/
  537. {
  538. BOOLEAN AuditPerformed;
  539. PAGED_CODE();
  540. if (AccessMode != KernelMode) {
  541. AuditPerformed = SepAdtPrivilegeObjectAuditAlarm (
  542. (PUNICODE_STRING)&SeSubsystemName,
  543. Handle,
  544. SubjectSecurityContext->ClientToken,
  545. SubjectSecurityContext->PrimaryToken,
  546. SubjectSecurityContext->ProcessAuditId,
  547. DesiredAccess,
  548. Privileges,
  549. AccessGranted
  550. );
  551. }
  552. }
  553. ////////////////////////////////////////////////////////////////////////
  554. // //
  555. // Privileged Service Audit Alarms //
  556. // //
  557. ////////////////////////////////////////////////////////////////////////
  558. NTSTATUS
  559. NtPrivilegedServiceAuditAlarm (
  560. IN PUNICODE_STRING SubsystemName,
  561. IN PUNICODE_STRING ServiceName,
  562. IN HANDLE ClientToken,
  563. IN PPRIVILEGE_SET Privileges,
  564. IN BOOLEAN AccessGranted
  565. )
  566. /*++
  567. Routine Description:
  568. This routine is used to generate audit and alarm messages when an
  569. attempt is made to perform privileged system service operations. This
  570. routine may result in several messages being generated and sent to Port
  571. objects. This may result in a significant latency before returning.
  572. Design of routines that must call this routine must take this potential
  573. latency into account. This may have an impact on the approach taken
  574. for data structure mutex locking, for example.
  575. This API requires the caller have SeAuditPrivilege privilege. The test
  576. for this privilege is always against the primary token of the calling
  577. process, allowing the caller to be impersonating a client during the
  578. call with no ill effects
  579. Arguments:
  580. SubsystemName - Supplies a name string identifying the subsystem
  581. calling the routine.
  582. ServiceName - Supplies a name of the privileged subsystem service. For
  583. example, "RESET RUNTIME LOCAL SECURITY POLICY" might be specified
  584. by a Local Security Authority service used to update the local
  585. security policy database.
  586. ClientToken - A handle to a token object representing the client that
  587. requested the operation. This handle must be obtained from a
  588. communication session layer, such as from an LPC Port or Local
  589. Named Pipe, to prevent possible security policy violations.
  590. Privileges - Points to a set of privileges required to perform the
  591. privileged operation. Those privileges that were held by the
  592. subject are marked using the UsedForAccess flag of the
  593. attributes associated with each privilege.
  594. AccessGranted - Indicates whether the requested access was granted or
  595. not. A value of TRUE indicates the access was granted. A value of
  596. FALSE indicates the access was not granted.
  597. Return value:
  598. --*/
  599. {
  600. PPRIVILEGE_SET CapturedPrivileges = NULL;
  601. ULONG PrivilegeParameterLength = 0;
  602. BOOLEAN Result;
  603. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  604. KPROCESSOR_MODE PreviousMode;
  605. PUNICODE_STRING CapturedSubsystemName = NULL;
  606. PUNICODE_STRING CapturedServiceName = NULL;
  607. NTSTATUS Status;
  608. PTOKEN Token;
  609. ULONG PrivilegeCount;
  610. PAGED_CODE();
  611. PreviousMode = KeGetPreviousMode();
  612. ASSERT(PreviousMode != KernelMode);
  613. Status = ObReferenceObjectByHandle(
  614. ClientToken, // Handle
  615. TOKEN_QUERY, // DesiredAccess
  616. SeTokenObjectType, // ObjectType
  617. PreviousMode, // AccessMode
  618. (PVOID *)&Token, // Object
  619. NULL // GrantedAccess
  620. );
  621. if ( !NT_SUCCESS( Status )) {
  622. return( Status );
  623. }
  624. //
  625. // If the passed token is an impersonation token, make sure
  626. // it is at SecurityIdentification or above.
  627. //
  628. if (Token->TokenType == TokenImpersonation) {
  629. if (Token->ImpersonationLevel < SecurityIdentification) {
  630. ObDereferenceObject( (PVOID)Token );
  631. return( STATUS_BAD_IMPERSONATION_LEVEL );
  632. }
  633. }
  634. // //
  635. // // Make sure the passed token is an impersonation token...
  636. // //
  637. //
  638. // if (Token->TokenType != TokenImpersonation) {
  639. //
  640. // ObDereferenceObject( (PVOID)Token );
  641. //
  642. // return( STATUS_NO_IMPERSONATION_TOKEN );
  643. //
  644. // }
  645. //
  646. // //
  647. // // ...and at a high enough impersonation level
  648. // //
  649. //
  650. // if (Token->ImpersonationLevel < SecurityIdentification) {
  651. //
  652. // ObDereferenceObject( (PVOID)Token );
  653. //
  654. // return( STATUS_BAD_IMPERSONATION_LEVEL );
  655. //
  656. // }
  657. //
  658. // Check for SeAuditPrivilege
  659. //
  660. SeCaptureSubjectContext ( &SubjectSecurityContext );
  661. Result = SeCheckAuditPrivilege (
  662. &SubjectSecurityContext,
  663. PreviousMode
  664. );
  665. if (!Result) {
  666. ObDereferenceObject( (PVOID)Token );
  667. SeReleaseSubjectContext ( &SubjectSecurityContext );
  668. return(STATUS_PRIVILEGE_NOT_HELD);
  669. }
  670. try {
  671. if ( ARGUMENT_PRESENT( SubsystemName )) {
  672. SepProbeAndCaptureString_U ( SubsystemName,
  673. &CapturedSubsystemName );
  674. }
  675. if ( ARGUMENT_PRESENT( ServiceName )) {
  676. SepProbeAndCaptureString_U ( ServiceName,
  677. &CapturedServiceName );
  678. }
  679. ProbeForReadSmallStructure(
  680. Privileges,
  681. sizeof(PRIVILEGE_SET),
  682. sizeof(ULONG)
  683. );
  684. PrivilegeCount = Privileges->PrivilegeCount;
  685. if (!IsValidElementCount( PrivilegeCount, LUID_AND_ATTRIBUTES ) ) {
  686. Status = STATUS_INVALID_PARAMETER;
  687. leave ;
  688. }
  689. PrivilegeParameterLength = (ULONG)sizeof(PRIVILEGE_SET) +
  690. ((PrivilegeCount - ANYSIZE_ARRAY) *
  691. (ULONG)sizeof(LUID_AND_ATTRIBUTES) );
  692. ProbeForRead(
  693. Privileges,
  694. PrivilegeParameterLength,
  695. sizeof(ULONG)
  696. );
  697. CapturedPrivileges = ExAllocatePoolWithTag( PagedPool,
  698. PrivilegeParameterLength,
  699. 'rPeS'
  700. );
  701. //
  702. // If ExAllocatePool has failed, too bad. Carry on and do as much of the
  703. // audit as we can.
  704. //
  705. if (CapturedPrivileges != NULL) {
  706. RtlCopyMemory ( CapturedPrivileges,
  707. Privileges,
  708. PrivilegeParameterLength );
  709. CapturedPrivileges->PrivilegeCount = PrivilegeCount;
  710. }
  711. } except (EXCEPTION_EXECUTE_HANDLER) {
  712. Status = GetExceptionCode();
  713. }
  714. if (!NT_SUCCESS(Status)) {
  715. if (CapturedSubsystemName != NULL) {
  716. SepFreeCapturedString ( CapturedSubsystemName );
  717. }
  718. if (CapturedServiceName != NULL) {
  719. SepFreeCapturedString ( CapturedServiceName );
  720. }
  721. if (CapturedPrivileges != NULL) {
  722. ExFreePool ( CapturedPrivileges );
  723. }
  724. SeReleaseSubjectContext ( &SubjectSecurityContext );
  725. ObDereferenceObject( (PVOID)Token );
  726. return Status;
  727. }
  728. //
  729. // The AuthenticationId is in the read-only part of the token,
  730. // so we may reference it without having the token read-locked.
  731. //
  732. SepAdtPrivilegedServiceAuditAlarm ( CapturedSubsystemName,
  733. CapturedServiceName,
  734. Token,
  735. SubjectSecurityContext.PrimaryToken,
  736. CapturedPrivileges,
  737. AccessGranted );
  738. if (CapturedSubsystemName != NULL) {
  739. SepFreeCapturedString ( CapturedSubsystemName );
  740. }
  741. if (CapturedServiceName != NULL) {
  742. SepFreeCapturedString ( CapturedServiceName );
  743. }
  744. if (CapturedPrivileges != NULL) {
  745. ExFreePool ( CapturedPrivileges );
  746. }
  747. ObDereferenceObject( (PVOID)Token );
  748. SeReleaseSubjectContext ( &SubjectSecurityContext );
  749. return(STATUS_SUCCESS);
  750. }
  751. VOID
  752. SePrivilegedServiceAuditAlarm (
  753. IN PUNICODE_STRING ServiceName,
  754. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
  755. IN PPRIVILEGE_SET Privileges,
  756. IN BOOLEAN AccessGranted
  757. )
  758. /*++
  759. Routine Description:
  760. This routine is to be called whenever a privileged system service
  761. is attempted. It should be called immediately after the privilege
  762. check regardless of whether or not the test succeeds.
  763. Arguments:
  764. ServiceName - Supplies the name of the privileged system service.
  765. SubjectSecurityContext - The subject security context representing
  766. the caller of the system service.
  767. Privileges - Supplies a privilge set containing the privilege(s)
  768. required for the access.
  769. AccessGranted - Supplies the results of the privilege test.
  770. Return Value:
  771. None.
  772. --*/
  773. {
  774. PTOKEN Token;
  775. PAGED_CODE();
  776. if ( SepAdtAuditThisEvent( AuditCategoryPrivilegeUse, &AccessGranted ) &&
  777. SepFilterPrivilegeAudits( Privileges )) {
  778. Token = (PTOKEN)EffectiveToken( SubjectSecurityContext );
  779. if ( RtlEqualSid( SeLocalSystemSid, SepTokenUserSid( Token ))) {
  780. return;
  781. }
  782. SepAdtPrivilegedServiceAuditAlarm (
  783. (PUNICODE_STRING)&SeSubsystemName,
  784. ServiceName,
  785. SubjectSecurityContext->ClientToken,
  786. SubjectSecurityContext->PrimaryToken,
  787. Privileges,
  788. AccessGranted
  789. );
  790. }
  791. return;
  792. }
  793. NTSTATUS
  794. SepAccessCheckAndAuditAlarm (
  795. IN PUNICODE_STRING SubsystemName,
  796. IN PVOID HandleId,
  797. IN PHANDLE ClientToken OPTIONAL,
  798. IN PUNICODE_STRING ObjectTypeName,
  799. IN PUNICODE_STRING ObjectName,
  800. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  801. IN PSID PrincipalSelfSid,
  802. IN ACCESS_MASK DesiredAccess,
  803. IN AUDIT_EVENT_TYPE AuditType,
  804. IN ULONG Flags,
  805. IN POBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
  806. IN ULONG ObjectTypeListLength,
  807. IN PGENERIC_MAPPING GenericMapping,
  808. OUT PACCESS_MASK GrantedAccess,
  809. OUT PNTSTATUS AccessStatus,
  810. OUT PBOOLEAN GenerateOnClose,
  811. IN BOOLEAN ReturnResultList
  812. )
  813. /*++
  814. Routine Description:
  815. This system service is used to perform both an access validation and
  816. generate the corresponding audit and alarm messages. This service may
  817. only be used by a protected server that chooses to impersonate its
  818. client and thereby specifies the client security context implicitly.
  819. Arguments:
  820. SubsystemName - Supplies a name string identifying the subsystem
  821. calling the routine.
  822. HandleId - A unique value that will be used to represent the client's
  823. handle to the object. This value is ignored (and may be re-used)
  824. if the access is denied.
  825. ClientToken - Supplies the client token so that the caller does not have
  826. to impersonate before making the kernel call.
  827. ObjectTypeName - Supplies the name of the type of the object being
  828. created or accessed.
  829. ObjectName - Supplies the name of the object being created or accessed.
  830. SecurityDescriptor - A pointer to the Security Descriptor against which
  831. acccess is to be checked.
  832. DesiredAccess - The desired acccess mask. This mask must have been
  833. previously mapped to contain no generic accesses.
  834. AuditType - Specifies the type of audit to be generated. Valid values
  835. are: AuditEventObjectAccess and AuditEventDirectoryServiceAccess.
  836. Flags - Flags modifying the execution of the API:
  837. AUDIT_ALLOW_NO_PRIVILEGE - If the called does not have AuditPrivilege,
  838. the call will silently continue to check access and will
  839. generate no audit.
  840. ObjectTypeList - Supplies a list of GUIDs representing the object (and
  841. sub-objects) being accessed. If no list is present, AccessCheckByType
  842. behaves identically to AccessCheck.
  843. ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
  844. GenericMapping - Supplies a pointer to the generic mapping associated
  845. with this object type.
  846. ObjectCreation - A boolean flag indicated whether the access will
  847. result in a new object being created if granted. A value of TRUE
  848. indicates an object will be created, FALSE indicates an existing
  849. object will be opened.
  850. GrantedAccess - Receives a masking indicating which accesses have been
  851. granted.
  852. AccessStatus - Receives an indication of the success or failure of the
  853. access check. If access is granted, STATUS_SUCCESS is returned.
  854. If access is denied, a value appropriate for return to the client
  855. is returned. This will be STATUS_ACCESS_DENIED or, when mandatory
  856. access controls are implemented, STATUS_OBJECT_NOT_FOUND.
  857. GenerateOnClose - Points to a boolean that is set by the audity
  858. generation routine and must be passed to NtCloseObjectAuditAlarm
  859. when the object handle is closed.
  860. ReturnResultList - If true, GrantedAccess and AccessStatus are actually
  861. arrays of entries ObjectTypeListLength elements long.
  862. Return Value:
  863. STATUS_SUCCESS - Indicates the call completed successfully. In this
  864. case, ClientStatus receives the result of the access check.
  865. STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have
  866. sufficient privilege to use this privileged system service.
  867. --*/
  868. {
  869. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  870. NTSTATUS Status = STATUS_SUCCESS;
  871. ACCESS_MASK LocalGrantedAccess = (ACCESS_MASK)0;
  872. PACCESS_MASK LocalGrantedAccessPointer = NULL;
  873. BOOLEAN LocalGrantedAccessAllocated = FALSE;
  874. NTSTATUS LocalAccessStatus = STATUS_UNSUCCESSFUL;
  875. PNTSTATUS LocalAccessStatusPointer = NULL;
  876. BOOLEAN LocalGenerateOnClose = FALSE;
  877. POLICY_AUDIT_EVENT_TYPE NtAuditType;
  878. KPROCESSOR_MODE PreviousMode;
  879. PUNICODE_STRING CapturedSubsystemName = (PUNICODE_STRING) NULL;
  880. PUNICODE_STRING CapturedObjectTypeName = (PUNICODE_STRING) NULL;
  881. PUNICODE_STRING CapturedObjectName = (PUNICODE_STRING) NULL;
  882. PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = (PSECURITY_DESCRIPTOR) NULL;
  883. PSID CapturedPrincipalSelfSid = NULL;
  884. PIOBJECT_TYPE_LIST LocalObjectTypeList = NULL;
  885. ACCESS_MASK PreviouslyGrantedAccess = (ACCESS_MASK)0;
  886. GENERIC_MAPPING LocalGenericMapping;
  887. PPRIVILEGE_SET PrivilegeSet = NULL;
  888. BOOLEAN Result;
  889. BOOLEAN AccessGranted;
  890. BOOLEAN AccessDenied;
  891. BOOLEAN GenerateSuccessAudit = FALSE;
  892. BOOLEAN GenerateFailureAudit = FALSE;
  893. LUID OperationId;
  894. BOOLEAN AuditPerformed;
  895. BOOLEAN AvoidAudit = FALSE;
  896. PTOKEN NewToken = NULL;
  897. PTOKEN OldToken = NULL;
  898. BOOLEAN TokenSwapped = FALSE;
  899. PAGED_CODE();
  900. PreviousMode = KeGetPreviousMode();
  901. ASSERT( PreviousMode != KernelMode );
  902. //
  903. // Capture the subject Context
  904. //
  905. SeCaptureSubjectContext ( &SubjectSecurityContext );
  906. //
  907. // Convert AuditType
  908. //
  909. if ( AuditType == AuditEventObjectAccess ) {
  910. NtAuditType = AuditCategoryObjectAccess;
  911. } else if ( AuditType == AuditEventDirectoryServiceAccess ) {
  912. NtAuditType = AuditCategoryDirectoryServiceAccess;
  913. } else {
  914. Status = STATUS_INVALID_PARAMETER;
  915. goto Cleanup;
  916. }
  917. //
  918. // Impersonation checks should be done only if the ClientToken is NULL.
  919. //
  920. if ( !ARGUMENT_PRESENT( ClientToken ) ) {
  921. //
  922. // Make sure we're impersonating a client...
  923. //
  924. if ( (SubjectSecurityContext.ClientToken == NULL) ) {
  925. Status = STATUS_NO_IMPERSONATION_TOKEN;
  926. goto Cleanup;
  927. }
  928. //
  929. // ...and at a high enough impersonation level
  930. //
  931. if (SubjectSecurityContext.ImpersonationLevel < SecurityIdentification) {
  932. Status = STATUS_BAD_IMPERSONATION_LEVEL;
  933. goto Cleanup;
  934. }
  935. }
  936. try {
  937. if ( ReturnResultList ) {
  938. if ( ObjectTypeListLength == 0 ) {
  939. Status = STATUS_INVALID_PARAMETER;
  940. leave;
  941. }
  942. if (!IsValidElementCount(ObjectTypeListLength, ULONG)) {
  943. Status = STATUS_INVALID_PARAMETER;
  944. leave;
  945. }
  946. ProbeForWrite(
  947. AccessStatus,
  948. sizeof(NTSTATUS) * ObjectTypeListLength,
  949. sizeof(ULONG)
  950. );
  951. ProbeForWrite(
  952. GrantedAccess,
  953. sizeof(ACCESS_MASK) * ObjectTypeListLength,
  954. sizeof(ULONG)
  955. );
  956. } else {
  957. ProbeForWriteUlong((PULONG)AccessStatus);
  958. ProbeForWriteUlong((PULONG)GrantedAccess);
  959. }
  960. ProbeForReadSmallStructure(
  961. GenericMapping,
  962. sizeof(GENERIC_MAPPING),
  963. sizeof(ULONG)
  964. );
  965. LocalGenericMapping = *GenericMapping;
  966. } except (EXCEPTION_EXECUTE_HANDLER) {
  967. Status = GetExceptionCode();
  968. }
  969. if (!NT_SUCCESS(Status)) {
  970. goto Cleanup;
  971. }
  972. if ( ARGUMENT_PRESENT( ClientToken ) ) {
  973. Status = ObReferenceObjectByHandle(
  974. *ClientToken, // Handle
  975. (ACCESS_MASK)TOKEN_QUERY, // DesiredAccess
  976. SeTokenObjectType, // ObjectType
  977. PreviousMode, // AccessMode
  978. (PVOID *)&NewToken, // Object
  979. NULL // GrantedAccess
  980. );
  981. if (!NT_SUCCESS(Status)) {
  982. NewToken = NULL;
  983. goto Cleanup;
  984. }
  985. //
  986. // Save the old token so that it can be recovered before
  987. // SeReleaseSubjectContext.
  988. //
  989. OldToken = SubjectSecurityContext.ClientToken;
  990. //
  991. // Set the impersonation token to the one that has been obtained thru
  992. // ClientToken handle. This must be freed later in Cleanup.
  993. //
  994. SubjectSecurityContext.ClientToken = NewToken;
  995. TokenSwapped = TRUE;
  996. }
  997. //
  998. // Check for SeAuditPrivilege
  999. //
  1000. Result = SeCheckAuditPrivilege (
  1001. &SubjectSecurityContext,
  1002. PreviousMode
  1003. );
  1004. if (!Result) {
  1005. if ( Flags & AUDIT_ALLOW_NO_PRIVILEGE ) {
  1006. AvoidAudit = TRUE;
  1007. } else {
  1008. Status = STATUS_PRIVILEGE_NOT_HELD;
  1009. goto Cleanup;
  1010. }
  1011. }
  1012. if (DesiredAccess &
  1013. ( GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL )) {
  1014. Status = STATUS_GENERIC_NOT_MAPPED;
  1015. goto Cleanup;
  1016. }
  1017. //
  1018. // Capture the passed security descriptor.
  1019. //
  1020. // SeCaptureSecurityDescriptor probes the input security descriptor,
  1021. // so we don't have to
  1022. //
  1023. Status = SeCaptureSecurityDescriptor (
  1024. SecurityDescriptor,
  1025. PreviousMode,
  1026. PagedPool,
  1027. FALSE,
  1028. &CapturedSecurityDescriptor
  1029. );
  1030. if (!NT_SUCCESS(Status) ) {
  1031. CapturedSecurityDescriptor = NULL;
  1032. goto Cleanup;
  1033. }
  1034. if ( CapturedSecurityDescriptor == NULL ) {
  1035. Status = STATUS_INVALID_SECURITY_DESCR;
  1036. goto Cleanup;
  1037. }
  1038. //
  1039. // A valid security descriptor must have an owner and a group
  1040. //
  1041. if ( RtlpOwnerAddrSecurityDescriptor(
  1042. (PISECURITY_DESCRIPTOR)CapturedSecurityDescriptor
  1043. ) == NULL ||
  1044. RtlpGroupAddrSecurityDescriptor(
  1045. (PISECURITY_DESCRIPTOR)CapturedSecurityDescriptor
  1046. ) == NULL ) {
  1047. Status = STATUS_INVALID_SECURITY_DESCR;
  1048. goto Cleanup;
  1049. }
  1050. //
  1051. // Probe and capture the STRING arguments
  1052. //
  1053. try {
  1054. ProbeForWriteBoolean(GenerateOnClose);
  1055. SepProbeAndCaptureString_U ( SubsystemName, &CapturedSubsystemName );
  1056. SepProbeAndCaptureString_U ( ObjectTypeName, &CapturedObjectTypeName );
  1057. SepProbeAndCaptureString_U ( ObjectName, &CapturedObjectName );
  1058. } except (EXCEPTION_EXECUTE_HANDLER) {
  1059. Status = GetExceptionCode();
  1060. goto Cleanup;
  1061. }
  1062. //
  1063. // Capture the PrincipalSelfSid.
  1064. //
  1065. if ( PrincipalSelfSid != NULL ) {
  1066. Status = SeCaptureSid(
  1067. PrincipalSelfSid,
  1068. PreviousMode,
  1069. NULL, 0,
  1070. PagedPool,
  1071. TRUE,
  1072. &CapturedPrincipalSelfSid );
  1073. if (!NT_SUCCESS(Status)) {
  1074. CapturedPrincipalSelfSid = NULL;
  1075. goto Cleanup;
  1076. }
  1077. }
  1078. //
  1079. // Capture any Object type list
  1080. //
  1081. Status = SeCaptureObjectTypeList( ObjectTypeList,
  1082. ObjectTypeListLength,
  1083. PreviousMode,
  1084. &LocalObjectTypeList );
  1085. if (!NT_SUCCESS(Status)) {
  1086. goto Cleanup;
  1087. }
  1088. //
  1089. // See if anything (or everything) in the desired access can be
  1090. // satisfied by privileges.
  1091. //
  1092. Status = SePrivilegePolicyCheck(
  1093. &DesiredAccess,
  1094. &PreviouslyGrantedAccess,
  1095. &SubjectSecurityContext,
  1096. NULL,
  1097. &PrivilegeSet,
  1098. PreviousMode
  1099. );
  1100. SeLockSubjectContext( &SubjectSecurityContext );
  1101. if (!NT_SUCCESS( Status )) {
  1102. AccessGranted = FALSE;
  1103. AccessDenied = TRUE;
  1104. LocalAccessStatus = Status;
  1105. if ( ReturnResultList ) {
  1106. ULONG ResultListIndex;
  1107. LocalGrantedAccessPointer =
  1108. ExAllocatePoolWithTag( PagedPool, (sizeof(ACCESS_MASK)+sizeof(NTSTATUS)) * ObjectTypeListLength, 'aGeS' );
  1109. if (LocalGrantedAccessPointer == NULL) {
  1110. SeUnlockSubjectContext( &SubjectSecurityContext );
  1111. Status = STATUS_INSUFFICIENT_RESOURCES;
  1112. goto Cleanup;
  1113. }
  1114. LocalGrantedAccessAllocated = TRUE;
  1115. LocalAccessStatusPointer = (PNTSTATUS)(LocalGrantedAccessPointer + ObjectTypeListLength);
  1116. for ( ResultListIndex=0; ResultListIndex<ObjectTypeListLength; ResultListIndex++ ) {
  1117. LocalGrantedAccessPointer[ResultListIndex] = LocalGrantedAccess;
  1118. LocalAccessStatusPointer[ResultListIndex] = LocalAccessStatus;
  1119. }
  1120. } else {
  1121. LocalGrantedAccessPointer = &LocalGrantedAccess;
  1122. LocalAccessStatusPointer = &LocalAccessStatus;
  1123. }
  1124. } else {
  1125. //
  1126. // If the user in the token is the owner of the object, we
  1127. // must automatically grant ReadControl and WriteDac access
  1128. // if desired. If the DesiredAccess mask is empty after
  1129. // these bits are turned off, we don't have to do any more
  1130. // access checking (ref section 4, DSA ACL Arch)
  1131. //
  1132. if ( DesiredAccess & (WRITE_DAC | READ_CONTROL | MAXIMUM_ALLOWED) ) {
  1133. if (SepTokenIsOwner( SubjectSecurityContext.ClientToken, CapturedSecurityDescriptor, TRUE )) {
  1134. if ( DesiredAccess & MAXIMUM_ALLOWED ) {
  1135. PreviouslyGrantedAccess |= ( WRITE_DAC | READ_CONTROL );
  1136. } else {
  1137. PreviouslyGrantedAccess |= (DesiredAccess & (WRITE_DAC | READ_CONTROL));
  1138. }
  1139. DesiredAccess &= ~(WRITE_DAC | READ_CONTROL);
  1140. }
  1141. }
  1142. if (DesiredAccess == 0) {
  1143. LocalGrantedAccess = PreviouslyGrantedAccess;
  1144. AccessGranted = TRUE;
  1145. AccessDenied = FALSE;
  1146. LocalAccessStatus = STATUS_SUCCESS;
  1147. if ( ReturnResultList ) {
  1148. ULONG ResultListIndex;
  1149. LocalGrantedAccessPointer =
  1150. ExAllocatePoolWithTag( PagedPool, (sizeof(ACCESS_MASK)+sizeof(NTSTATUS)) * ObjectTypeListLength, 'aGeS' );
  1151. if (LocalGrantedAccessPointer == NULL) {
  1152. Status = STATUS_INSUFFICIENT_RESOURCES;
  1153. SeUnlockSubjectContext( &SubjectSecurityContext );
  1154. goto Cleanup;
  1155. }
  1156. LocalGrantedAccessAllocated = TRUE;
  1157. LocalAccessStatusPointer = (PNTSTATUS)(LocalGrantedAccessPointer + ObjectTypeListLength);
  1158. for ( ResultListIndex=0; ResultListIndex<ObjectTypeListLength; ResultListIndex++ ) {
  1159. LocalGrantedAccessPointer[ResultListIndex] = LocalGrantedAccess;
  1160. LocalAccessStatusPointer[ResultListIndex] = LocalAccessStatus;
  1161. }
  1162. } else {
  1163. LocalGrantedAccessPointer = &LocalGrantedAccess;
  1164. LocalAccessStatusPointer = &LocalAccessStatus;
  1165. }
  1166. } else {
  1167. //
  1168. // Finally, do the access check
  1169. //
  1170. if ( ReturnResultList ) {
  1171. LocalGrantedAccessPointer =
  1172. ExAllocatePoolWithTag( PagedPool, (sizeof(ACCESS_MASK)+sizeof(NTSTATUS)) * ObjectTypeListLength, 'aGeS' );
  1173. if (LocalGrantedAccessPointer == NULL) {
  1174. Status = STATUS_INSUFFICIENT_RESOURCES;
  1175. SeUnlockSubjectContext( &SubjectSecurityContext );
  1176. goto Cleanup;
  1177. }
  1178. LocalGrantedAccessAllocated = TRUE;
  1179. LocalAccessStatusPointer = (PNTSTATUS)(LocalGrantedAccessPointer + ObjectTypeListLength);
  1180. } else {
  1181. LocalGrantedAccessPointer = &LocalGrantedAccess;
  1182. LocalAccessStatusPointer = &LocalAccessStatus;
  1183. }
  1184. //
  1185. // This does not ask for privilege set to be returned so we can ignore
  1186. // the return value of the call.
  1187. //
  1188. (VOID) SepAccessCheck (
  1189. CapturedSecurityDescriptor,
  1190. CapturedPrincipalSelfSid,
  1191. SubjectSecurityContext.PrimaryToken,
  1192. SubjectSecurityContext.ClientToken,
  1193. DesiredAccess,
  1194. LocalObjectTypeList,
  1195. ObjectTypeListLength,
  1196. &LocalGenericMapping,
  1197. PreviouslyGrantedAccess,
  1198. PreviousMode,
  1199. LocalGrantedAccessPointer,
  1200. NULL, // Privileges already checked
  1201. LocalAccessStatusPointer,
  1202. ReturnResultList,
  1203. &AccessGranted,
  1204. &AccessDenied
  1205. );
  1206. }
  1207. }
  1208. //
  1209. // sound the alarms...
  1210. //
  1211. if ( !AvoidAudit ) {
  1212. if ( SepAdtAuditThisEventEx( NtAuditType, AccessGranted, AccessDenied )) {
  1213. SepExamineSaclEx(
  1214. RtlpSaclAddrSecurityDescriptor( (PISECURITY_DESCRIPTOR)CapturedSecurityDescriptor ),
  1215. EffectiveToken( &SubjectSecurityContext ),
  1216. DesiredAccess | PreviouslyGrantedAccess,
  1217. LocalObjectTypeList,
  1218. ObjectTypeListLength,
  1219. ReturnResultList,
  1220. LocalAccessStatusPointer,
  1221. LocalGrantedAccessPointer,
  1222. CapturedPrincipalSelfSid,
  1223. &GenerateSuccessAudit,
  1224. &GenerateFailureAudit
  1225. );
  1226. }
  1227. if ( GenerateSuccessAudit ||
  1228. GenerateFailureAudit ) {
  1229. //
  1230. // Save this to a local here, so we don't
  1231. // have to risk accessing user memory and
  1232. // potentially having to exit before the audit
  1233. //
  1234. if ( AccessGranted ) {
  1235. //
  1236. // SAM calls NtCloseObjectAuditAlarm despite the fact that it may not
  1237. // have successfully opened the object, causing a spurious close audit.
  1238. // Since no one should rely on this anyway if their access attempt
  1239. // failed, make sure it's false and SAM will work properly.
  1240. //
  1241. LocalGenerateOnClose = TRUE;
  1242. }
  1243. //
  1244. // Generate the success audit if needed.
  1245. //
  1246. if ( GenerateSuccessAudit ) {
  1247. ExAllocateLocallyUniqueId( &OperationId );
  1248. // ??
  1249. ASSERT( AccessGranted );
  1250. AuditPerformed = SepAdtOpenObjectAuditAlarm (
  1251. CapturedSubsystemName,
  1252. AccessGranted ? &HandleId : NULL, // Don't audit handle if failure
  1253. CapturedObjectTypeName,
  1254. CapturedObjectName,
  1255. SubjectSecurityContext.ClientToken,
  1256. SubjectSecurityContext.PrimaryToken,
  1257. *LocalGrantedAccessPointer,
  1258. *LocalGrantedAccessPointer,
  1259. &OperationId,
  1260. PrivilegeSet,
  1261. TRUE, // Generate success case
  1262. PsProcessAuditId( PsGetCurrentProcess() ),
  1263. NtAuditType,
  1264. LocalObjectTypeList,
  1265. ObjectTypeListLength,
  1266. ReturnResultList ? LocalGrantedAccessPointer : NULL
  1267. );
  1268. }
  1269. //
  1270. // Generate failure audit if it is needed.
  1271. //
  1272. if ( GenerateFailureAudit ) {
  1273. ExAllocateLocallyUniqueId( &OperationId );
  1274. // ??
  1275. ASSERT( AccessDenied );
  1276. AuditPerformed = SepAdtOpenObjectAuditAlarm (
  1277. CapturedSubsystemName,
  1278. AccessGranted ? &HandleId : NULL, // Don't audit handle if failure
  1279. CapturedObjectTypeName,
  1280. CapturedObjectName,
  1281. SubjectSecurityContext.ClientToken,
  1282. SubjectSecurityContext.PrimaryToken,
  1283. DesiredAccess,
  1284. DesiredAccess,
  1285. &OperationId,
  1286. PrivilegeSet,
  1287. FALSE, // Generate failure case
  1288. PsProcessAuditId( PsGetCurrentProcess() ),
  1289. NtAuditType,
  1290. LocalObjectTypeList,
  1291. ObjectTypeListLength,
  1292. ReturnResultList ? LocalGrantedAccessPointer : NULL
  1293. );
  1294. }
  1295. } else {
  1296. //
  1297. // We didn't generate an audit due to the SACL. If privileges were used, we need
  1298. // to audit that.
  1299. //
  1300. if ( PrivilegeSet != NULL ) {
  1301. if ( SepAdtAuditThisEvent( AuditCategoryPrivilegeUse, &AccessGranted) ) {
  1302. AuditPerformed = SepAdtPrivilegeObjectAuditAlarm ( CapturedSubsystemName,
  1303. &HandleId,
  1304. SubjectSecurityContext.ClientToken,
  1305. SubjectSecurityContext.PrimaryToken,
  1306. PsProcessAuditId( PsGetCurrentProcess() ),
  1307. DesiredAccess,
  1308. PrivilegeSet,
  1309. AccessGranted
  1310. );
  1311. //
  1312. // We don't want close audits to be generated. May need to revisit this.
  1313. //
  1314. LocalGenerateOnClose = FALSE;
  1315. }
  1316. }
  1317. }
  1318. }
  1319. SeUnlockSubjectContext( &SubjectSecurityContext );
  1320. try {
  1321. if ( ReturnResultList ) {
  1322. ULONG ResultListIndex;
  1323. if ( LocalAccessStatusPointer == NULL ) {
  1324. for ( ResultListIndex=0; ResultListIndex<ObjectTypeListLength; ResultListIndex++ ) {
  1325. AccessStatus[ResultListIndex] = LocalAccessStatus;
  1326. GrantedAccess[ResultListIndex] = LocalGrantedAccess;
  1327. }
  1328. } else {
  1329. for ( ResultListIndex=0; ResultListIndex<ObjectTypeListLength; ResultListIndex++ ) {
  1330. AccessStatus[ResultListIndex] = LocalAccessStatusPointer[ResultListIndex];
  1331. GrantedAccess[ResultListIndex] = LocalGrantedAccessPointer[ResultListIndex];
  1332. }
  1333. }
  1334. } else {
  1335. *AccessStatus = LocalAccessStatus;
  1336. *GrantedAccess = LocalGrantedAccess;
  1337. }
  1338. *GenerateOnClose = LocalGenerateOnClose;
  1339. Status = STATUS_SUCCESS;
  1340. } except (EXCEPTION_EXECUTE_HANDLER) {
  1341. Status = GetExceptionCode();
  1342. }
  1343. //
  1344. // Free locally used resources.
  1345. //
  1346. Cleanup:
  1347. if ( TokenSwapped ) {
  1348. //
  1349. // Decrement the reference count for the ClientToken that was passed in.
  1350. //
  1351. ObDereferenceObject( (PVOID)NewToken );
  1352. //
  1353. // Reset the value of the token from saved value.
  1354. //
  1355. SubjectSecurityContext.ClientToken = OldToken;
  1356. }
  1357. //
  1358. // Free any privileges allocated as part of the access check
  1359. //
  1360. if (PrivilegeSet != NULL) {
  1361. ExFreePool( PrivilegeSet );
  1362. }
  1363. SeReleaseSubjectContext ( &SubjectSecurityContext );
  1364. SeReleaseSecurityDescriptor ( CapturedSecurityDescriptor,
  1365. PreviousMode,
  1366. FALSE );
  1367. if (CapturedSubsystemName != NULL) {
  1368. SepFreeCapturedString( CapturedSubsystemName );
  1369. }
  1370. if (CapturedObjectTypeName != NULL) {
  1371. SepFreeCapturedString( CapturedObjectTypeName );
  1372. }
  1373. if (CapturedObjectName != NULL) {
  1374. SepFreeCapturedString( CapturedObjectName );
  1375. }
  1376. if (CapturedPrincipalSelfSid != NULL) {
  1377. SeReleaseSid( CapturedPrincipalSelfSid, PreviousMode, TRUE);
  1378. }
  1379. if ( LocalObjectTypeList != NULL ) {
  1380. SeFreeCapturedObjectTypeList( LocalObjectTypeList );
  1381. }
  1382. if ( LocalGrantedAccessAllocated ) {
  1383. if ( LocalGrantedAccessPointer != NULL ) {
  1384. ExFreePool( LocalGrantedAccessPointer );
  1385. }
  1386. }
  1387. return Status;
  1388. }
  1389. NTSTATUS
  1390. NtAccessCheckAndAuditAlarm (
  1391. IN PUNICODE_STRING SubsystemName,
  1392. IN PVOID HandleId,
  1393. IN PUNICODE_STRING ObjectTypeName,
  1394. IN PUNICODE_STRING ObjectName,
  1395. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1396. IN ACCESS_MASK DesiredAccess,
  1397. IN PGENERIC_MAPPING GenericMapping,
  1398. IN BOOLEAN ObjectCreation,
  1399. OUT PACCESS_MASK GrantedAccess,
  1400. OUT PNTSTATUS AccessStatus,
  1401. OUT PBOOLEAN GenerateOnClose
  1402. )
  1403. /*++
  1404. Routine Description:
  1405. See SepAccessCheckAndAuditAlarm.
  1406. Arguments:
  1407. See SepAccessCheckAndAuditAlarm.
  1408. Return Value:
  1409. STATUS_SUCCESS - Indicates the call completed successfully. In this
  1410. case, ClientStatus receives the result of the access check.
  1411. STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have
  1412. sufficient privilege to use this privileged system service.
  1413. --*/
  1414. {
  1415. PAGED_CODE();
  1416. UNREFERENCED_PARAMETER( ObjectCreation );
  1417. return SepAccessCheckAndAuditAlarm(
  1418. SubsystemName,
  1419. HandleId,
  1420. NULL,
  1421. ObjectTypeName,
  1422. ObjectName,
  1423. SecurityDescriptor,
  1424. NULL, // No Principal Self sid
  1425. DesiredAccess,
  1426. AuditEventObjectAccess, // Default to ObjectAccess
  1427. 0, // No Flags
  1428. NULL, // No ObjectType List
  1429. 0, // No ObjectType List
  1430. GenericMapping,
  1431. GrantedAccess,
  1432. AccessStatus,
  1433. GenerateOnClose,
  1434. FALSE ); // Return a single GrantedAccess and AccessStatus
  1435. }
  1436. NTSTATUS
  1437. NtAccessCheckByTypeAndAuditAlarm (
  1438. IN PUNICODE_STRING SubsystemName,
  1439. IN PVOID HandleId,
  1440. IN PUNICODE_STRING ObjectTypeName,
  1441. IN PUNICODE_STRING ObjectName,
  1442. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1443. IN PSID PrincipalSelfSid,
  1444. IN ACCESS_MASK DesiredAccess,
  1445. IN AUDIT_EVENT_TYPE AuditType,
  1446. IN ULONG Flags,
  1447. IN POBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
  1448. IN ULONG ObjectTypeListLength,
  1449. IN PGENERIC_MAPPING GenericMapping,
  1450. IN BOOLEAN ObjectCreation,
  1451. OUT PACCESS_MASK GrantedAccess,
  1452. OUT PNTSTATUS AccessStatus,
  1453. OUT PBOOLEAN GenerateOnClose
  1454. )
  1455. /*++
  1456. Routine Description:
  1457. See SepAccessCheckAndAuditAlarm.
  1458. Arguments:
  1459. See SepAccessCheckAndAuditAlarm.
  1460. Return Value:
  1461. STATUS_SUCCESS - Indicates the call completed successfully. In this
  1462. case, ClientStatus receives the result of the access check.
  1463. STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have
  1464. sufficient privilege to use this privileged system service.
  1465. --*/
  1466. {
  1467. PAGED_CODE();
  1468. UNREFERENCED_PARAMETER( ObjectCreation );
  1469. return SepAccessCheckAndAuditAlarm(
  1470. SubsystemName,
  1471. HandleId,
  1472. NULL,
  1473. ObjectTypeName,
  1474. ObjectName,
  1475. SecurityDescriptor,
  1476. PrincipalSelfSid,
  1477. DesiredAccess,
  1478. AuditType,
  1479. Flags,
  1480. ObjectTypeList,
  1481. ObjectTypeListLength,
  1482. GenericMapping,
  1483. GrantedAccess,
  1484. AccessStatus,
  1485. GenerateOnClose,
  1486. FALSE ); // Return a single GrantedAccess and AccessStatus
  1487. }
  1488. NTSTATUS
  1489. NtAccessCheckByTypeResultListAndAuditAlarm (
  1490. IN PUNICODE_STRING SubsystemName,
  1491. IN PVOID HandleId,
  1492. IN PUNICODE_STRING ObjectTypeName,
  1493. IN PUNICODE_STRING ObjectName,
  1494. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1495. IN PSID PrincipalSelfSid,
  1496. IN ACCESS_MASK DesiredAccess,
  1497. IN AUDIT_EVENT_TYPE AuditType,
  1498. IN ULONG Flags,
  1499. IN POBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
  1500. IN ULONG ObjectTypeListLength,
  1501. IN PGENERIC_MAPPING GenericMapping,
  1502. IN BOOLEAN ObjectCreation,
  1503. OUT PACCESS_MASK GrantedAccess,
  1504. OUT PNTSTATUS AccessStatus,
  1505. OUT PBOOLEAN GenerateOnClose
  1506. )
  1507. /*++
  1508. Routine Description:
  1509. See SepAccessCheckAndAuditAlarm.
  1510. Arguments:
  1511. See SepAccessCheckAndAuditAlarm.
  1512. Return Value:
  1513. STATUS_SUCCESS - Indicates the call completed successfully. In this
  1514. case, ClientStatus receives the result of the access check.
  1515. STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have
  1516. sufficient privilege to use this privileged system service.
  1517. --*/
  1518. {
  1519. PAGED_CODE();
  1520. UNREFERENCED_PARAMETER( ObjectCreation );
  1521. return SepAccessCheckAndAuditAlarm(
  1522. SubsystemName,
  1523. HandleId,
  1524. NULL,
  1525. ObjectTypeName,
  1526. ObjectName,
  1527. SecurityDescriptor,
  1528. PrincipalSelfSid,
  1529. DesiredAccess,
  1530. AuditType,
  1531. Flags,
  1532. ObjectTypeList,
  1533. ObjectTypeListLength,
  1534. GenericMapping,
  1535. GrantedAccess,
  1536. AccessStatus,
  1537. GenerateOnClose,
  1538. TRUE ); // Return an array of GrantedAccess and AccessStatus
  1539. }
  1540. NTSTATUS
  1541. NtAccessCheckByTypeResultListAndAuditAlarmByHandle (
  1542. IN PUNICODE_STRING SubsystemName,
  1543. IN PVOID HandleId,
  1544. IN HANDLE ClientToken,
  1545. IN PUNICODE_STRING ObjectTypeName,
  1546. IN PUNICODE_STRING ObjectName,
  1547. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  1548. IN PSID PrincipalSelfSid,
  1549. IN ACCESS_MASK DesiredAccess,
  1550. IN AUDIT_EVENT_TYPE AuditType,
  1551. IN ULONG Flags,
  1552. IN POBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
  1553. IN ULONG ObjectTypeListLength,
  1554. IN PGENERIC_MAPPING GenericMapping,
  1555. IN BOOLEAN ObjectCreation,
  1556. OUT PACCESS_MASK GrantedAccess,
  1557. OUT PNTSTATUS AccessStatus,
  1558. OUT PBOOLEAN GenerateOnClose
  1559. )
  1560. /*++
  1561. Routine Description:
  1562. See SepAccessCheckAndAuditAlarm.
  1563. Arguments:
  1564. See SepAccessCheckAndAuditAlarm.
  1565. Return Value:
  1566. STATUS_SUCCESS - Indicates the call completed successfully. In this
  1567. case, ClientStatus receives the result of the access check.
  1568. STATUS_PRIVILEGE_NOT_HELD - Indicates the caller does not have
  1569. sufficient privilege to use this privileged system service.
  1570. --*/
  1571. {
  1572. PAGED_CODE();
  1573. UNREFERENCED_PARAMETER( ObjectCreation );
  1574. return SepAccessCheckAndAuditAlarm(
  1575. SubsystemName,
  1576. HandleId,
  1577. &ClientToken,
  1578. ObjectTypeName,
  1579. ObjectName,
  1580. SecurityDescriptor,
  1581. PrincipalSelfSid,
  1582. DesiredAccess,
  1583. AuditType,
  1584. Flags,
  1585. ObjectTypeList,
  1586. ObjectTypeListLength,
  1587. GenericMapping,
  1588. GrantedAccess,
  1589. AccessStatus,
  1590. GenerateOnClose,
  1591. TRUE ); // Return an array of GrantedAccess and AccessStatus
  1592. }
  1593. NTSTATUS
  1594. NtOpenObjectAuditAlarm (
  1595. IN PUNICODE_STRING SubsystemName,
  1596. IN PVOID HandleId OPTIONAL,
  1597. IN PUNICODE_STRING ObjectTypeName,
  1598. IN PUNICODE_STRING ObjectName,
  1599. IN PSECURITY_DESCRIPTOR SecurityDescriptor OPTIONAL,
  1600. IN HANDLE ClientToken,
  1601. IN ACCESS_MASK DesiredAccess,
  1602. IN ACCESS_MASK GrantedAccess,
  1603. IN PPRIVILEGE_SET Privileges OPTIONAL,
  1604. IN BOOLEAN ObjectCreation,
  1605. IN BOOLEAN AccessGranted,
  1606. OUT PBOOLEAN GenerateOnClose
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. This routine is used to generate audit and alarm messages when an
  1611. attempt is made to access an existing protected subsystem object or
  1612. create a new one. This routine may result in several messages being
  1613. generated and sent to Port objects. This may result in a significant
  1614. latency before returning. Design of routines that must call this
  1615. routine must take this potential latency into account. This may have
  1616. an impact on the approach taken for data structure mutex locking, for
  1617. example.
  1618. This routine may not be able to generate a complete audit record
  1619. due to memory restrictions.
  1620. This API requires the caller have SeAuditPrivilege privilege. The test
  1621. for this privilege is always against the primary token of the calling
  1622. process, not the impersonation token of the thread.
  1623. Arguments:
  1624. SubsystemName - Supplies a name string identifying the
  1625. subsystem calling the routine.
  1626. HandleId - A unique value representing the client's handle to the
  1627. object. If the access attempt was not successful (AccessGranted is
  1628. FALSE), then this parameter is ignored.
  1629. ObjectTypeName - Supplies the name of the type of object being
  1630. accessed.
  1631. ObjectName - Supplies the name of the object the client
  1632. accessed or attempted to access.
  1633. SecurityDescriptor - An optional pointer to the security descriptor of
  1634. the object being accessed.
  1635. ClientToken - A handle to a token object representing the client that
  1636. requested the operation. This handle must be obtained from a
  1637. communication session layer, such as from an LPC Port or Local
  1638. Named Pipe, to prevent possible security policy violations.
  1639. DesiredAccess - The desired access mask. This mask must have been
  1640. previously mapped to contain no generic accesses.
  1641. GrantedAccess - The mask of accesses that were actually granted.
  1642. Privileges - Optionally points to a set of privileges that were
  1643. required for the access attempt. Those privileges that were held
  1644. by the subject are marked using the UsedForAccess flag of the
  1645. attributes associated with each privilege.
  1646. ObjectCreation - A boolean flag indicating whether the access will
  1647. result in a new object being created if granted. A value of TRUE
  1648. indicates an object will be created, FALSE indicates an existing
  1649. object will be opened.
  1650. AccessGranted - Indicates whether the requested access was granted or
  1651. not. A value of TRUE indicates the access was granted. A value of
  1652. FALSE indicates the access was not granted.
  1653. GenerateOnClose - Points to a boolean that is set by the audit
  1654. generation routine and must be passed to NtCloseObjectAuditAlarm()
  1655. when the object handle is closed.
  1656. Return Value:
  1657. --*/
  1658. {
  1659. KPROCESSOR_MODE PreviousMode;
  1660. ULONG PrivilegeParameterLength;
  1661. PUNICODE_STRING CapturedSubsystemName = (PUNICODE_STRING) NULL;
  1662. PUNICODE_STRING CapturedObjectTypeName = (PUNICODE_STRING) NULL;
  1663. PUNICODE_STRING CapturedObjectName = (PUNICODE_STRING) NULL;
  1664. PSECURITY_DESCRIPTOR CapturedSecurityDescriptor = (PSECURITY_DESCRIPTOR) NULL;
  1665. PPRIVILEGE_SET CapturedPrivileges = NULL;
  1666. BOOLEAN LocalGenerateOnClose = FALSE;
  1667. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  1668. BOOLEAN Result;
  1669. NTSTATUS Status;
  1670. BOOLEAN GenerateAudit = FALSE;
  1671. BOOLEAN GenerateAlarm = FALSE;
  1672. PLUID ClientAuthenticationId = NULL;
  1673. HANDLE CapturedHandleId = NULL;
  1674. BOOLEAN AuditPerformed;
  1675. ULONG PrivilegeCount;
  1676. PTOKEN Token;
  1677. PAGED_CODE();
  1678. UNREFERENCED_PARAMETER( ObjectCreation );
  1679. PreviousMode = KeGetPreviousMode();
  1680. ASSERT( PreviousMode != KernelMode );
  1681. Status = ObReferenceObjectByHandle( ClientToken, // Handle
  1682. TOKEN_QUERY, // DesiredAccess
  1683. SeTokenObjectType, // ObjectType
  1684. PreviousMode, // AccessMode
  1685. (PVOID *)&Token, // Object
  1686. NULL // GrantedAccess
  1687. );
  1688. if (!NT_SUCCESS(Status)) {
  1689. return( Status );
  1690. }
  1691. //
  1692. // If the passed token is an impersonation token, make sure
  1693. // it is at SecurityIdentification or above.
  1694. //
  1695. if (Token->TokenType == TokenImpersonation) {
  1696. if (Token->ImpersonationLevel < SecurityIdentification) {
  1697. ObDereferenceObject( (PVOID)Token );
  1698. return( STATUS_BAD_IMPERSONATION_LEVEL );
  1699. }
  1700. }
  1701. //
  1702. // Check for SeAuditPrivilege. This must be tested against
  1703. // the caller's primary token.
  1704. //
  1705. SeCaptureSubjectContext ( &SubjectSecurityContext );
  1706. Result = SeCheckAuditPrivilege (
  1707. &SubjectSecurityContext,
  1708. PreviousMode
  1709. );
  1710. if (!Result) {
  1711. ObDereferenceObject( (PVOID)Token );
  1712. SeReleaseSubjectContext ( &SubjectSecurityContext );
  1713. return(STATUS_PRIVILEGE_NOT_HELD);
  1714. }
  1715. //
  1716. // This will just return NULL if the input descriptor is NULL
  1717. //
  1718. Status = SeCaptureSecurityDescriptor ( SecurityDescriptor,
  1719. PreviousMode,
  1720. PagedPool,
  1721. FALSE,
  1722. &CapturedSecurityDescriptor
  1723. );
  1724. //
  1725. // At this point in time, if there's no security descriptor, there's
  1726. // nothing to do. Return success.
  1727. //
  1728. if (!NT_SUCCESS( Status ) || CapturedSecurityDescriptor == NULL) {
  1729. ObDereferenceObject( (PVOID)Token );
  1730. SeReleaseSubjectContext ( &SubjectSecurityContext );
  1731. return( Status );
  1732. }
  1733. try {
  1734. //
  1735. // Only capture the privileges if we've completed a successful
  1736. // access check. Otherwise they don't mean anything.
  1737. //
  1738. if (AccessGranted && ARGUMENT_PRESENT(Privileges)) {
  1739. ProbeForReadSmallStructure(
  1740. Privileges,
  1741. sizeof(PRIVILEGE_SET),
  1742. sizeof(ULONG)
  1743. );
  1744. PrivilegeCount = Privileges->PrivilegeCount;
  1745. if (!IsValidPrivilegeCount( PrivilegeCount )) {
  1746. Status = STATUS_INVALID_PARAMETER;
  1747. leave;
  1748. }
  1749. PrivilegeParameterLength = (ULONG)sizeof(PRIVILEGE_SET) +
  1750. ((PrivilegeCount - ANYSIZE_ARRAY) *
  1751. (ULONG)sizeof(LUID_AND_ATTRIBUTES) );
  1752. ProbeForRead(
  1753. Privileges,
  1754. PrivilegeParameterLength,
  1755. sizeof(ULONG)
  1756. );
  1757. CapturedPrivileges = ExAllocatePoolWithTag( PagedPool,
  1758. PrivilegeParameterLength,
  1759. 'rPeS'
  1760. );
  1761. if (CapturedPrivileges != NULL) {
  1762. RtlCopyMemory ( CapturedPrivileges,
  1763. Privileges,
  1764. PrivilegeParameterLength );
  1765. CapturedPrivileges->PrivilegeCount = PrivilegeCount;
  1766. } else {
  1767. SeReleaseSecurityDescriptor ( CapturedSecurityDescriptor,
  1768. PreviousMode,
  1769. FALSE );
  1770. ObDereferenceObject( (PVOID)Token );
  1771. SeReleaseSubjectContext ( &SubjectSecurityContext );
  1772. return( STATUS_INSUFFICIENT_RESOURCES );
  1773. }
  1774. }
  1775. if (ARGUMENT_PRESENT( HandleId )) {
  1776. ProbeForReadSmallStructure( (PHANDLE)HandleId, sizeof(PVOID), sizeof(PVOID) );
  1777. CapturedHandleId = *(PHANDLE)HandleId;
  1778. }
  1779. ProbeForWriteBoolean(GenerateOnClose);
  1780. //
  1781. // Probe and Capture the parameter strings.
  1782. // If we run out of memory attempting to capture
  1783. // the strings, the returned pointer will be
  1784. // NULL and we will continue with the audit.
  1785. //
  1786. SepProbeAndCaptureString_U ( SubsystemName,
  1787. &CapturedSubsystemName );
  1788. SepProbeAndCaptureString_U ( ObjectTypeName,
  1789. &CapturedObjectTypeName );
  1790. SepProbeAndCaptureString_U ( ObjectName,
  1791. &CapturedObjectName );
  1792. } except(EXCEPTION_EXECUTE_HANDLER) {
  1793. Status = GetExceptionCode();
  1794. }
  1795. if (!NT_SUCCESS(Status)) {
  1796. if (CapturedSubsystemName != NULL) {
  1797. SepFreeCapturedString( CapturedSubsystemName );
  1798. }
  1799. if (CapturedObjectTypeName != NULL) {
  1800. SepFreeCapturedString( CapturedObjectTypeName );
  1801. }
  1802. if (CapturedObjectName != NULL) {
  1803. SepFreeCapturedString( CapturedObjectName );
  1804. }
  1805. if (CapturedPrivileges != NULL) {
  1806. ExFreePool( CapturedPrivileges );
  1807. }
  1808. if (CapturedSecurityDescriptor != NULL) {
  1809. SeReleaseSecurityDescriptor ( CapturedSecurityDescriptor,
  1810. PreviousMode,
  1811. FALSE );
  1812. }
  1813. ObDereferenceObject( (PVOID)Token );
  1814. SeReleaseSubjectContext ( &SubjectSecurityContext );
  1815. return Status;
  1816. }
  1817. if ( SepAdtAuditThisEvent( AuditCategoryObjectAccess, &AccessGranted) ) {
  1818. SepExamineSacl(
  1819. RtlpSaclAddrSecurityDescriptor( (PISECURITY_DESCRIPTOR)CapturedSecurityDescriptor ),
  1820. Token,
  1821. DesiredAccess | GrantedAccess,
  1822. AccessGranted,
  1823. &GenerateAudit,
  1824. &GenerateAlarm
  1825. );
  1826. if (GenerateAudit || GenerateAlarm) {
  1827. //
  1828. // Take a read lock on the token, because we're going to extract
  1829. // the user's Sid from it.
  1830. //
  1831. LocalGenerateOnClose = TRUE;
  1832. AuditPerformed = SepAdtOpenObjectAuditAlarm ( CapturedSubsystemName,
  1833. ARGUMENT_PRESENT(HandleId) ? (PVOID)&CapturedHandleId : NULL,
  1834. CapturedObjectTypeName,
  1835. CapturedObjectName,
  1836. Token,
  1837. SubjectSecurityContext.PrimaryToken,
  1838. DesiredAccess,
  1839. GrantedAccess,
  1840. NULL,
  1841. CapturedPrivileges,
  1842. AccessGranted,
  1843. PsProcessAuditId( PsGetCurrentProcess() ),
  1844. AuditCategoryObjectAccess,
  1845. NULL,
  1846. 0,
  1847. NULL
  1848. );
  1849. LocalGenerateOnClose = AuditPerformed;
  1850. }
  1851. }
  1852. if ( !(GenerateAudit || GenerateAlarm) ) {
  1853. //
  1854. // We didn't attempt to generate an audit above, so if privileges were used,
  1855. // see if we should generate an audit here.
  1856. //
  1857. if ( ARGUMENT_PRESENT(Privileges) ) {
  1858. if ( SepAdtAuditThisEvent( AuditCategoryPrivilegeUse, &AccessGranted) ) {
  1859. AuditPerformed = SepAdtPrivilegeObjectAuditAlarm ( CapturedSubsystemName,
  1860. CapturedHandleId,
  1861. Token,
  1862. SubjectSecurityContext.PrimaryToken,
  1863. PsProcessAuditId( PsGetCurrentProcess() ),
  1864. DesiredAccess,
  1865. CapturedPrivileges,
  1866. AccessGranted
  1867. );
  1868. //
  1869. // If we generate an audit due to use of privilege, don't set generate on close,
  1870. // because then we'll have a close audit without a corresponding open audit.
  1871. //
  1872. LocalGenerateOnClose = FALSE;
  1873. }
  1874. }
  1875. }
  1876. if (CapturedSecurityDescriptor != NULL) {
  1877. SeReleaseSecurityDescriptor ( CapturedSecurityDescriptor,
  1878. PreviousMode,
  1879. FALSE );
  1880. }
  1881. if (CapturedSubsystemName != NULL) {
  1882. SepFreeCapturedString( CapturedSubsystemName );
  1883. }
  1884. if (CapturedObjectTypeName != NULL) {
  1885. SepFreeCapturedString( CapturedObjectTypeName );
  1886. }
  1887. if (CapturedObjectName != NULL) {
  1888. SepFreeCapturedString( CapturedObjectName );
  1889. }
  1890. if (CapturedPrivileges != NULL) {
  1891. ExFreePool( CapturedPrivileges );
  1892. }
  1893. ObDereferenceObject( (PVOID)Token );
  1894. SeReleaseSubjectContext ( &SubjectSecurityContext );
  1895. try {
  1896. *GenerateOnClose = LocalGenerateOnClose;
  1897. } except (EXCEPTION_EXECUTE_HANDLER) {
  1898. return GetExceptionCode();
  1899. }
  1900. return(STATUS_SUCCESS);
  1901. }
  1902. NTSTATUS
  1903. NtCloseObjectAuditAlarm (
  1904. IN PUNICODE_STRING SubsystemName,
  1905. IN PVOID HandleId,
  1906. IN BOOLEAN GenerateOnClose
  1907. )
  1908. /*++
  1909. Routine Description:
  1910. This routine is used to generate audit and alarm messages when a handle
  1911. to a protected subsystem object is deleted. This routine may result in
  1912. several messages being generated and sent to Port objects. This may
  1913. result in a significant latency before returning. Design of routines
  1914. that must call this routine must take this potential latency into
  1915. account. This may have an impact on the approach taken for data
  1916. structure mutex locking, for example.
  1917. This API requires the caller have SeAuditPrivilege privilege. The test
  1918. for this privilege is always against the primary token of the calling
  1919. process, allowing the caller to be impersonating a client during the
  1920. call with no ill effects.
  1921. Arguments:
  1922. SubsystemName - Supplies a name string identifying the subsystem
  1923. calling the routine.
  1924. HandleId - A unique value representing the client's handle to the
  1925. object.
  1926. GenerateOnClose - Is a boolean value returned from a corresponding
  1927. NtAccessCheckAndAuditAlarm() call or NtOpenObjectAuditAlarm() call
  1928. when the object handle was created.
  1929. Return value:
  1930. --*/
  1931. {
  1932. BOOLEAN Result;
  1933. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  1934. KPROCESSOR_MODE PreviousMode;
  1935. PUNICODE_STRING CapturedSubsystemName = NULL;
  1936. PSID UserSid;
  1937. PSID CapturedUserSid = NULL;
  1938. NTSTATUS Status;
  1939. PAGED_CODE();
  1940. PreviousMode = KeGetPreviousMode();
  1941. ASSERT(PreviousMode != KernelMode);
  1942. if (!GenerateOnClose) {
  1943. return( STATUS_SUCCESS );
  1944. }
  1945. //
  1946. // Check for SeAuditPrivilege
  1947. //
  1948. SeCaptureSubjectContext ( &SubjectSecurityContext );
  1949. Result = SeCheckAuditPrivilege (
  1950. &SubjectSecurityContext,
  1951. PreviousMode
  1952. );
  1953. if (!Result) {
  1954. Status = STATUS_PRIVILEGE_NOT_HELD;
  1955. goto Cleanup;
  1956. }
  1957. UserSid = SepTokenUserSid( EffectiveToken (&SubjectSecurityContext));
  1958. CapturedUserSid = ExAllocatePoolWithTag(
  1959. PagedPool,
  1960. SeLengthSid( UserSid ),
  1961. 'iSeS'
  1962. );
  1963. if ( CapturedUserSid == NULL ) {
  1964. Status = STATUS_INSUFFICIENT_RESOURCES;
  1965. goto Cleanup;
  1966. }
  1967. Status = RtlCopySid (
  1968. SeLengthSid( UserSid ),
  1969. CapturedUserSid,
  1970. UserSid
  1971. );
  1972. ASSERT( NT_SUCCESS( Status ));
  1973. try {
  1974. SepProbeAndCaptureString_U ( SubsystemName,
  1975. &CapturedSubsystemName );
  1976. } except (EXCEPTION_EXECUTE_HANDLER) {
  1977. Status = GetExceptionCode();
  1978. goto Cleanup;
  1979. }
  1980. //
  1981. // This routine will check to see if auditing is enabled
  1982. //
  1983. SepAdtCloseObjectAuditAlarm( CapturedSubsystemName, HandleId, CapturedUserSid );
  1984. Status = STATUS_SUCCESS;
  1985. Cleanup:
  1986. if ( CapturedSubsystemName != NULL ) {
  1987. SepFreeCapturedString( CapturedSubsystemName );
  1988. }
  1989. if ( CapturedUserSid != NULL ) {
  1990. ExFreePool( CapturedUserSid );
  1991. }
  1992. SeReleaseSubjectContext ( &SubjectSecurityContext );
  1993. return Status;
  1994. }
  1995. NTSTATUS
  1996. NtDeleteObjectAuditAlarm (
  1997. IN PUNICODE_STRING SubsystemName,
  1998. IN PVOID HandleId,
  1999. IN BOOLEAN GenerateOnClose
  2000. )
  2001. /*++
  2002. Routine Description:
  2003. This routine is used to generate audit and alarm messages when an object
  2004. in a protected subsystem object is deleted. This routine may result in
  2005. several messages being generated and sent to Port objects. This may
  2006. result in a significant latency before returning. Design of routines
  2007. that must call this routine must take this potential latency into
  2008. account. This may have an impact on the approach taken for data
  2009. structure mutex locking, for example.
  2010. This API requires the caller have SeAuditPrivilege privilege. The test
  2011. for this privilege is always against the primary token of the calling
  2012. process, allowing the caller to be impersonating a client during the
  2013. call with no ill effects.
  2014. Arguments:
  2015. SubsystemName - Supplies a name string identifying the subsystem
  2016. calling the routine.
  2017. HandleId - A unique value representing the client's handle to the
  2018. object.
  2019. GenerateOnClose - Is a boolean value returned from a corresponding
  2020. NtAccessCheckAndAuditAlarm() call or NtOpenObjectAuditAlarm() call
  2021. when the object handle was created.
  2022. Return value:
  2023. --*/
  2024. {
  2025. BOOLEAN Result;
  2026. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  2027. KPROCESSOR_MODE PreviousMode;
  2028. PUNICODE_STRING CapturedSubsystemName = NULL;
  2029. PSID UserSid;
  2030. PSID CapturedUserSid;
  2031. NTSTATUS Status;
  2032. PAGED_CODE();
  2033. PreviousMode = KeGetPreviousMode();
  2034. ASSERT(PreviousMode != KernelMode);
  2035. if (!GenerateOnClose) {
  2036. return( STATUS_SUCCESS );
  2037. }
  2038. //
  2039. // Check for SeAuditPrivilege
  2040. //
  2041. SeCaptureSubjectContext ( &SubjectSecurityContext );
  2042. Result = SeCheckAuditPrivilege (
  2043. &SubjectSecurityContext,
  2044. PreviousMode
  2045. );
  2046. if (!Result) {
  2047. SeReleaseSubjectContext ( &SubjectSecurityContext );
  2048. return(STATUS_PRIVILEGE_NOT_HELD);
  2049. }
  2050. UserSid = SepTokenUserSid( EffectiveToken (&SubjectSecurityContext));
  2051. CapturedUserSid = ExAllocatePoolWithTag(
  2052. PagedPool,
  2053. SeLengthSid( UserSid ),
  2054. 'iSeS'
  2055. );
  2056. if ( CapturedUserSid == NULL ) {
  2057. SeReleaseSubjectContext ( &SubjectSecurityContext );
  2058. return( STATUS_INSUFFICIENT_RESOURCES );
  2059. }
  2060. Status = RtlCopySid (
  2061. SeLengthSid( UserSid ),
  2062. CapturedUserSid,
  2063. UserSid
  2064. );
  2065. ASSERT( NT_SUCCESS( Status ));
  2066. try {
  2067. SepProbeAndCaptureString_U ( SubsystemName,
  2068. &CapturedSubsystemName );
  2069. } except (EXCEPTION_EXECUTE_HANDLER) {
  2070. if ( CapturedSubsystemName != NULL ) {
  2071. SepFreeCapturedString( CapturedSubsystemName );
  2072. }
  2073. ExFreePool( CapturedUserSid );
  2074. SeReleaseSubjectContext ( &SubjectSecurityContext );
  2075. return GetExceptionCode();
  2076. }
  2077. //
  2078. // This routine will check to see if auditing is enabled
  2079. //
  2080. SepAdtDeleteObjectAuditAlarm ( CapturedSubsystemName,
  2081. HandleId,
  2082. CapturedUserSid
  2083. );
  2084. SeReleaseSubjectContext ( &SubjectSecurityContext );
  2085. if ( CapturedSubsystemName != NULL ) {
  2086. SepFreeCapturedString( CapturedSubsystemName );
  2087. }
  2088. ExFreePool( CapturedUserSid );
  2089. return(STATUS_SUCCESS);
  2090. }
  2091. VOID
  2092. SeOpenObjectAuditAlarm (
  2093. IN PUNICODE_STRING ObjectTypeName,
  2094. IN PVOID Object OPTIONAL,
  2095. IN PUNICODE_STRING AbsoluteObjectName OPTIONAL,
  2096. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  2097. IN PACCESS_STATE AccessState,
  2098. IN BOOLEAN ObjectCreated,
  2099. IN BOOLEAN AccessGranted,
  2100. IN KPROCESSOR_MODE AccessMode,
  2101. OUT PBOOLEAN GenerateOnClose
  2102. )
  2103. /*++
  2104. Routine Description:
  2105. SeOpenObjectAuditAlarm is used by the object manager that open objects
  2106. to generate any necessary audit or alarm messages. The open may be to
  2107. existing objects or for newly created objects. No messages will be
  2108. generated for Kernel mode accesses.
  2109. This routine is used to generate audit and alarm messages when an
  2110. attempt is made to open an object.
  2111. This routine may result in several messages being generated and sent to
  2112. Port objects. This may result in a significant latency before
  2113. returning. Design of routines that must call this routine must take
  2114. this potential latency into account. This may have an impact on the
  2115. approach taken for data structure mutex locking, for example.
  2116. Arguments:
  2117. ObjectTypeName - Supplies the name of the type of object being
  2118. accessed. This must be the same name provided to the
  2119. ObCreateObjectType service when the object type was created.
  2120. Object - Address of the object accessed. This value will not be used
  2121. as a pointer (referenced). It is necessary only to enter into log
  2122. messages. If the open was not successful, then this argument is
  2123. ignored. Otherwise, it must be provided.
  2124. AbsoluteObjectName - Supplies the name of the object being accessed.
  2125. If the object doesn't have a name, then this field is left null.
  2126. Otherwise, it must be provided.
  2127. SecurityDescriptor - A pointer to the security descriptor of the
  2128. object being accessed.
  2129. AccessState - A pointer to an access state structure containing the
  2130. subject context, the remaining desired access types, the granted
  2131. access types, and optionally a privilege set to indicate which
  2132. privileges were used to permit the access.
  2133. ObjectCreated - A boolean flag indicating whether the access resulted
  2134. in a new object being created. A value of TRUE indicates an object
  2135. was created, FALSE indicates an existing object was opened.
  2136. AccessGranted - Indicates if the access was granted or denied based on
  2137. the access check or privilege check.
  2138. AccessMode - Indicates the access mode used for the access check. One
  2139. of UserMode or KernelMode. Messages will not be generated by
  2140. kernel mode accesses.
  2141. GenerateOnClose - Points to a boolean that is set by the audit
  2142. generation routine and must be passed to SeCloseObjectAuditAlarm()
  2143. when the object handle is closed.
  2144. Return value:
  2145. None.
  2146. --*/
  2147. {
  2148. BOOLEAN GenerateAudit = FALSE;
  2149. BOOLEAN GenerateAlarm = FALSE;
  2150. ACCESS_MASK RequestedAccess;
  2151. POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
  2152. PUNICODE_STRING ObjectTypeNameInfo = NULL;
  2153. PUNICODE_STRING ObjectName = NULL;
  2154. PUNICODE_STRING LocalObjectTypeName = NULL;
  2155. PLUID PrimaryAuthenticationId = NULL;
  2156. PLUID ClientAuthenticationId = NULL;
  2157. BOOLEAN AuditPrivileges = FALSE;
  2158. BOOLEAN AuditPerformed;
  2159. PTOKEN Token;
  2160. ACCESS_MASK MappedGrantMask = (ACCESS_MASK)0;
  2161. ACCESS_MASK MappedDenyMask = (ACCESS_MASK)0;
  2162. PAUX_ACCESS_DATA AuxData;
  2163. PAGED_CODE();
  2164. UNREFERENCED_PARAMETER( ObjectCreated );
  2165. if ( AccessMode == KernelMode ) {
  2166. return;
  2167. }
  2168. AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
  2169. Token = EffectiveToken( &AccessState->SubjectSecurityContext );
  2170. if (ARGUMENT_PRESENT(Token->AuditData)) {
  2171. MappedGrantMask = Token->AuditData->GrantMask;
  2172. RtlMapGenericMask(
  2173. &MappedGrantMask,
  2174. &AuxData->GenericMapping
  2175. );
  2176. MappedDenyMask = Token->AuditData->DenyMask;
  2177. RtlMapGenericMask(
  2178. &MappedDenyMask,
  2179. &AuxData->GenericMapping
  2180. );
  2181. }
  2182. if (SecurityDescriptor != NULL) {
  2183. RequestedAccess = AccessState->RemainingDesiredAccess |
  2184. AccessState->PreviouslyGrantedAccess;
  2185. if ( SepAdtAuditThisEvent( AuditCategoryObjectAccess, &AccessGranted )) {
  2186. if ( RequestedAccess & (AccessGranted ? MappedGrantMask : MappedDenyMask)) {
  2187. GenerateAudit = TRUE;
  2188. } else {
  2189. SepExamineSacl(
  2190. RtlpSaclAddrSecurityDescriptor( (PISECURITY_DESCRIPTOR)SecurityDescriptor ),
  2191. Token,
  2192. RequestedAccess,
  2193. AccessGranted,
  2194. &GenerateAudit,
  2195. &GenerateAlarm
  2196. );
  2197. }
  2198. //
  2199. // Only generate an audit on close of we're auditing from SACL
  2200. // settings.
  2201. //
  2202. if (GenerateAudit) {
  2203. *GenerateOnClose = TRUE;
  2204. //
  2205. // Construct the audit mask that will be placed into the handle.
  2206. //
  2207. if (AccessGranted) {
  2208. SeMaximumAuditMask(
  2209. RtlpSaclAddrSecurityDescriptor( (PISECURITY_DESCRIPTOR)SecurityDescriptor ),
  2210. RequestedAccess,
  2211. Token,
  2212. &AuxData->MaximumAuditMask
  2213. );
  2214. }
  2215. }
  2216. }
  2217. }
  2218. //
  2219. // If we don't generate an audit via the SACL, see if we need to generate
  2220. // one for privilege use.
  2221. //
  2222. // Note that we only audit privileges successfully used to open objects,
  2223. // so we don't care about a failed privilege use here. Therefore, only
  2224. // do this test of access has been granted.
  2225. //
  2226. if (!GenerateAudit && (AccessGranted == TRUE)) {
  2227. if ( SepAdtAuditThisEvent( AuditCategoryPrivilegeUse, &AccessGranted )) {
  2228. if ((AuxData->PrivilegesUsed != NULL) &&
  2229. (AuxData->PrivilegesUsed->PrivilegeCount > 0) ) {
  2230. //
  2231. // Make sure these are actually privileges that we want to audit
  2232. //
  2233. if (SepFilterPrivilegeAudits( AuxData->PrivilegesUsed )) {
  2234. GenerateAudit = TRUE;
  2235. //
  2236. // When we finally try to generate this audit, this flag
  2237. // will tell us that we need to audit the fact that we
  2238. // used a privilege, as opposed to audit due to the SACL.
  2239. //
  2240. AccessState->AuditPrivileges = TRUE;
  2241. }
  2242. }
  2243. }
  2244. }
  2245. //
  2246. // Set up either to generate an audit (if the access check has failed), or save
  2247. // the stuff that we're going to audit later into the AccessState structure.
  2248. //
  2249. if (GenerateAudit || GenerateAlarm) {
  2250. AccessState->GenerateAudit = TRUE;
  2251. //
  2252. // Figure out what we've been passed, and obtain as much
  2253. // missing information as possible.
  2254. //
  2255. if ( !ARGUMENT_PRESENT( AbsoluteObjectName )) {
  2256. if ( ARGUMENT_PRESENT( Object )) {
  2257. ObjectNameInfo = SepQueryNameString( Object );
  2258. if ( ObjectNameInfo != NULL ) {
  2259. ObjectName = &ObjectNameInfo->Name;
  2260. }
  2261. }
  2262. } else {
  2263. ObjectName = AbsoluteObjectName;
  2264. }
  2265. if ( !ARGUMENT_PRESENT( ObjectTypeName )) {
  2266. if ( ARGUMENT_PRESENT( Object )) {
  2267. ObjectTypeNameInfo = SepQueryTypeString( Object );
  2268. if ( ObjectTypeNameInfo != NULL ) {
  2269. LocalObjectTypeName = ObjectTypeNameInfo;
  2270. }
  2271. }
  2272. } else {
  2273. LocalObjectTypeName = ObjectTypeName;
  2274. }
  2275. //
  2276. // If the access attempt failed, do the audit here. If it succeeded,
  2277. // we'll do the audit later, when the handle is allocated.
  2278. //
  2279. //
  2280. if (!AccessGranted) {
  2281. AuditPerformed = SepAdtOpenObjectAuditAlarm ( (PUNICODE_STRING)&SeSubsystemName,
  2282. NULL,
  2283. LocalObjectTypeName,
  2284. ObjectName,
  2285. AccessState->SubjectSecurityContext.ClientToken,
  2286. AccessState->SubjectSecurityContext.PrimaryToken,
  2287. AccessState->OriginalDesiredAccess,
  2288. AccessState->PreviouslyGrantedAccess,
  2289. &AccessState->OperationID,
  2290. AuxData->PrivilegesUsed,
  2291. FALSE,
  2292. AccessState->SubjectSecurityContext.ProcessAuditId,
  2293. AuditCategoryObjectAccess,
  2294. NULL,
  2295. 0,
  2296. NULL );
  2297. } else {
  2298. //
  2299. // Copy all the stuff we're going to need into the
  2300. // AccessState and return.
  2301. //
  2302. if ( ObjectName != NULL ) {
  2303. if ( AccessState->ObjectName.Buffer != NULL ) {
  2304. ExFreePool( AccessState->ObjectName.Buffer );
  2305. AccessState->ObjectName.Length = 0;
  2306. AccessState->ObjectName.MaximumLength = 0;
  2307. }
  2308. AccessState->ObjectName.Buffer = ExAllocatePool( PagedPool,ObjectName->MaximumLength );
  2309. if (AccessState->ObjectName.Buffer != NULL) {
  2310. AccessState->ObjectName.MaximumLength = ObjectName->MaximumLength;
  2311. RtlCopyUnicodeString( &AccessState->ObjectName, ObjectName );
  2312. }
  2313. }
  2314. if ( LocalObjectTypeName != NULL ) {
  2315. if ( AccessState->ObjectTypeName.Buffer != NULL ) {
  2316. ExFreePool( AccessState->ObjectTypeName.Buffer );
  2317. AccessState->ObjectTypeName.Length = 0;
  2318. AccessState->ObjectTypeName.MaximumLength = 0;
  2319. }
  2320. AccessState->ObjectTypeName.Buffer = ExAllocatePool( PagedPool, LocalObjectTypeName->MaximumLength );
  2321. if (AccessState->ObjectTypeName.Buffer != NULL) {
  2322. AccessState->ObjectTypeName.MaximumLength = LocalObjectTypeName->MaximumLength;
  2323. RtlCopyUnicodeString( &AccessState->ObjectTypeName, LocalObjectTypeName );
  2324. }
  2325. }
  2326. }
  2327. if ( ObjectNameInfo != NULL ) {
  2328. ExFreePool( ObjectNameInfo );
  2329. }
  2330. if ( ObjectTypeNameInfo != NULL ) {
  2331. ExFreePool( ObjectTypeNameInfo );
  2332. }
  2333. }
  2334. return;
  2335. }
  2336. VOID
  2337. SeOpenObjectForDeleteAuditAlarm (
  2338. IN PUNICODE_STRING ObjectTypeName,
  2339. IN PVOID Object OPTIONAL,
  2340. IN PUNICODE_STRING AbsoluteObjectName OPTIONAL,
  2341. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  2342. IN PACCESS_STATE AccessState,
  2343. IN BOOLEAN ObjectCreated,
  2344. IN BOOLEAN AccessGranted,
  2345. IN KPROCESSOR_MODE AccessMode,
  2346. OUT PBOOLEAN GenerateOnClose
  2347. )
  2348. /*++
  2349. Routine Description:
  2350. SeOpenObjectForDeleteAuditAlarm is used by the object manager that open
  2351. objects to generate any necessary audit or alarm messages. The open may
  2352. be to existing objects or for newly created objects. No messages will be
  2353. generated for Kernel mode accesses.
  2354. This routine is used to generate audit and alarm messages when an
  2355. attempt is made to open an object with the intent to delete it.
  2356. Specifically, this is used by file systems when the flag
  2357. FILE_DELETE_ON_CLOSE is specified.
  2358. This routine may result in several messages being generated and sent to
  2359. Port objects. This may result in a significant latency before
  2360. returning. Design of routines that must call this routine must take
  2361. this potential latency into account. This may have an impact on the
  2362. approach taken for data structure mutex locking, for example.
  2363. Arguments:
  2364. ObjectTypeName - Supplies the name of the type of object being
  2365. accessed. This must be the same name provided to the
  2366. ObCreateObjectType service when the object type was created.
  2367. Object - Address of the object accessed. This value will not be used
  2368. as a pointer (referenced). It is necessary only to enter into log
  2369. messages. If the open was not successful, then this argument is
  2370. ignored. Otherwise, it must be provided.
  2371. AbsoluteObjectName - Supplies the name of the object being accessed.
  2372. If the object doesn't have a name, then this field is left null.
  2373. Otherwise, it must be provided.
  2374. SecurityDescriptor - A pointer to the security descriptor of the
  2375. object being accessed.
  2376. AccessState - A pointer to an access state structure containing the
  2377. subject context, the remaining desired access types, the granted
  2378. access types, and optionally a privilege set to indicate which
  2379. privileges were used to permit the access.
  2380. ObjectCreated - A boolean flag indicating whether the access resulted
  2381. in a new object being created. A value of TRUE indicates an object
  2382. was created, FALSE indicates an existing object was opened.
  2383. AccessGranted - Indicates if the access was granted or denied based on
  2384. the access check or privilege check.
  2385. AccessMode - Indicates the access mode used for the access check. One
  2386. of UserMode or KernelMode. Messages will not be generated by
  2387. kernel mode accesses.
  2388. GenerateOnClose - Points to a boolean that is set by the audit
  2389. generation routine and must be passed to SeCloseObjectAuditAlarm()
  2390. when the object handle is closed.
  2391. Return value:
  2392. None.
  2393. --*/
  2394. {
  2395. BOOLEAN GenerateAudit = FALSE;
  2396. BOOLEAN GenerateAlarm = FALSE;
  2397. ACCESS_MASK RequestedAccess;
  2398. POBJECT_NAME_INFORMATION ObjectNameInfo = NULL;
  2399. PUNICODE_STRING ObjectTypeNameInfo = NULL;
  2400. PUNICODE_STRING ObjectName = NULL;
  2401. PUNICODE_STRING LocalObjectTypeName = NULL;
  2402. PLUID PrimaryAuthenticationId = NULL;
  2403. PLUID ClientAuthenticationId = NULL;
  2404. BOOLEAN AuditPrivileges = FALSE;
  2405. BOOLEAN AuditPerformed;
  2406. PTOKEN Token;
  2407. ACCESS_MASK MappedGrantMask = (ACCESS_MASK)0;
  2408. ACCESS_MASK MappedDenyMask = (ACCESS_MASK)0;
  2409. PAUX_ACCESS_DATA AuxData;
  2410. PAGED_CODE();
  2411. UNREFERENCED_PARAMETER( ObjectCreated );
  2412. if ( AccessMode == KernelMode ) {
  2413. return;
  2414. }
  2415. AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
  2416. Token = EffectiveToken( &AccessState->SubjectSecurityContext );
  2417. if (ARGUMENT_PRESENT(Token->AuditData)) {
  2418. MappedGrantMask = Token->AuditData->GrantMask;
  2419. RtlMapGenericMask(
  2420. &MappedGrantMask,
  2421. &AuxData->GenericMapping
  2422. );
  2423. MappedDenyMask = Token->AuditData->DenyMask;
  2424. RtlMapGenericMask(
  2425. &MappedDenyMask,
  2426. &AuxData->GenericMapping
  2427. );
  2428. }
  2429. if (SecurityDescriptor != NULL) {
  2430. RequestedAccess = AccessState->RemainingDesiredAccess |
  2431. AccessState->PreviouslyGrantedAccess;
  2432. if ( SepAdtAuditThisEvent( AuditCategoryObjectAccess, &AccessGranted )) {
  2433. if ( RequestedAccess & (AccessGranted ? MappedGrantMask : MappedDenyMask)) {
  2434. GenerateAudit = TRUE;
  2435. } else {
  2436. SepExamineSacl(
  2437. RtlpSaclAddrSecurityDescriptor( (PISECURITY_DESCRIPTOR)SecurityDescriptor ),
  2438. Token,
  2439. RequestedAccess,
  2440. AccessGranted,
  2441. &GenerateAudit,
  2442. &GenerateAlarm
  2443. );
  2444. }
  2445. //
  2446. // Only generate an audit on close of we're auditing from SACL
  2447. // settings.
  2448. //
  2449. if (GenerateAudit) {
  2450. *GenerateOnClose = TRUE;
  2451. }
  2452. }
  2453. }
  2454. //
  2455. // If we don't generate an audit via the SACL, see if we need to generate
  2456. // one for privilege use.
  2457. //
  2458. // Note that we only audit privileges successfully used to open objects,
  2459. // so we don't care about a failed privilege use here. Therefore, only
  2460. // do this test of access has been granted.
  2461. //
  2462. if (!GenerateAudit && (AccessGranted == TRUE)) {
  2463. if ( SepAdtAuditThisEvent( AuditCategoryPrivilegeUse, &AccessGranted )) {
  2464. if ((AuxData->PrivilegesUsed != NULL) &&
  2465. (AuxData->PrivilegesUsed->PrivilegeCount > 0) ) {
  2466. //
  2467. // Make sure these are actually privileges that we want to audit
  2468. //
  2469. if (SepFilterPrivilegeAudits( AuxData->PrivilegesUsed )) {
  2470. GenerateAudit = TRUE;
  2471. //
  2472. // When we finally try to generate this audit, this flag
  2473. // will tell us that we need to audit the fact that we
  2474. // used a privilege, as opposed to audit due to the SACL.
  2475. //
  2476. AccessState->AuditPrivileges = TRUE;
  2477. }
  2478. }
  2479. }
  2480. }
  2481. //
  2482. // Set up either to generate an audit (if the access check has failed), or save
  2483. // the stuff that we're going to audit later into the AccessState structure.
  2484. //
  2485. if (GenerateAudit || GenerateAlarm) {
  2486. AccessState->GenerateAudit = TRUE;
  2487. //
  2488. // Figure out what we've been passed, and obtain as much
  2489. // missing information as possible.
  2490. //
  2491. if ( !ARGUMENT_PRESENT( AbsoluteObjectName )) {
  2492. if ( ARGUMENT_PRESENT( Object )) {
  2493. ObjectNameInfo = SepQueryNameString( Object );
  2494. if ( ObjectNameInfo != NULL ) {
  2495. ObjectName = &ObjectNameInfo->Name;
  2496. }
  2497. }
  2498. } else {
  2499. ObjectName = AbsoluteObjectName;
  2500. }
  2501. if ( !ARGUMENT_PRESENT( ObjectTypeName )) {
  2502. if ( ARGUMENT_PRESENT( Object )) {
  2503. ObjectTypeNameInfo = SepQueryTypeString( Object );
  2504. if ( ObjectTypeNameInfo != NULL ) {
  2505. LocalObjectTypeName = ObjectTypeNameInfo;
  2506. }
  2507. }
  2508. } else {
  2509. LocalObjectTypeName = ObjectTypeName;
  2510. }
  2511. //
  2512. // If the access attempt failed, do the audit here. If it succeeded,
  2513. // we'll do the audit later, when the handle is allocated.
  2514. //
  2515. //
  2516. if (!AccessGranted) {
  2517. AuditPerformed = SepAdtOpenObjectAuditAlarm ( (PUNICODE_STRING)&SeSubsystemName,
  2518. NULL,
  2519. LocalObjectTypeName,
  2520. ObjectName,
  2521. AccessState->SubjectSecurityContext.ClientToken,
  2522. AccessState->SubjectSecurityContext.PrimaryToken,
  2523. AccessState->OriginalDesiredAccess,
  2524. AccessState->PreviouslyGrantedAccess,
  2525. &AccessState->OperationID,
  2526. AuxData->PrivilegesUsed,
  2527. FALSE,
  2528. AccessState->SubjectSecurityContext.ProcessAuditId,
  2529. AuditCategoryObjectAccess,
  2530. NULL,
  2531. 0,
  2532. NULL );
  2533. } else {
  2534. //
  2535. // Generate the delete audit first
  2536. //
  2537. SepAdtOpenObjectForDeleteAuditAlarm ( (PUNICODE_STRING)&SeSubsystemName,
  2538. NULL,
  2539. LocalObjectTypeName,
  2540. ObjectName,
  2541. AccessState->SubjectSecurityContext.ClientToken,
  2542. AccessState->SubjectSecurityContext.PrimaryToken,
  2543. AccessState->OriginalDesiredAccess,
  2544. AccessState->PreviouslyGrantedAccess,
  2545. &AccessState->OperationID,
  2546. AuxData->PrivilegesUsed,
  2547. TRUE,
  2548. AccessState->SubjectSecurityContext.ProcessAuditId );
  2549. //
  2550. // Copy all the stuff we're going to need into the
  2551. // AccessState and return.
  2552. //
  2553. if ( ObjectName != NULL ) {
  2554. if ( AccessState->ObjectName.Buffer != NULL ) {
  2555. ExFreePool( AccessState->ObjectName.Buffer );
  2556. AccessState->ObjectName.Length = 0;
  2557. AccessState->ObjectName.MaximumLength = 0;
  2558. }
  2559. AccessState->ObjectName.Buffer = ExAllocatePool( PagedPool,ObjectName->MaximumLength );
  2560. if (AccessState->ObjectName.Buffer != NULL) {
  2561. AccessState->ObjectName.MaximumLength = ObjectName->MaximumLength;
  2562. RtlCopyUnicodeString( &AccessState->ObjectName, ObjectName );
  2563. }
  2564. }
  2565. if ( LocalObjectTypeName != NULL ) {
  2566. if ( AccessState->ObjectTypeName.Buffer != NULL ) {
  2567. ExFreePool( AccessState->ObjectTypeName.Buffer );
  2568. AccessState->ObjectTypeName.Length = 0;
  2569. AccessState->ObjectTypeName.MaximumLength = 0;
  2570. }
  2571. AccessState->ObjectTypeName.Buffer = ExAllocatePool( PagedPool, LocalObjectTypeName->MaximumLength );
  2572. if (AccessState->ObjectTypeName.Buffer != NULL) {
  2573. AccessState->ObjectTypeName.MaximumLength = LocalObjectTypeName->MaximumLength;
  2574. RtlCopyUnicodeString( &AccessState->ObjectTypeName, LocalObjectTypeName );
  2575. }
  2576. }
  2577. }
  2578. if ( ObjectNameInfo != NULL ) {
  2579. ExFreePool( ObjectNameInfo );
  2580. }
  2581. if ( ObjectTypeNameInfo != NULL ) {
  2582. ExFreePool( ObjectTypeNameInfo );
  2583. }
  2584. }
  2585. return;
  2586. }
  2587. VOID
  2588. SeObjectReferenceAuditAlarm(
  2589. IN PLUID OperationID OPTIONAL,
  2590. IN PVOID Object,
  2591. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  2592. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
  2593. IN ACCESS_MASK DesiredAccess,
  2594. IN PPRIVILEGE_SET Privileges OPTIONAL,
  2595. IN BOOLEAN AccessGranted,
  2596. IN KPROCESSOR_MODE AccessMode
  2597. )
  2598. /*++
  2599. Routine Description:
  2600. description-of-function.
  2601. Arguments:
  2602. argument-name - Supplies | Returns description of argument.
  2603. .
  2604. .
  2605. Return Value:
  2606. return-value - Description of conditions needed to return value. - or -
  2607. None.
  2608. --*/
  2609. {
  2610. BOOLEAN GenerateAudit = FALSE;
  2611. BOOLEAN GenerateAlarm = FALSE;
  2612. PAGED_CODE();
  2613. UNREFERENCED_PARAMETER( OperationID );
  2614. UNREFERENCED_PARAMETER( Privileges );
  2615. if (AccessMode == KernelMode) {
  2616. return;
  2617. }
  2618. if ( SecurityDescriptor != NULL ) {
  2619. if ( SepAdtAuditThisEvent( AuditCategoryDetailedTracking, &AccessGranted )) {
  2620. SepExamineSacl(
  2621. RtlpSaclAddrSecurityDescriptor( (PISECURITY_DESCRIPTOR)SecurityDescriptor ),
  2622. EffectiveToken( SubjectSecurityContext ),
  2623. DesiredAccess,
  2624. AccessGranted,
  2625. &GenerateAudit,
  2626. &GenerateAlarm
  2627. );
  2628. if ( GenerateAudit || GenerateAlarm ) {
  2629. SepAdtObjectReferenceAuditAlarm(
  2630. Object,
  2631. SubjectSecurityContext,
  2632. DesiredAccess,
  2633. AccessGranted
  2634. );
  2635. }
  2636. }
  2637. }
  2638. return;
  2639. }
  2640. VOID
  2641. SeAuditHandleCreation(
  2642. IN PACCESS_STATE AccessState,
  2643. IN HANDLE Handle
  2644. )
  2645. /*++
  2646. Routine Description:
  2647. This function audits the creation of a handle.
  2648. It will examine the AuditHandleCreation field in the passed AccessState,
  2649. which will indicate whether auditing was performed when the object
  2650. was found or created.
  2651. This routine is necessary because object name decoding and handle
  2652. allocation occur in widely separate places, preventing us from
  2653. auditing everything at once.
  2654. Arguments:
  2655. AccessState - Supplies a pointer to the AccessState structure
  2656. representing this access attempt.
  2657. Handle - The newly allocated handle value.
  2658. Return Value:
  2659. None.
  2660. --*/
  2661. {
  2662. BOOLEAN AuditPerformed = FALSE;
  2663. PAUX_ACCESS_DATA AuxData;
  2664. PAGED_CODE();
  2665. AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
  2666. if ( AccessState->GenerateAudit ) {
  2667. if ( AccessState->AuditPrivileges ) {
  2668. AuditPerformed = SepAdtPrivilegeObjectAuditAlarm (
  2669. (PUNICODE_STRING)&SeSubsystemName,
  2670. Handle,
  2671. (PTOKEN)AccessState->SubjectSecurityContext.ClientToken,
  2672. (PTOKEN)AccessState->SubjectSecurityContext.PrimaryToken,
  2673. AccessState->SubjectSecurityContext.ProcessAuditId,
  2674. AccessState->PreviouslyGrantedAccess,
  2675. AuxData->PrivilegesUsed,
  2676. TRUE
  2677. );
  2678. } else {
  2679. AuditPerformed = SepAdtOpenObjectAuditAlarm (
  2680. (PUNICODE_STRING)&SeSubsystemName,
  2681. &Handle,
  2682. &AccessState->ObjectTypeName,
  2683. &AccessState->ObjectName,
  2684. AccessState->SubjectSecurityContext.ClientToken,
  2685. AccessState->SubjectSecurityContext.PrimaryToken,
  2686. AccessState->OriginalDesiredAccess,
  2687. AccessState->PreviouslyGrantedAccess,
  2688. &AccessState->OperationID,
  2689. AuxData->PrivilegesUsed,
  2690. TRUE,
  2691. PsGetCurrentProcessId(),
  2692. AuditCategoryObjectAccess,
  2693. NULL,
  2694. 0,
  2695. NULL );
  2696. }
  2697. }
  2698. //
  2699. // If we generated an 'open' audit, make sure we generate a close
  2700. //
  2701. AccessState->GenerateOnClose = AuditPerformed;
  2702. return;
  2703. }
  2704. VOID
  2705. SeCloseObjectAuditAlarm(
  2706. IN PVOID Object,
  2707. IN HANDLE Handle,
  2708. IN BOOLEAN GenerateOnClose
  2709. )
  2710. /*++
  2711. Routine Description:
  2712. This routine is used to generate audit and alarm messages when a handle
  2713. to an object is deleted.
  2714. This routine may result in several messages being generated and sent to
  2715. Port objects. This may result in a significant latency before
  2716. returning. Design of routines that must call this routine must take
  2717. this potential latency into account. This may have an impact on the
  2718. approach taken for data structure mutex locking, for example.
  2719. Arguments:
  2720. Object - Address of the object being accessed. This value will not be
  2721. used as a pointer (referenced). It is necessary only to enter into
  2722. log messages.
  2723. Handle - Supplies the handle value assigned to the open.
  2724. GenerateOnClose - Is a boolean value returned from a corresponding
  2725. SeOpenObjectAuditAlarm() call when the object handle was created.
  2726. Return Value:
  2727. None.
  2728. --*/
  2729. {
  2730. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  2731. PSID UserSid;
  2732. NTSTATUS Status;
  2733. PAGED_CODE();
  2734. UNREFERENCED_PARAMETER( Object );
  2735. if (GenerateOnClose) {
  2736. SeCaptureSubjectContext ( &SubjectSecurityContext );
  2737. UserSid = SepTokenUserSid( EffectiveToken (&SubjectSecurityContext));
  2738. SepAdtCloseObjectAuditAlarm( (PUNICODE_STRING) &SeSubsystemName,
  2739. Handle,
  2740. UserSid );
  2741. SeReleaseSubjectContext ( &SubjectSecurityContext );
  2742. }
  2743. return;
  2744. }
  2745. VOID
  2746. SeDeleteObjectAuditAlarm(
  2747. IN PVOID Object,
  2748. IN HANDLE Handle
  2749. )
  2750. /*++
  2751. Routine Description:
  2752. This routine is used to generate audit and alarm messages when an object
  2753. is marked for deletion.
  2754. This routine may result in several messages being generated and sent to
  2755. Port objects. This may result in a significant latency before
  2756. returning. Design of routines that must call this routine must take
  2757. this potential latency into account. This may have an impact on the
  2758. approach taken for data structure mutex locking, for example.
  2759. Arguments:
  2760. Object - Address of the object being accessed. This value will not be
  2761. used as a pointer (referenced). It is necessary only to enter into
  2762. log messages.
  2763. Handle - Supplies the handle value assigned to the open.
  2764. Return Value:
  2765. None.
  2766. --*/
  2767. {
  2768. SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
  2769. PSID UserSid;
  2770. NTSTATUS Status;
  2771. PAGED_CODE();
  2772. UNREFERENCED_PARAMETER( Object );
  2773. SeCaptureSubjectContext ( &SubjectSecurityContext );
  2774. UserSid = SepTokenUserSid( EffectiveToken (&SubjectSecurityContext));
  2775. SepAdtDeleteObjectAuditAlarm (
  2776. (PUNICODE_STRING)&SeSubsystemName,
  2777. (PVOID)Handle,
  2778. UserSid
  2779. );
  2780. SeReleaseSubjectContext ( &SubjectSecurityContext );
  2781. return;
  2782. }
  2783. VOID
  2784. SepExamineSacl(
  2785. IN PACL Sacl,
  2786. IN PACCESS_TOKEN Token,
  2787. IN ACCESS_MASK DesiredAccess,
  2788. IN BOOLEAN AccessGranted,
  2789. OUT PBOOLEAN GenerateAudit,
  2790. OUT PBOOLEAN GenerateAlarm
  2791. )
  2792. /*++
  2793. Routine Description:
  2794. This routine will examine the passed Sacl and determine what
  2795. if any action is required based its contents.
  2796. Note that this routine is not aware of any system state, ie,
  2797. whether or not auditing is currently enabled for either the
  2798. system or this particular object type.
  2799. Arguments:
  2800. Sacl - Supplies a pointer to the Sacl to be examined.
  2801. Token - Supplies the effective token of the caller
  2802. AccessGranted - Supplies whether or not the access attempt
  2803. was successful.
  2804. GenerateAudit - Returns a boolean indicating whether or not
  2805. we should generate an audit.
  2806. GenerateAlarm - Returns a boolean indiciating whether or not
  2807. we should generate an alarm.
  2808. Return Value:
  2809. STATUS_SUCCESS - The operation completed successfully.
  2810. --*/
  2811. {
  2812. ULONG i;
  2813. PVOID Ace;
  2814. ULONG AceCount;
  2815. ACCESS_MASK AccessMask;
  2816. UCHAR AceFlags;
  2817. BOOLEAN FailedMaximumAllowed;
  2818. PAGED_CODE();
  2819. *GenerateAudit = FALSE;
  2820. *GenerateAlarm = FALSE;
  2821. //
  2822. // If we failed an attempt to open an object for ONLY maximumum allowed,
  2823. // then we generate an audit if ANY ACCESS_DENIED audit matching this
  2824. // user's list of sids is found
  2825. //
  2826. FailedMaximumAllowed = FALSE;
  2827. if (!AccessGranted && (DesiredAccess & MAXIMUM_ALLOWED)) {
  2828. FailedMaximumAllowed = TRUE;
  2829. }
  2830. //
  2831. // If the Sacl is null, do nothing and return
  2832. //
  2833. if (Sacl == NULL) {
  2834. return;
  2835. }
  2836. AceCount = Sacl->AceCount;
  2837. if (AceCount == 0) {
  2838. return;
  2839. }
  2840. //
  2841. // Iterate through the ACEs on the Sacl until either we reach
  2842. // the end or discover that we have to take all possible actions,
  2843. // in which case it doesn't pay to look any further
  2844. //
  2845. for ( i = 0, Ace = FirstAce( Sacl ) ;
  2846. (i < AceCount) && !(*GenerateAudit && *GenerateAlarm);
  2847. i++, Ace = NextAce( Ace ) ) {
  2848. if ( !(((PACE_HEADER)Ace)->AceFlags & INHERIT_ONLY_ACE)) {
  2849. if ( (((PACE_HEADER)Ace)->AceType == SYSTEM_AUDIT_ACE_TYPE) ) {
  2850. if ( SepSidInToken( (PACCESS_TOKEN)Token, NULL, &((PSYSTEM_AUDIT_ACE)Ace)->SidStart, FALSE ) ) {
  2851. AccessMask = ((PSYSTEM_AUDIT_ACE)Ace)->Mask;
  2852. AceFlags = ((PACE_HEADER)Ace)->AceFlags;
  2853. if ( AccessMask & DesiredAccess ) {
  2854. if (((AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) && AccessGranted) ||
  2855. ((AceFlags & FAILED_ACCESS_ACE_FLAG) && !AccessGranted)) {
  2856. *GenerateAudit = TRUE;
  2857. }
  2858. } else if ( FailedMaximumAllowed && (AceFlags & FAILED_ACCESS_ACE_FLAG) ) {
  2859. *GenerateAudit = TRUE;
  2860. }
  2861. }
  2862. continue;
  2863. }
  2864. if ( (((PACE_HEADER)Ace)->AceType == SYSTEM_ALARM_ACE_TYPE) ) {
  2865. if ( SepSidInToken( (PACCESS_TOKEN)Token, NULL, &((PSYSTEM_ALARM_ACE)Ace)->SidStart, FALSE ) ) {
  2866. AccessMask = ((PSYSTEM_ALARM_ACE)Ace)->Mask;
  2867. if ( AccessMask & DesiredAccess ) {
  2868. AceFlags = ((PACE_HEADER)Ace)->AceFlags;
  2869. if (((AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG) && AccessGranted) ||
  2870. ((AceFlags & FAILED_ACCESS_ACE_FLAG) && !AccessGranted)) {
  2871. *GenerateAlarm = TRUE;
  2872. }
  2873. }
  2874. }
  2875. }
  2876. }
  2877. }
  2878. return;
  2879. }
  2880. VOID
  2881. SepAuditTypeList (
  2882. IN PIOBJECT_TYPE_LIST ObjectTypeList,
  2883. IN ULONG ObjectTypeListLength,
  2884. IN PNTSTATUS AccessStatus,
  2885. IN ULONG StartIndex,
  2886. OUT PBOOLEAN GenerateSuccessAudit,
  2887. OUT PBOOLEAN GenerateFailureAudit
  2888. )
  2889. /*++
  2890. Routine Description:
  2891. This routine determines if any children of the object represented by
  2892. StartIndex have a different degree of success than the StartIndex element.
  2893. Arguments:
  2894. ObjectTypeList - The object type list to update.
  2895. ObjectTypeListLength - Number of elements in ObjectTypeList
  2896. AccessStatus - Specifies STATUS_SUCCESS or other error code to be
  2897. propogated back to the caller
  2898. StartIndex - Index to the target element to update.
  2899. GenerateSuccessAudit - Returns a boolean indicating whether or not
  2900. we should generate a success audit.
  2901. GenerateFailureAudit - Returns a boolean indicating whether or not
  2902. we should generate a failure audit.
  2903. Return Value:
  2904. None.
  2905. --*/
  2906. {
  2907. ULONG Index;
  2908. BOOLEAN WasSuccess;
  2909. PAGED_CODE();
  2910. //
  2911. // Determine if the target was successful.
  2912. //
  2913. WasSuccess = NT_SUCCESS( AccessStatus[StartIndex] );
  2914. //
  2915. // Loop handling all children of the target.
  2916. //
  2917. for ( Index=StartIndex+1; Index < ObjectTypeListLength; Index++ ) {
  2918. //
  2919. // By definition, the children of an object are all those entries
  2920. // immediately following the target. The list of children (or
  2921. // grandchildren) stops as soon as we reach an entry the has the
  2922. // same level as the target (a sibling) or lower than the target
  2923. // (an uncle).
  2924. //
  2925. if ( ObjectTypeList[Index].Level <= ObjectTypeList[StartIndex].Level ) {
  2926. break;
  2927. }
  2928. //
  2929. // If the child has different access than the target,
  2930. // mark the child.
  2931. //
  2932. if ( WasSuccess && !NT_SUCCESS( AccessStatus[Index]) ) {
  2933. *GenerateFailureAudit = TRUE;
  2934. ObjectTypeList[Index].Flags |= OBJECT_FAILURE_AUDIT;
  2935. } else if ( !WasSuccess && NT_SUCCESS( AccessStatus[Index]) ) {
  2936. *GenerateSuccessAudit = TRUE;
  2937. ObjectTypeList[Index].Flags |= OBJECT_SUCCESS_AUDIT;
  2938. }
  2939. }
  2940. }
  2941. VOID
  2942. SepSetAuditInfoForObjectType(
  2943. IN UCHAR AceFlags,
  2944. IN ACCESS_MASK AccessMask,
  2945. IN ACCESS_MASK DesiredAccess,
  2946. IN PIOBJECT_TYPE_LIST ObjectTypeList,
  2947. IN ULONG ObjectTypeListLength,
  2948. IN BOOLEAN ReturnResultList,
  2949. IN ULONG ObjectTypeIndex,
  2950. IN PNTSTATUS AccessStatus,
  2951. IN PACCESS_MASK GrantedAccess,
  2952. IN BOOLEAN FailedMaximumAllowed,
  2953. OUT PBOOLEAN GenerateSuccessAudit,
  2954. OUT PBOOLEAN GenerateFailureAudit
  2955. )
  2956. /*++
  2957. Routine Description:
  2958. Determine if success/failure audit needs to be generated for
  2959. object at ObjectTypeIndex in ObjectTypeList.
  2960. This helper function is called only by SepExamineSaclEx.
  2961. Arguments:
  2962. please refer to arg help for function SepExamineSaclEx
  2963. Return Value:
  2964. None.
  2965. --*/
  2966. {
  2967. PAGED_CODE();
  2968. if ( AccessMask & (DesiredAccess|GrantedAccess[ObjectTypeIndex]) ) {
  2969. if ( ( AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG ) &&
  2970. NT_SUCCESS(AccessStatus[ObjectTypeIndex]) ) {
  2971. *GenerateSuccessAudit = TRUE;
  2972. if ( ObjectTypeListLength != 0 ) {
  2973. ObjectTypeList[ObjectTypeIndex].Flags |= OBJECT_SUCCESS_AUDIT;
  2974. if ( ReturnResultList ) {
  2975. SepAuditTypeList( ObjectTypeList,
  2976. ObjectTypeListLength,
  2977. AccessStatus,
  2978. ObjectTypeIndex,
  2979. GenerateSuccessAudit,
  2980. GenerateFailureAudit );
  2981. }
  2982. }
  2983. } else if ( ( AceFlags & FAILED_ACCESS_ACE_FLAG ) &&
  2984. !NT_SUCCESS(AccessStatus[ObjectTypeIndex]) ) {
  2985. *GenerateFailureAudit = TRUE;
  2986. if ( ObjectTypeListLength != 0 ) {
  2987. ObjectTypeList[ObjectTypeIndex].Flags |= OBJECT_FAILURE_AUDIT;
  2988. if ( ReturnResultList ) {
  2989. SepAuditTypeList( ObjectTypeList,
  2990. ObjectTypeListLength,
  2991. AccessStatus,
  2992. ObjectTypeIndex,
  2993. GenerateSuccessAudit,
  2994. GenerateFailureAudit );
  2995. }
  2996. }
  2997. }
  2998. } else if ( FailedMaximumAllowed && (AceFlags & FAILED_ACCESS_ACE_FLAG) ) {
  2999. *GenerateFailureAudit = TRUE;
  3000. if ( ObjectTypeListLength != 0 ) {
  3001. ObjectTypeList[ObjectTypeIndex].Flags |= OBJECT_FAILURE_AUDIT;
  3002. }
  3003. }
  3004. }
  3005. VOID
  3006. SepExamineSaclEx(
  3007. IN PACL Sacl,
  3008. IN PACCESS_TOKEN Token,
  3009. IN ACCESS_MASK DesiredAccess,
  3010. IN PIOBJECT_TYPE_LIST ObjectTypeList OPTIONAL,
  3011. IN ULONG ObjectTypeListLength,
  3012. IN BOOLEAN ReturnResultList,
  3013. IN PNTSTATUS AccessStatus,
  3014. IN PACCESS_MASK GrantedAccess,
  3015. IN PSID PrincipalSelfSid,
  3016. OUT PBOOLEAN GenerateSuccessAudit,
  3017. OUT PBOOLEAN GenerateFailureAudit
  3018. )
  3019. /*++
  3020. Routine Description:
  3021. This routine will examine the passed Sacl and determine what
  3022. if any action is required based its contents.
  3023. Note that this routine is not aware of any system state, ie,
  3024. whether or not auditing is currently enabled for either the
  3025. system or this particular object type.
  3026. Arguments:
  3027. Sacl - Supplies a pointer to the Sacl to be examined.
  3028. Token - Supplies the effective token of the caller
  3029. DesiredAccess - Access that the caller wanted to the object
  3030. ObjectTypeList - Supplies a list of GUIDs representing the object (and
  3031. sub-objects) being accessed.
  3032. ObjectTypeListLength - Specifies the number of elements in the ObjectTypeList.
  3033. ReturnResultList - If true, AccessStatus and GrantedAccess is actually
  3034. an array of entries ObjectTypeListLength elements long.
  3035. AccessStatus - Specifies STATUS_SUCCESS or other error code to be
  3036. propogated back to the caller
  3037. PrincipalSelfSid - If the security descriptor is associated with an object
  3038. that represents a principal (for example, a user object),
  3039. the PrincipalSelfSid parameter should be the SID of the object.
  3040. When evaluating access, this SID logically replaces the SID in any ACE
  3041. containing the well-known PRINCIPAL_SELF SID (S-1-5-10).
  3042. GrantedAccess - Specifies the access granted to the caller.
  3043. GenerateSuccessAudit - Returns a boolean indicating whether or not
  3044. we should generate a success audit.
  3045. GenerateFailureAudit - Returns a boolean indicating whether or not
  3046. we should generate a failure audit.
  3047. Return Value:
  3048. STATUS_SUCCESS - The operation completed successfully.
  3049. --*/
  3050. {
  3051. ULONG i, j;
  3052. PVOID Ace;
  3053. ULONG AceCount;
  3054. ACCESS_MASK AccessMask=0;
  3055. UCHAR AceFlags;
  3056. BOOLEAN FailedMaximumAllowed;
  3057. ULONG Index;
  3058. ULONG SuccessIndex;
  3059. #define INVALID_OBJECT_TYPE_LIST_INDEX 0xFFFFFFFF
  3060. PAGED_CODE();
  3061. *GenerateSuccessAudit = FALSE;
  3062. *GenerateFailureAudit = FALSE;
  3063. //
  3064. // If we failed an attempt to open an object for maximumum allowed,
  3065. // then we generate an audit if ANY ACCESS_DENIED audit matching this
  3066. // user's list of sids is found
  3067. //
  3068. FailedMaximumAllowed = FALSE;
  3069. if (!NT_SUCCESS(*AccessStatus) && (DesiredAccess & MAXIMUM_ALLOWED)) {
  3070. FailedMaximumAllowed = TRUE;
  3071. }
  3072. //
  3073. // If the Sacl is null, do nothing and return
  3074. //
  3075. if (Sacl == NULL) {
  3076. return;
  3077. }
  3078. AceCount = Sacl->AceCount;
  3079. if (AceCount == 0) {
  3080. return;
  3081. }
  3082. //
  3083. // Iterate through the ACEs on the Sacl until either we reach
  3084. // the end or discover that we have to take all possible actions,
  3085. // in which case it doesn't pay to look any further
  3086. //
  3087. for ( i = 0, Ace = FirstAce( Sacl ) ;
  3088. (i < AceCount) && !((*GenerateSuccessAudit || *GenerateFailureAudit) && ObjectTypeListLength <= 1 );
  3089. i++, Ace = NextAce( Ace ) ) {
  3090. AceFlags = ((PACE_HEADER)Ace)->AceFlags;
  3091. if ( AceFlags & INHERIT_ONLY_ACE ) {
  3092. continue;
  3093. }
  3094. Index = INVALID_OBJECT_TYPE_LIST_INDEX;
  3095. if ( (((PACE_HEADER)Ace)->AceType == SYSTEM_AUDIT_ACE_TYPE) ) {
  3096. if ( SepSidInToken( Token, PrincipalSelfSid, &((PSYSTEM_AUDIT_ACE)Ace)->SidStart, (BOOLEAN) ((AceFlags & FAILED_ACCESS_ACE_FLAG) != 0) ) ) {
  3097. AccessMask = ((PSYSTEM_AUDIT_ACE)Ace)->Mask;
  3098. if (ObjectTypeListLength == 0) {
  3099. if ( NT_SUCCESS(AccessStatus[0]) ) {
  3100. if ( ( AceFlags & SUCCESSFUL_ACCESS_ACE_FLAG ) &&
  3101. ( AccessMask & GrantedAccess[0] ) ) {
  3102. *GenerateSuccessAudit = TRUE;
  3103. }
  3104. } else {
  3105. if ( ( AceFlags & FAILED_ACCESS_ACE_FLAG ) &&
  3106. ( AccessMask & DesiredAccess ) ) {
  3107. *GenerateFailureAudit = TRUE;
  3108. }
  3109. }
  3110. } else {
  3111. for (j=0; j < ObjectTypeListLength; j++)
  3112. {
  3113. SepSetAuditInfoForObjectType(AceFlags,
  3114. AccessMask,
  3115. DesiredAccess,
  3116. ObjectTypeList,
  3117. ObjectTypeListLength,
  3118. ReturnResultList,
  3119. j,
  3120. AccessStatus,
  3121. GrantedAccess,
  3122. FailedMaximumAllowed,
  3123. GenerateSuccessAudit,
  3124. GenerateFailureAudit
  3125. );
  3126. }
  3127. Index = INVALID_OBJECT_TYPE_LIST_INDEX;
  3128. }
  3129. }
  3130. //
  3131. // Handle an object specific audit ACE
  3132. //
  3133. } else if ( (((PACE_HEADER)Ace)->AceType == SYSTEM_AUDIT_OBJECT_ACE_TYPE) ) {
  3134. GUID *ObjectTypeInAce;
  3135. //
  3136. // If no object type is in the ACE,
  3137. // treat this as a normal audit ACE.
  3138. //
  3139. AccessMask = ((PSYSTEM_AUDIT_OBJECT_ACE)Ace)->Mask;
  3140. ObjectTypeInAce = RtlObjectAceObjectType(Ace);
  3141. if ( ObjectTypeInAce == NULL ) {
  3142. if ( SepSidInToken( Token, PrincipalSelfSid, RtlObjectAceSid(Ace), (BOOLEAN)((AceFlags & FAILED_ACCESS_ACE_FLAG) != 0) ) ) {
  3143. for (j=0; j < ObjectTypeListLength; j++)
  3144. {
  3145. SepSetAuditInfoForObjectType(AceFlags,
  3146. AccessMask,
  3147. DesiredAccess,
  3148. ObjectTypeList,
  3149. ObjectTypeListLength,
  3150. ReturnResultList,
  3151. j,
  3152. AccessStatus,
  3153. GrantedAccess,
  3154. FailedMaximumAllowed,
  3155. GenerateSuccessAudit,
  3156. GenerateFailureAudit
  3157. );
  3158. }
  3159. Index = INVALID_OBJECT_TYPE_LIST_INDEX;
  3160. }
  3161. //
  3162. // If an object type is in the ACE,
  3163. // Find it in the LocalTypeList before using the ACE.
  3164. //
  3165. } else {
  3166. if ( SepSidInToken( Token, PrincipalSelfSid, RtlObjectAceSid(Ace), (BOOLEAN)((AceFlags & FAILED_ACCESS_ACE_FLAG) != 0) ) ) {
  3167. if ( !SepObjectInTypeList( ObjectTypeInAce,
  3168. ObjectTypeList,
  3169. ObjectTypeListLength,
  3170. &Index ) ) {
  3171. Index = INVALID_OBJECT_TYPE_LIST_INDEX;
  3172. }
  3173. }
  3174. }
  3175. }
  3176. //
  3177. // If the ACE has a matched SID and a matched GUID,
  3178. // handle it.
  3179. //
  3180. if ( Index != INVALID_OBJECT_TYPE_LIST_INDEX ) {
  3181. //
  3182. // ASSERT: we have an ACE to be audited.
  3183. //
  3184. // Index is an index into ObjectTypeList of the entry to mark
  3185. // as the GUID needs auditing.
  3186. //
  3187. // SuccessIndex is an index into AccessStatus to determine if
  3188. // a success or failure audit is to be generated
  3189. //
  3190. SepSetAuditInfoForObjectType(AceFlags,
  3191. AccessMask,
  3192. DesiredAccess,
  3193. ObjectTypeList,
  3194. ObjectTypeListLength,
  3195. ReturnResultList,
  3196. Index,
  3197. AccessStatus,
  3198. GrantedAccess,
  3199. FailedMaximumAllowed,
  3200. GenerateSuccessAudit,
  3201. GenerateFailureAudit
  3202. );
  3203. }
  3204. }
  3205. return;
  3206. }
  3207. /******************************************************************************
  3208. * *
  3209. * The following list of privileges is checked at high frequency *
  3210. * during normal operation, and tend to clog up the audit log when *
  3211. * privilege auditing is enabled. The use of these privileges will *
  3212. * not be audited when they are checked singly or in combination with *
  3213. * each other. *
  3214. * *
  3215. * When adding new privileges, be careful to preserve the NULL *
  3216. * privilege pointer marking the end of the array. *
  3217. * *
  3218. * Be sure to update the corresponding array in LSA when adding new *
  3219. * privileges to this list (LsaFilterPrivileges). *
  3220. * *
  3221. ******************************************************************************/
  3222. #ifdef ALLOC_DATA_PRAGMA
  3223. #pragma data_seg("PAGEDATA")
  3224. #pragma const_seg("PAGECONST")
  3225. #endif
  3226. PLUID const * SepFilterPrivileges = NULL;
  3227. const PLUID SepFilterPrivilegesLong[] =
  3228. {
  3229. &SeChangeNotifyPrivilege,
  3230. &SeAuditPrivilege,
  3231. &SeCreateTokenPrivilege,
  3232. &SeAssignPrimaryTokenPrivilege,
  3233. &SeBackupPrivilege,
  3234. &SeRestorePrivilege,
  3235. &SeDebugPrivilege,
  3236. NULL
  3237. };
  3238. /******************************************************************************
  3239. * *
  3240. * The following list of privileges is the same as the above list, except *
  3241. * is missing backup and restore privileges. This allows for auditing *
  3242. * the use of those privileges at the time they are used. *
  3243. * *
  3244. * The use of this list or the one above is determined by settings in *
  3245. * the registry. *
  3246. * *
  3247. ******************************************************************************/
  3248. const PLUID SepFilterPrivilegesShort[] =
  3249. {
  3250. &SeChangeNotifyPrivilege,
  3251. &SeAuditPrivilege,
  3252. &SeCreateTokenPrivilege,
  3253. &SeAssignPrimaryTokenPrivilege,
  3254. &SeDebugPrivilege,
  3255. NULL
  3256. };
  3257. BOOLEAN
  3258. SepInitializePrivilegeFilter(
  3259. BOOLEAN Verbose
  3260. )
  3261. /*++
  3262. Routine Description:
  3263. Initializes SepFilterPrivileges for either normal or verbose auditing.
  3264. Arguments:
  3265. Verbose - Whether we want to filter by the short or long privileges
  3266. list. Verbose == TRUE means use the short list.
  3267. Return Value:
  3268. TRUE for success, FALSE for failure
  3269. --*/
  3270. {
  3271. if (Verbose) {
  3272. SepFilterPrivileges = SepFilterPrivilegesShort;
  3273. } else {
  3274. SepFilterPrivileges = SepFilterPrivilegesLong;
  3275. }
  3276. return( TRUE );
  3277. }
  3278. BOOLEAN
  3279. SepFilterPrivilegeAudits(
  3280. IN PPRIVILEGE_SET PrivilegeSet
  3281. )
  3282. /*++
  3283. Routine Description:
  3284. This routine will filter out a list of privileges as listed in the
  3285. SepFilterPrivileges array.
  3286. Arguments:
  3287. Privileges - The privilege set to be audited
  3288. Return Value:
  3289. FALSE means that this use of privilege is not to be audited.
  3290. TRUE means that the audit should continue normally.
  3291. --*/
  3292. {
  3293. PLUID const *Privilege;
  3294. ULONG Match = 0;
  3295. ULONG i;
  3296. PAGED_CODE();
  3297. if ( !ARGUMENT_PRESENT(PrivilegeSet) ||
  3298. (PrivilegeSet->PrivilegeCount == 0) ) {
  3299. return( FALSE );
  3300. }
  3301. for (i=0; i<PrivilegeSet->PrivilegeCount; i++) {
  3302. Privilege = SepFilterPrivileges;
  3303. do {
  3304. if ( RtlEqualLuid( &PrivilegeSet->Privilege[i].Luid, *Privilege )) {
  3305. Match++;
  3306. break;
  3307. }
  3308. } while ( *++Privilege != NULL );
  3309. }
  3310. if ( Match == PrivilegeSet->PrivilegeCount ) {
  3311. return( FALSE );
  3312. } else {
  3313. return( TRUE );
  3314. }
  3315. }
  3316. BOOLEAN
  3317. SeAuditingFileOrGlobalEvents(
  3318. IN BOOLEAN AccessGranted,
  3319. IN PSECURITY_DESCRIPTOR SecurityDescriptor,
  3320. IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext
  3321. )
  3322. /*++
  3323. Routine Description:
  3324. This routine is to be called by a file system to quickly determine
  3325. if we are auditing file open events. This allows the file system
  3326. to avoid the often considerable setup involved in generating an audit.
  3327. Arguments:
  3328. AccessGranted - Supplies whether the access attempt was successful
  3329. or a failure.
  3330. Return Value:
  3331. Boolean - TRUE if events of type AccessGranted are being audited, FALSE
  3332. otherwise.
  3333. --*/
  3334. {
  3335. PISECURITY_DESCRIPTOR ISecurityDescriptor = (PISECURITY_DESCRIPTOR) SecurityDescriptor;
  3336. PAGED_CODE();
  3337. if ( ((PTOKEN)EffectiveToken( SubjectSecurityContext ))->AuditData != NULL) {
  3338. return( TRUE );
  3339. }
  3340. if ( RtlpSaclAddrSecurityDescriptor( ISecurityDescriptor ) == NULL ) {
  3341. return( FALSE );
  3342. }
  3343. return( SepAdtAuditThisEvent( AuditCategoryObjectAccess, &AccessGranted ) );
  3344. }
  3345. BOOLEAN
  3346. SeAuditingFileEvents(
  3347. IN BOOLEAN AccessGranted,
  3348. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  3349. )
  3350. /*++
  3351. Routine Description:
  3352. This routine is to be called by a file system to quickly determine
  3353. if we are auditing file open events. This allows the file system
  3354. to avoid the often considerable setup involved in generating an audit.
  3355. Arguments:
  3356. AccessGranted - Supplies whether the access attempt was successful
  3357. or a failure.
  3358. Return Value:
  3359. Boolean - TRUE if events of type AccessGranted are being audited, FALSE
  3360. otherwise.
  3361. --*/
  3362. {
  3363. PAGED_CODE();
  3364. UNREFERENCED_PARAMETER( SecurityDescriptor );
  3365. return( SepAdtAuditThisEvent( AuditCategoryObjectAccess, &AccessGranted ) );
  3366. }
  3367. BOOLEAN
  3368. SeAuditingHardLinkEvents(
  3369. IN BOOLEAN AccessGranted,
  3370. IN PSECURITY_DESCRIPTOR SecurityDescriptor
  3371. )
  3372. /*++
  3373. Routine Description:
  3374. This routine is to be called by a file system to quickly determine
  3375. if we are auditing hard link creation.
  3376. Arguments:
  3377. AccessGranted - Supplies whether the access attempt was successful
  3378. or a failure.
  3379. SecurityDescriptor - SD of the linked file.
  3380. Return Value:
  3381. Boolean - TRUE if events of type AccessGranted are being audited, FALSE
  3382. otherwise.
  3383. --*/
  3384. {
  3385. PISECURITY_DESCRIPTOR pSD = SecurityDescriptor;
  3386. PACL Sacl = RtlpSaclAddrSecurityDescriptor( pSD );
  3387. PAGED_CODE();
  3388. //
  3389. // Audit hard link creation if object access auditing is on and the original file
  3390. // has a non empty SACL.
  3391. //
  3392. if ( (SepAdtAuditThisEvent( AuditCategoryObjectAccess, &AccessGranted )) &&
  3393. (NULL != Sacl) &&
  3394. (0 != Sacl->AceCount)) {
  3395. return TRUE;
  3396. }
  3397. return FALSE;
  3398. }