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

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