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.

1195 lines
36 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. adtqueue.c
  5. Abstract:
  6. This module implements the routines for the Authz audit queue.
  7. Author:
  8. Jeff Hamblin - May 2000
  9. Environment:
  10. User mode only.
  11. Revision History:
  12. Created - May 2000
  13. --*/
  14. /*++
  15. The Authz Audit Queue Algorithm
  16. The following are used in the queueing algorithm:
  17. hAuthzAuditQueueLowEvent - event that is signalled when threads are free
  18. to place audits on the queue (queue is below high water mark). Note that
  19. this is an auto reset event: when the event is signalled, exactly one
  20. waiting thread is scheduled to run and the event then returns to a
  21. nonsignalled state.
  22. bAuthzAuditQueueHighEvent - boolean indicating that audits may not be
  23. added (queue is over high water mark).
  24. hAuthzAuditAddedEvent - event that is signalled when the queue is empty and an
  25. audit get placed on the queue. The dequeueing thread runs when this is signalled.
  26. hAuthzAuditQueueEmptyEvent - signals when the queue is empty.
  27. AuthzAuditQueue - doubly linked list. This is the audit queue.
  28. AuthzAuditQueueLength - The current number of audits in the queue.
  29. hAuthzAuditThread - the dequeueing thread.
  30. AuthzAuditQueueLock - critical section locking the queue and related
  31. variables.
  32. Assume that the Resource Manager wishes to monitor the queue length and
  33. has specified High and Low water marks to control the growth of the queue.
  34. If the queue length reaches the High water mark, then all queueing threads
  35. will be blocked until the dequeueing thread has reduced the queue length
  36. to the Low water mark.
  37. Here is the flow of code for a thread attempting to log an audit (via
  38. AuthziLogAuditEvent()) when the Resource Manager is monitoring the queue
  39. length:
  40. if QueueLength > .75 * HighWater # this is heuristic to save unnecessary
  41. wait until the LowEvent is signalled # kernel transitions
  42. enter queue critical section
  43. {
  44. insert audit on queue
  45. QueueLength ++
  46. signal AuditAddedEvent # notifying the dequeue thread
  47. if (QueueLength >= HighWater)
  48. {
  49. bHigh = TRUE
  50. }
  51. }
  52. leave critical section
  53. ...[code overhead, execute cleanup code in AuthziLogAuditEvent ...]
  54. enter queue critical section
  55. {
  56. if (!bHigh)
  57. {
  58. if (QueueLength <= HighWater)
  59. {
  60. signal LowEvent #allow other threads to run
  61. }
  62. }
  63. ASSERT(FALSE);
  64. }
  65. leave critical section
  66. Here is the algorithm for the dequeueing thread:
  67. while (TRUE)
  68. {
  69. wait for AuditAdded event
  70. while (QueueLength > 0)
  71. {
  72. enter queue critical section
  73. {
  74. remove audit from head of list
  75. QueueLength--
  76. if (bHigh)
  77. {
  78. if (QueueLength <= LowWater)
  79. {
  80. bHigh = FALSE
  81. signal LowEvent # tell threads it is okay to queue
  82. }
  83. }
  84. }
  85. release critical section
  86. Send to LSA
  87. }
  88. enter critical section
  89. {
  90. if (QueueLength == 0)
  91. {
  92. reset AuditAdded event # make myself wait
  93. }
  94. }
  95. release critical section
  96. }
  97. --*/
  98. #include "pch.h"
  99. #pragma hdrstop
  100. #include <authzp.h>
  101. #include <authzi.h>
  102. #ifdef AUTHZ_AUDIT_COUNTER
  103. LONG AuthzpAuditsEnqueued = 0;
  104. LONG AuthzpAuditsDequeued = 0;
  105. #endif
  106. BOOL
  107. AuthzpEnQueueAuditEvent(
  108. PAUTHZI_AUDIT_QUEUE pQueue,
  109. PAUTHZ_AUDIT_QUEUE_ENTRY pAudit
  110. )
  111. /*++
  112. Routine Description
  113. This enqueues an audit without regard to any queue size limits. It does minimal event management.
  114. Arguments
  115. pQueue - Pointer to the queue to place the audit on.
  116. pAudit - Pointer to the audit to enqueue.
  117. Return Value
  118. Boolean, TRUE on success, FALSE on failure.
  119. Extended information available with GetLastError().
  120. --*/
  121. {
  122. BOOL b = TRUE;
  123. RtlEnterCriticalSection(&pQueue->AuthzAuditQueueLock);
  124. InsertTailList(&pQueue->AuthzAuditQueue, &pAudit->list);
  125. pQueue->AuthzAuditQueueLength++;
  126. #ifdef AUTHZ_AUDIT_COUNTER
  127. InterlockedIncrement(&AuthzpAuditsEnqueued);
  128. #endif
  129. //
  130. // Only set the AuditAdded event if the length goes from 0 to 1. This
  131. // saves us redundant kernel transitions.
  132. //
  133. if (pQueue->AuthzAuditQueueLength == 1)
  134. {
  135. b = SetEvent(pQueue->hAuthzAuditAddedEvent);
  136. if (!b)
  137. {
  138. ASSERT(L"AUTHZ: SetEvent on hAuthzAuditAddedEvent handle failed." && FALSE);
  139. goto Cleanup;
  140. }
  141. b = ResetEvent(pQueue->hAuthzAuditQueueEmptyEvent);
  142. if (!b)
  143. {
  144. ASSERT(L"AUTHZ: ResetEvent on hAuthzAuditQueueEmptyEvent handle failed." && FALSE);
  145. goto Cleanup;
  146. }
  147. }
  148. Cleanup:
  149. RtlLeaveCriticalSection(&pQueue->AuthzAuditQueueLock);
  150. return b;
  151. }
  152. BOOL
  153. AuthzpEnQueueAuditEventMonitor(
  154. PAUTHZI_AUDIT_QUEUE pQueue,
  155. PAUTHZ_AUDIT_QUEUE_ENTRY pAudit
  156. )
  157. /*++
  158. Routine Description
  159. This enqueues an audit and sets appropriate events for queue size monitoring.
  160. Arguments
  161. pQueue - pointer to the queue to place audit on.
  162. pAudit - pointer to the audit to queue.
  163. Return Value
  164. Boolean, TRUE on success, FALSE on failure.
  165. Extended information available with GetLastError().
  166. --*/
  167. {
  168. BOOL b = TRUE;
  169. RtlEnterCriticalSection(&pQueue->AuthzAuditQueueLock);
  170. InsertTailList(&pQueue->AuthzAuditQueue, &pAudit->list);
  171. pQueue->AuthzAuditQueueLength++;
  172. #ifdef AUTHZ_AUDIT_COUNTER
  173. InterlockedIncrement(&AuthzpAuditsEnqueued);
  174. #endif
  175. //
  176. // Only set the AuditAdded event if the length goes from 0 to 1. This
  177. // saves us redundant kernel transitions.
  178. //
  179. if (pQueue->AuthzAuditQueueLength == 1)
  180. {
  181. b = SetEvent(pQueue->hAuthzAuditAddedEvent);
  182. if (!b)
  183. {
  184. ASSERT(L"AUTHZ: SetEvent on hAuthzAuditAddedEvent handle failed." && FALSE);
  185. goto Cleanup;
  186. }
  187. b = ResetEvent(pQueue->hAuthzAuditQueueEmptyEvent);
  188. if (!b)
  189. {
  190. ASSERT(L"AUTHZ: ResetEvent on hAuthzAuditQueueEmptyEvent handle failed." && FALSE);
  191. goto Cleanup;
  192. }
  193. }
  194. if (pQueue->AuthzAuditQueueLength >= pQueue->dwAuditQueueHigh)
  195. {
  196. #ifdef AUTHZ_DEBUG_QUEUE
  197. wprintf(L"___Setting HIGH water mark ON\n");
  198. fflush(stdout);
  199. #endif
  200. pQueue->bAuthzAuditQueueHighEvent = TRUE;
  201. }
  202. Cleanup:
  203. RtlLeaveCriticalSection(&pQueue->AuthzAuditQueueLock);
  204. return b;
  205. }
  206. ULONG
  207. AuthzpDeQueueThreadWorker(
  208. LPVOID lpParameter
  209. )
  210. /*++
  211. Routine Description
  212. This is the function run by the dequeueing thread. It pulls audits from the queue
  213. and sends them to LSA.
  214. Arguments
  215. lpParameter - generic thread parameter. The actual parameter passed in is of
  216. type PAUTHZI_AUDIT_QUEUE.
  217. Return Value
  218. None.
  219. --*/
  220. {
  221. BOOL b;
  222. PAUTHZ_AUDIT_QUEUE_ENTRY pAuditEntry = NULL;
  223. PAUTHZI_AUDIT_QUEUE pQueue = (PAUTHZI_AUDIT_QUEUE) lpParameter;
  224. DWORD dwError;
  225. while (pQueue->bWorker)
  226. {
  227. //
  228. // The thread waits until there are audits in the queue.
  229. //
  230. dwError = WaitForSingleObject(
  231. pQueue->hAuthzAuditAddedEvent,
  232. INFINITE
  233. );
  234. //
  235. // If the wait does not succeed either something is very wrong or the hAuthzAuditAddedEvent
  236. // was closed, indicating that the RM is freeing its hRMAuditInfo. The thread should exit.
  237. //
  238. if (WAIT_OBJECT_0 != dwError)
  239. {
  240. ASSERT(L"WaitForSingleObject on hAuthzAuditAddedEvent failed." && FALSE);
  241. }
  242. //
  243. // The thread remains active while there are audits in the queue.
  244. //
  245. while (pQueue->AuthzAuditQueueLength > 0)
  246. {
  247. RtlEnterCriticalSection(&pQueue->AuthzAuditQueueLock);
  248. pAuditEntry = (PAUTHZ_AUDIT_QUEUE_ENTRY) (pQueue->AuthzAuditQueue).Flink;
  249. RemoveEntryList(&pAuditEntry->list);
  250. pQueue->AuthzAuditQueueLength--;
  251. #ifdef AUTHZ_AUDIT_COUNTER
  252. InterlockedIncrement(&AuthzpAuditsDequeued);
  253. #endif
  254. if (FLAG_ON(pQueue->Flags, AUTHZ_MONITOR_AUDIT_QUEUE_SIZE))
  255. {
  256. if (TRUE == pQueue->bAuthzAuditQueueHighEvent)
  257. {
  258. if (pQueue->AuthzAuditQueueLength <= pQueue->dwAuditQueueLow)
  259. {
  260. //
  261. // If the High flag is on and the length is now reduced to the low water mark, then
  262. // set appropriate events.
  263. //
  264. pQueue->bAuthzAuditQueueHighEvent = FALSE;
  265. b = SetEvent(pQueue->hAuthzAuditQueueLowEvent);
  266. if (!b)
  267. {
  268. ASSERT(L"SetEvent on hAuthzAuditQueueLowEvent failed." && FALSE);
  269. }
  270. #ifdef AUTHZ_DEBUG_QUEUE
  271. wprintf(L"** _____ TURNING HIGH WATER OFF _____\n");
  272. fflush(stdout);
  273. #endif
  274. }
  275. }
  276. }
  277. RtlLeaveCriticalSection(&pQueue->AuthzAuditQueueLock);
  278. b = AuthzpSendAuditToLsa(
  279. (AUDIT_HANDLE)(pAuditEntry->pAAETO->hAudit),
  280. pAuditEntry->Flags,
  281. pAuditEntry->pAuditParams,
  282. pAuditEntry->pReserved
  283. );
  284. #ifdef AUTHZ_DEBUG_QUEUE
  285. if (!b)
  286. {
  287. DbgPrint("Error in AuthzpSendAuditToLsa() :: Error = %d = 0x%x\n", GetLastError(), GetLastError());
  288. DbgPrint("Context = 0x%x\n", pAuditEntry->pAAETO->hAudit);
  289. DbgPrint("Flags = 0x%x\n", pAuditEntry->Flags);
  290. DbgPrint("Params = 0x%x\n", pAuditEntry->pAuditParams);
  291. ASSERT(FALSE);
  292. }
  293. #endif
  294. b = AuthzpDereferenceAuditEventType((AUTHZ_AUDIT_EVENT_TYPE_HANDLE)pAuditEntry->pAAETO);
  295. if (!b)
  296. {
  297. ASSERT(FALSE && L"Deref AuditEventType failed.");
  298. }
  299. AuthzpFree(pAuditEntry->pAuditParams);
  300. AuthzpFree(pAuditEntry);
  301. }
  302. RtlEnterCriticalSection(&pQueue->AuthzAuditQueueLock);
  303. if (0 == pQueue->AuthzAuditQueueLength)
  304. {
  305. b = ResetEvent(pQueue->hAuthzAuditAddedEvent);
  306. if (!b)
  307. {
  308. ASSERT(L"ResetEvent on hAuthzAuditAddedEvent failed." && FALSE);
  309. }
  310. b = SetEvent(pQueue->hAuthzAuditQueueEmptyEvent);
  311. if (!b)
  312. {
  313. ASSERT(L"SetEvent on hAuthzAuditQueueEmptyEvent failed." && FALSE);
  314. }
  315. }
  316. RtlLeaveCriticalSection(&pQueue->AuthzAuditQueueLock);
  317. }
  318. return STATUS_SUCCESS;
  319. }
  320. BOOL
  321. AuthzpCreateAndLogAudit(
  322. IN DWORD AuditTypeFlag,
  323. IN PAUTHZI_CLIENT_CONTEXT pAuthzClientContext,
  324. IN PAUTHZI_AUDIT_EVENT pAuditEvent,
  325. IN PAUTHZI_RESOURCE_MANAGER pRM,
  326. IN PIOBJECT_TYPE_LIST LocalTypeList,
  327. IN PAUTHZ_ACCESS_REQUEST pRequest,
  328. IN PAUTHZ_ACCESS_REPLY pReply
  329. )
  330. /*++
  331. Routine Description
  332. This is called from AuthzpGenerateAudit as a wrapper around LSA and
  333. AuthziLogAuditEvent functionality. It places the appropriate audit
  334. information on a queue for sending to LSA.
  335. Arguments
  336. AuditTypeFlag - mask to specify success | failure audit generation. Only
  337. one bit at a time.
  338. pAuthzClientContext - pointer to Authz context representing the client.
  339. pAuditEvent - Object specific audit info will be passed in this structure.
  340. pRM - Resource manager that generates the audit.
  341. LocalTypeList - Internal object type list structure.
  342. pRequest - specifies the desired access mask, principal self sid, the
  343. object type list structure (if any).
  344. pReply - The reply structure to return the results.
  345. Return Value
  346. TRUE if successful, FALSE if not.
  347. Extended information available with GetLastError().
  348. --*/
  349. {
  350. #define AUTHZ_BUFFER_CAPTURE_MAX 200
  351. BOOL b;
  352. AUDIT_PARAMS AuditParams = {0};
  353. AUDIT_PARAM ParamArray[SE_MAX_AUDIT_PARAMETERS] = {0};
  354. PAUTHZI_AUDIT_EVENT pCapturedAuditEvent = NULL;
  355. UCHAR pBuffer[AUTHZ_BUFFER_CAPTURE_MAX] = {0};
  356. AUDIT_OBJECT_TYPE FixedObjectTypeToAudit = {0};
  357. AUDIT_OBJECT_TYPES ObjectTypeListAudit = {0};
  358. PAUDIT_OBJECT_TYPE ObjectTypesToAudit = NULL;
  359. USHORT ObjectTypeAuditCount = 0;
  360. LONG i = 0;
  361. LONG j = 0;
  362. DWORD APF_AuditTypeFlag = 0;
  363. ACCESS_MASK MaskToAudit = 0;
  364. //
  365. // Capture pAuditEvent, as we may change the pAuditParams member and would like to
  366. // avoid the inevitable race that would follow.
  367. //
  368. if (AUTHZ_BUFFER_CAPTURE_MAX >= pAuditEvent->dwSize)
  369. {
  370. pCapturedAuditEvent = (PAUTHZI_AUDIT_EVENT) pBuffer;
  371. RtlCopyMemory(
  372. pCapturedAuditEvent,
  373. pAuditEvent,
  374. pAuditEvent->dwSize
  375. );
  376. }
  377. else
  378. {
  379. pCapturedAuditEvent = AuthzpAlloc(pAuditEvent->dwSize);
  380. if (AUTHZ_ALLOCATION_FAILED(pCapturedAuditEvent))
  381. {
  382. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  383. b = FALSE;
  384. goto Cleanup;
  385. }
  386. RtlCopyMemory(
  387. pCapturedAuditEvent,
  388. pAuditEvent,
  389. pAuditEvent->dwSize
  390. );
  391. }
  392. //
  393. // Make sure only one valid bit is on in the AuditTypeFlag. If a RM needs to generate
  394. // both success and failure audits, then two separate calls should be made.
  395. //
  396. ASSERT(!(
  397. FLAG_ON(AuditTypeFlag, AUTHZ_OBJECT_SUCCESS_AUDIT) &&
  398. FLAG_ON(AuditTypeFlag, AUTHZ_OBJECT_FAILURE_AUDIT)
  399. ));
  400. //
  401. // Set the APF_AuditTypeFlag. LSA has its own flags for audit success
  402. // and audit failure. Authz must map the Authz flag to the LSA APF equivalent.
  403. //
  404. if (FLAG_ON(AuditTypeFlag, AUTHZ_OBJECT_SUCCESS_AUDIT))
  405. {
  406. APF_AuditTypeFlag = APF_AuditSuccess;
  407. //
  408. // Test if the RM specifically disabled success audits
  409. //
  410. if (FLAG_ON(pCapturedAuditEvent->Flags, AUTHZ_NO_SUCCESS_AUDIT))
  411. {
  412. b = TRUE;
  413. goto Cleanup;
  414. }
  415. }
  416. else if (FLAG_ON(AuditTypeFlag, AUTHZ_OBJECT_FAILURE_AUDIT))
  417. {
  418. APF_AuditTypeFlag = APF_AuditFailure;
  419. //
  420. // Test if the RM specifically disabled failure audits
  421. //
  422. if (FLAG_ON(pCapturedAuditEvent->Flags, AUTHZ_NO_FAILURE_AUDIT))
  423. {
  424. b = TRUE;
  425. goto Cleanup;
  426. }
  427. }
  428. else
  429. {
  430. SetLastError(ERROR_INVALID_PARAMETER);
  431. b = FALSE;
  432. goto Cleanup;
  433. }
  434. //
  435. // Set the AUTHZ_AUDIT_QUEUE_HANDLE and AUTHZ_AUDIT_EVENT_TYPE_HANDLE of the AuditEvent if they are not yet set.
  436. //
  437. if (NULL == pCapturedAuditEvent->hAET)
  438. {
  439. if (FLAG_ON(pCapturedAuditEvent->Flags, AUTHZ_DS_CATEGORY_FLAG))
  440. {
  441. pCapturedAuditEvent->hAET = pRM->hAETDS;
  442. }
  443. else
  444. {
  445. pCapturedAuditEvent->hAET = pRM->hAET;
  446. }
  447. }
  448. if (NULL == pAuditEvent->hAuditQueue)
  449. {
  450. pCapturedAuditEvent->hAuditQueue = pRM->hAuditQueue;
  451. InterlockedCompareExchangePointer(
  452. &pAuditEvent->hAuditQueue,
  453. pRM->hAuditQueue,
  454. NULL
  455. );
  456. }
  457. //
  458. // Decide what access bits we should audit
  459. //
  460. MaskToAudit = (APF_AuditTypeFlag == APF_AuditSuccess) ? pReply->GrantedAccessMask[0] : pRequest->DesiredAccess;
  461. //
  462. // If the RM gives us an AUDIT_PARAMS structure to marshall, then we don't
  463. // need to generate our own.
  464. //
  465. if (AUTHZ_NON_NULL_PTR(pCapturedAuditEvent->pAuditParams))
  466. {
  467. //
  468. // Capture the AuditParams so that we can change the User SID without racing.
  469. //
  470. RtlCopyMemory(
  471. &AuditParams,
  472. pCapturedAuditEvent->pAuditParams,
  473. sizeof(AUDIT_PARAMS)
  474. );
  475. ASSERT(pCapturedAuditEvent->pAuditParams->Count <= SE_MAX_AUDIT_PARAMETERS);
  476. RtlCopyMemory(
  477. ParamArray,
  478. pCapturedAuditEvent->pAuditParams->Parameters,
  479. sizeof(AUDIT_PARAM) * pCapturedAuditEvent->pAuditParams->Count
  480. );
  481. AuditParams.Parameters = ParamArray;
  482. //
  483. // Replace the SID in the AUDIT_PARAMS with the SID of the current Client Context.
  484. //
  485. if (AUTHZ_NON_NULL_PTR(pAuthzClientContext->Sids[0].Sid))
  486. {
  487. AuditParams.Parameters[0].Data0 = (ULONG_PTR) pAuthzClientContext->Sids[0].Sid;
  488. }
  489. AuditParams.Flags = APF_AuditTypeFlag;
  490. pCapturedAuditEvent->pAuditParams = &AuditParams;
  491. b = AuthziLogAuditEvent(
  492. 0,
  493. (AUTHZ_AUDIT_EVENT_HANDLE)pCapturedAuditEvent,
  494. 0
  495. );
  496. goto Cleanup;
  497. }
  498. //
  499. // The caller has not given us an audit to generate. We will create one, provided that
  500. // the AuditID specifies the generic object access (SE_AUDITID_OBJECT_OPERATION)
  501. //
  502. if ((NULL != pCapturedAuditEvent->hAET) &&
  503. (((PAUTHZ_AUDIT_EVENT_TYPE_OLD)pCapturedAuditEvent->hAET)->u.Legacy.AuditId != SE_AUDITID_OBJECT_OPERATION))
  504. {
  505. SetLastError(ERROR_INVALID_PARAMETER);
  506. b = FALSE;
  507. goto Cleanup;
  508. }
  509. //
  510. // Create the generic object access audit. There are two codepaths
  511. // that initialize the AuditParams structure. The first path is taken if
  512. // there is no ObjectTypeList. The second path is taken if there is an
  513. // ObjectTypeList.
  514. //
  515. AuditParams.Parameters = ParamArray;
  516. pCapturedAuditEvent->pAuditParams = &AuditParams;
  517. //
  518. // Check if there is an ObjectTypeList.
  519. //
  520. if (AUTHZ_NON_NULL_PTR(pRequest->ObjectTypeList))
  521. {
  522. //
  523. // If the length of the structure is 1 then the caller only wants access
  524. // at the root of the tree.
  525. //
  526. if (1 == pReply->ResultListLength)
  527. {
  528. //
  529. // Caller only wants access at ObjectTypeList root, so only one ObjectType to
  530. // audit. For efficiency simply use the stack variable.
  531. //
  532. ObjectTypesToAudit = &FixedObjectTypeToAudit;
  533. ObjectTypeAuditCount = 1;
  534. FixedObjectTypeToAudit.AccessMask = pReply->GrantedAccessMask[0];
  535. RtlCopyMemory(
  536. &FixedObjectTypeToAudit.ObjectType,
  537. &LocalTypeList[0].ObjectType,
  538. sizeof(GUID)
  539. );
  540. }
  541. else
  542. {
  543. //
  544. // The caller wants more than access at ObjectTypeList root. He wants the
  545. // whole thing.
  546. //
  547. //
  548. // Determine how many GUIDs the client has access to which should be audited
  549. //
  550. for (ObjectTypeAuditCount = 0, i = 0; i < (LONG) pReply->ResultListLength; i++)
  551. {
  552. if (FLAG_ON(LocalTypeList[i].Flags, AuditTypeFlag))
  553. {
  554. ObjectTypeAuditCount++;
  555. }
  556. }
  557. //
  558. // Allocate appropriate storage space for GUID list
  559. //
  560. ObjectTypesToAudit = AuthzpAlloc(sizeof(AUDIT_OBJECT_TYPE) * ObjectTypeAuditCount);
  561. if (AUTHZ_ALLOCATION_FAILED(ObjectTypesToAudit))
  562. {
  563. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  564. b = FALSE;
  565. goto Cleanup;
  566. }
  567. RtlZeroMemory(
  568. ObjectTypesToAudit,
  569. sizeof(AUDIT_OBJECT_TYPE) * ObjectTypeAuditCount
  570. );
  571. for (i = 0, j = -1; i < ObjectTypeAuditCount; i++)
  572. {
  573. //
  574. // One counter tracks position in the alloc'ed array of ObjectTypesToAudit.
  575. // The other counter picks out the indices in the pReply and LocalTypeList
  576. // structures that need to be audited for success.
  577. //
  578. //
  579. // find the next GUID to audit in pReply that client was granted access to.
  580. //
  581. do
  582. {
  583. j++;
  584. }
  585. while (!FLAG_ON(LocalTypeList[j].Flags, AuditTypeFlag));
  586. //
  587. // In the success audit, the AccessMask records the actual
  588. // granted bits.
  589. //
  590. ObjectTypesToAudit[i].AccessMask = pReply->GrantedAccessMask[j];
  591. ObjectTypesToAudit[i].Level = LocalTypeList[j].Level;
  592. ObjectTypesToAudit[i].Flags = 0;
  593. RtlCopyMemory(
  594. &ObjectTypesToAudit[i].ObjectType,
  595. &LocalTypeList[j].ObjectType,
  596. sizeof(GUID)
  597. );
  598. }
  599. }
  600. ObjectTypeListAudit.Count = ObjectTypeAuditCount;
  601. ObjectTypeListAudit.pObjectTypes = ObjectTypesToAudit;
  602. ObjectTypeListAudit.Flags = 0;
  603. b = AuthziInitializeAuditParamsWithRM(
  604. APF_AuditTypeFlag,
  605. (AUTHZ_RESOURCE_MANAGER_HANDLE)pRM,
  606. AUTHZP_NUM_PARAMS_FOR_SE_AUDITID_OBJECT_OPERATION,
  607. &AuditParams,
  608. APT_String, pRM->szResourceManagerName,
  609. APT_String, pCapturedAuditEvent->szOperationType,
  610. APT_String, pCapturedAuditEvent->szObjectType,
  611. APT_String, pCapturedAuditEvent->szObjectName,
  612. APT_String, L"-",
  613. APT_LogonId | AP_PrimaryLogonId,
  614. APT_LogonId, pAuthzClientContext->AuthenticationId,
  615. APT_Ulong | AP_AccessMask, MaskToAudit, 2,
  616. APT_ObjectTypeList, &ObjectTypeListAudit, 2,
  617. APT_String, pCapturedAuditEvent->szAdditionalInfo,
  618. APT_String, pCapturedAuditEvent->szAdditionalInfo2,
  619. APT_Ulong | AP_FormatHex, MaskToAudit
  620. );
  621. if (!b)
  622. {
  623. #ifdef AUTHZ_DEBUG_QUEUE
  624. DbgPrint("AuthzInitializeAuditParams failed %d\n", GetLastError());
  625. #endif
  626. goto Cleanup;
  627. }
  628. } // matches "if (AUTHZ_NON_NULL_PTR(pRequest->ObjectTypeList))"
  629. else
  630. {
  631. b = AuthziInitializeAuditParamsWithRM(
  632. APF_AuditTypeFlag,
  633. (AUTHZ_RESOURCE_MANAGER_HANDLE)pRM,
  634. AUTHZP_NUM_PARAMS_FOR_SE_AUDITID_OBJECT_OPERATION,
  635. &AuditParams,
  636. APT_String, pRM->szResourceManagerName,
  637. APT_String, pCapturedAuditEvent->szOperationType,
  638. APT_String, pCapturedAuditEvent->szObjectType,
  639. APT_String, pCapturedAuditEvent->szObjectName,
  640. APT_String, L"-",
  641. APT_LogonId | AP_PrimaryLogonId,
  642. APT_LogonId, pAuthzClientContext->AuthenticationId,
  643. APT_Ulong | AP_AccessMask, MaskToAudit, 2,
  644. APT_String, L"-",
  645. APT_String, pCapturedAuditEvent->szAdditionalInfo,
  646. APT_String, pCapturedAuditEvent->szAdditionalInfo2,
  647. APT_Ulong | AP_FormatHex, MaskToAudit
  648. );
  649. if (!b)
  650. {
  651. #ifdef AUTHZ_DEBUG_QUEUE
  652. DbgPrint("AuthzInitializeAuditParams failed %d\n", GetLastError());
  653. #endif
  654. goto Cleanup;
  655. }
  656. }
  657. //
  658. // Replace the SID in the AUDIT_PARAMS with the SID of the current Client Context.
  659. //
  660. if (AUTHZ_NON_NULL_PTR(pAuthzClientContext->Sids[0].Sid))
  661. {
  662. //
  663. // Free an existing sid if alloc'd from heap
  664. //
  665. if (pCapturedAuditEvent->pAuditParams->Parameters[0].Data0 &&
  666. pCapturedAuditEvent->pAuditParams->Parameters[0].Type == APT_Sid &&
  667. (pCapturedAuditEvent->pAuditParams->Parameters[0].Flags & AUTHZP_PARAM_FREE_SID))
  668. {
  669. AuthzpFree((PVOID)(pCapturedAuditEvent->pAuditParams->Parameters[0].Data0));
  670. pCapturedAuditEvent->pAuditParams->Parameters[0].Flags &= ~AUTHZP_PARAM_FREE_SID;
  671. }
  672. pCapturedAuditEvent->pAuditParams->Parameters[0].Data0 = (ULONG_PTR) pAuthzClientContext->Sids[0].Sid;
  673. }
  674. //
  675. // At this point, AuditParams is initialized for an audit. Send to the LSA.
  676. //
  677. b = AuthziLogAuditEvent(
  678. 0,
  679. (AUTHZ_AUDIT_EVENT_HANDLE)pCapturedAuditEvent,
  680. 0
  681. );
  682. if (!b)
  683. {
  684. goto Cleanup;
  685. }
  686. Cleanup:
  687. if (ObjectTypesToAudit != &FixedObjectTypeToAudit)
  688. {
  689. AuthzpFreeNonNull(ObjectTypesToAudit);
  690. }
  691. if (pCapturedAuditEvent != (PAUTHZI_AUDIT_EVENT)pBuffer)
  692. {
  693. AuthzpFreeNonNull(pCapturedAuditEvent);
  694. }
  695. return b;
  696. }
  697. BOOL
  698. AuthzpMarshallAuditParams(
  699. OUT PAUDIT_PARAMS * ppMarshalledAuditParams,
  700. IN PAUDIT_PARAMS pAuditParams
  701. )
  702. /*++
  703. Routine Description:
  704. This routine will take an AUDIT_PARAMS structure and create a new
  705. structure that is suitable for sending to LSA. It will be allocated
  706. as a single chunk of memory.
  707. Arguments:
  708. ppMarshalledAuditParams - pointer to pointer that will receive the
  709. marshalled audit parameters. This memory is allocated within the routine.
  710. The dequeue thread frees this memory.
  711. pAuditParams - Original, unmarshalled version of the AUDIT_PARAMS.
  712. Return Value:
  713. Boolean: TRUE if success, FALSE if failure.
  714. Extended information available with GetLastError().
  715. --*/
  716. {
  717. DWORD i = 0;
  718. DWORD AuditParamsSize = 0;
  719. PAUDIT_PARAMS pMarshalledAuditParams = NULL;
  720. BOOL b = TRUE;
  721. PUCHAR Base = NULL;
  722. PUCHAR inData0 = NULL;
  723. *ppMarshalledAuditParams = NULL;
  724. //
  725. // Begin calculating the total size required for the marshalled version
  726. // of pAuditParams.
  727. //
  728. AuditParamsSize = sizeof(AUDIT_PARAMS) + sizeof(AUDIT_PARAM) * pAuditParams->Count;
  729. AuditParamsSize = PtrAlignSize( AuditParamsSize );
  730. //
  731. // Determine how much memory each parameter requires.
  732. //
  733. for (i = 0; i < pAuditParams->Count; i++)
  734. {
  735. inData0 = (PUCHAR) pAuditParams->Parameters[i].Data0;
  736. switch (pAuditParams->Parameters[i].Type)
  737. {
  738. case APT_String:
  739. {
  740. //
  741. // wcslen returns the number of characters, excluding the terminating NULL. Must check for NULL
  742. // because the AdditionalInfo string is OPTIONAL.
  743. //
  744. if (AUTHZ_NON_NULL_PTR(inData0))
  745. {
  746. AuditParamsSize += (DWORD)(sizeof(WCHAR) * wcslen((PWSTR) inData0) + sizeof(WCHAR));
  747. AuditParamsSize = PtrAlignSize( AuditParamsSize );
  748. }
  749. break;
  750. }
  751. case APT_Pointer:
  752. case APT_Ulong:
  753. case APT_Int64:
  754. case APT_LogonId:
  755. case APT_Luid:
  756. case APT_Time:
  757. {
  758. break;
  759. }
  760. case APT_Sid:
  761. {
  762. AuditParamsSize += RtlLengthSid((PSID) inData0);
  763. AuditParamsSize = PtrAlignSize( AuditParamsSize );
  764. break;
  765. }
  766. case APT_Guid:
  767. {
  768. AuditParamsSize += sizeof(GUID);
  769. AuditParamsSize = PtrAlignSize( AuditParamsSize );
  770. break;
  771. }
  772. case APT_ObjectTypeList:
  773. {
  774. AUDIT_OBJECT_TYPES * aot = (AUDIT_OBJECT_TYPES *) inData0;
  775. //
  776. // Need space for AUDIT_OBJECT_TYPES structure, and the AUDIT_OBJECT_TYPE
  777. // array that it contains.
  778. //
  779. AuditParamsSize += sizeof (AUDIT_OBJECT_TYPES);
  780. AuditParamsSize = PtrAlignSize( AuditParamsSize );
  781. AuditParamsSize += sizeof(AUDIT_OBJECT_TYPE) * aot->Count;
  782. AuditParamsSize = PtrAlignSize( AuditParamsSize );
  783. break;
  784. }
  785. default:
  786. {
  787. ASSERT(L"Invalid Authz audit parameter" && FALSE);
  788. SetLastError(ERROR_INVALID_PARAMETER);
  789. b = FALSE;
  790. break;
  791. }
  792. }
  793. if (!b)
  794. {
  795. goto Cleanup;
  796. }
  797. }
  798. //
  799. // Allocate space for the marshalled blob.
  800. //
  801. pMarshalledAuditParams = (PAUDIT_PARAMS) AuthzpAlloc(AuditParamsSize);
  802. if (AUTHZ_ALLOCATION_FAILED(pMarshalledAuditParams))
  803. {
  804. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  805. b = FALSE;
  806. goto Cleanup;
  807. }
  808. //
  809. // Set the fields of the marshalled AUDIT_PARAMS
  810. //
  811. pMarshalledAuditParams->Count = pAuditParams->Count;
  812. pMarshalledAuditParams->Flags = pAuditParams->Flags;
  813. pMarshalledAuditParams->Length = pAuditParams->Length;
  814. pMarshalledAuditParams->Parameters = (AUDIT_PARAM *)((PUCHAR)pMarshalledAuditParams + sizeof(AUDIT_PARAMS));
  815. //
  816. // Base points to the beginning of the "data" section of the marshalled space,
  817. // that is, Base is the area to copy member fields in and subsequently point at.
  818. //
  819. Base = (PUCHAR)pMarshalledAuditParams;
  820. Base += PtrAlignSize( sizeof(AUDIT_PARAMS) + sizeof(AUDIT_PARAM) * pAuditParams->Count );
  821. ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
  822. ASSERT(Base < (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
  823. //
  824. // Move the Parameters array into the marshalled blob.
  825. //
  826. RtlCopyMemory(
  827. pMarshalledAuditParams->Parameters,
  828. pAuditParams->Parameters,
  829. sizeof(AUDIT_PARAM) * pAuditParams->Count
  830. );
  831. for (i = 0; i < pMarshalledAuditParams->Count; i++)
  832. {
  833. inData0 = (PUCHAR) pAuditParams->Parameters[i].Data0;
  834. switch (pMarshalledAuditParams->Parameters[i].Type)
  835. {
  836. case APT_String:
  837. {
  838. if (AUTHZ_NON_NULL_PTR(inData0))
  839. {
  840. DWORD StringLength = (DWORD)(sizeof(WCHAR) * wcslen((PWSTR) inData0) + sizeof(WCHAR));
  841. pMarshalledAuditParams->Parameters[i].Data0 = (ULONG_PTR) Base;
  842. RtlCopyMemory(
  843. (PVOID) Base,
  844. (PWSTR) inData0,
  845. StringLength
  846. );
  847. Base += PtrAlignSize( StringLength );
  848. ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
  849. ASSERT(Base <= (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
  850. }
  851. break;
  852. }
  853. case APT_Pointer:
  854. case APT_Ulong:
  855. case APT_LogonId:
  856. case APT_Luid:
  857. case APT_Time:
  858. {
  859. break;
  860. }
  861. case APT_Sid:
  862. {
  863. DWORD SidLength = RtlLengthSid((PSID) inData0);
  864. pMarshalledAuditParams->Parameters[i].Data0 = (ULONG_PTR) Base;
  865. RtlCopyMemory(
  866. (PVOID) Base,
  867. (PSID) inData0,
  868. SidLength
  869. );
  870. Base += PtrAlignSize( SidLength );
  871. ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
  872. ASSERT(Base <= (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
  873. break;
  874. }
  875. case APT_Guid:
  876. {
  877. pMarshalledAuditParams->Parameters[i].Data0 = (ULONG_PTR) Base;
  878. RtlCopyMemory(
  879. (PVOID) Base,
  880. (GUID *) inData0,
  881. sizeof(GUID)
  882. );
  883. Base += PtrAlignSize( sizeof(GUID) );
  884. ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
  885. ASSERT(Base <= (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
  886. break;
  887. }
  888. case APT_ObjectTypeList:
  889. {
  890. AUDIT_OBJECT_TYPES *aot = (AUDIT_OBJECT_TYPES *) inData0;
  891. DWORD OTLength = sizeof(AUDIT_OBJECT_TYPE) * aot->Count;
  892. pMarshalledAuditParams->Parameters[i].Data0 = (ULONG_PTR) Base;
  893. //
  894. // Copy the AUDIT_OBJECT_TYPES structure
  895. //
  896. RtlCopyMemory(
  897. (PVOID) Base,
  898. aot,
  899. sizeof(AUDIT_OBJECT_TYPES)
  900. );
  901. Base += PtrAlignSize( sizeof(AUDIT_OBJECT_TYPES) );
  902. //
  903. // Point the pObjectTypes field at the end of the copied blob.
  904. //
  905. ((AUDIT_OBJECT_TYPES *)pMarshalledAuditParams->Parameters[i].Data0)->pObjectTypes = (AUDIT_OBJECT_TYPE *) Base;
  906. //
  907. // Copy the AUDIT_OBJECT_TYPE array (pObjectTypes)
  908. //
  909. RtlCopyMemory(
  910. (PVOID) Base,
  911. (AUDIT_OBJECT_TYPE *) aot->pObjectTypes,
  912. OTLength
  913. );
  914. Base += PtrAlignSize( OTLength );
  915. ASSERT(Base > (PUCHAR)pMarshalledAuditParams);
  916. ASSERT(Base <= (PUCHAR)((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
  917. break;
  918. }
  919. default:
  920. {
  921. ASSERT(L"Invalid Authz audit parameter" && FALSE);
  922. b = FALSE;
  923. SetLastError(ERROR_INVALID_PARAMETER);
  924. break;
  925. }
  926. }
  927. if (!b)
  928. {
  929. goto Cleanup;
  930. }
  931. }
  932. //
  933. // Sanity check on the Base value. If this assertion passes, then I have
  934. // not exceeded my allocated space.
  935. //
  936. ASSERT(Base == ((PUCHAR)pMarshalledAuditParams + AuditParamsSize));
  937. Cleanup:
  938. if (b)
  939. {
  940. *ppMarshalledAuditParams = pMarshalledAuditParams;
  941. }
  942. else
  943. {
  944. AuthzpFreeNonNull(pMarshalledAuditParams);
  945. }
  946. return b;
  947. }