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

686 lines
20 KiB

  1. /*******************************************************************************
  2. * AUDIT.C
  3. *
  4. * This module contains the routines for logging audit events
  5. *
  6. * Copyright (C) 1997-1999 Microsoft Corp.
  7. *******************************************************************************/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. #include <rpc.h>
  11. #include <msaudite.h>
  12. #include <ntlsa.h>
  13. #include <authz.h>
  14. #include <authzi.h>
  15. HANDLE AuditLogHandle = NULL;
  16. HANDLE SystemLogHandle = NULL;
  17. #define MAX_INSTANCE_MEMORYERR 20
  18. /*
  19. * Global data
  20. */
  21. //Authz Changes
  22. AUTHZ_RESOURCE_MANAGER_HANDLE hRM = NULL;
  23. extern RTL_CRITICAL_SECTION g_AuthzCritSection;
  24. //END Authz Changes
  25. /*
  26. * External procedures defined
  27. */
  28. VOID
  29. AuditEvent( PWINSTATION pWinstation, ULONG EventId );
  30. NTSTATUS
  31. AuthzReportEventW( IN PAUTHZ_AUDIT_EVENT_TYPE_HANDLE pHAET,
  32. IN DWORD Flags,
  33. IN ULONG EventId,
  34. IN PSID pUserID,
  35. IN USHORT NumStrings,
  36. IN ULONG DataSize OPTIONAL, //Future - DO NOT USE
  37. IN PWSTR* Strings,
  38. IN PVOID Data OPTIONAL //Future - DO NOT USE
  39. );
  40. BOOL AuthzInit( IN DWORD Flags,
  41. IN USHORT CategoryID,
  42. IN USHORT AuditID,
  43. IN USHORT ParameterCount,
  44. OUT PAUTHZ_AUDIT_EVENT_TYPE_HANDLE phAuditEventType
  45. );
  46. BOOLEAN
  47. AuditingEnabled ();
  48. VOID
  49. AuditEnd();
  50. /*
  51. * Internal procedures defined
  52. */
  53. NTSTATUS
  54. AdtBuildLuidString(
  55. IN PLUID Value,
  56. OUT PUNICODE_STRING ResultantString
  57. );
  58. BOOLEAN
  59. IsAuditLogFull(
  60. HANDLE LogHandle
  61. )
  62. {
  63. BOOLEAN retval = TRUE;
  64. EVENTLOG_FULL_INFORMATION EventLogFullInformation;
  65. DWORD dwBytesNeeded;
  66. if (GetEventLogInformation(LogHandle,
  67. EVENTLOG_FULL_INFO,
  68. &EventLogFullInformation,
  69. sizeof(EventLogFullInformation),
  70. &dwBytesNeeded ) ) {
  71. if (EventLogFullInformation.dwFull == FALSE) {
  72. retval = FALSE;
  73. }
  74. }
  75. return retval;
  76. }
  77. NTSTATUS
  78. AdtBuildLuidString(
  79. IN PLUID Value,
  80. OUT PUNICODE_STRING ResultantString
  81. )
  82. /*++
  83. Routine Description:
  84. This function builds a unicode string representing the passed LUID.
  85. The resultant string will be formatted as follows:
  86. (0x00005678,0x12340000)
  87. Arguments:
  88. Value - The value to be transformed to printable format (Unicode string).
  89. ResultantString - Points to the unicode string header. The body of this
  90. unicode string will be set to point to the resultant output value
  91. if successful. Otherwise, the Buffer field of this parameter
  92. will be set to NULL.
  93. FreeWhenDone - If TRUE, indicates that the body of the ResultantString
  94. must be freed to process heap when no longer needed.
  95. Return Values:
  96. STATUS_NO_MEMORY - indicates memory could not be allocated
  97. for the string body.
  98. All other Result Codes are generated by called routines.
  99. --*/
  100. {
  101. NTSTATUS Status;
  102. UNICODE_STRING IntegerString;
  103. ULONG Buffer[(16*sizeof(WCHAR))/sizeof(ULONG)];
  104. IntegerString.Buffer = (PWCHAR)&Buffer[0];
  105. IntegerString.MaximumLength = 16*sizeof(WCHAR);
  106. //
  107. // Length (in WCHARS) is 3 for (0x
  108. // 10 for 1st hex number
  109. // 3 for ,0x
  110. // 10 for 2nd hex number
  111. // 1 for )
  112. // 1 for null termination
  113. //
  114. ResultantString->Length = 0;
  115. ResultantString->MaximumLength = 28 * sizeof(WCHAR);
  116. ResultantString->Buffer = RtlAllocateHeap( RtlProcessHeap(), 0,
  117. ResultantString->MaximumLength);
  118. if (ResultantString->Buffer == NULL) {
  119. return(STATUS_NO_MEMORY);
  120. }
  121. Status = RtlAppendUnicodeToString( ResultantString, L"(0x" );
  122. Status = RtlIntegerToUnicodeString( Value->HighPart, 16, &IntegerString );
  123. Status = RtlAppendUnicodeToString( ResultantString, IntegerString.Buffer );
  124. Status = RtlAppendUnicodeToString( ResultantString, L",0x" );
  125. Status = RtlIntegerToUnicodeString( Value->LowPart, 16, &IntegerString );
  126. Status = RtlAppendUnicodeToString( ResultantString, IntegerString.Buffer );
  127. Status = RtlAppendUnicodeToString( ResultantString, L")" );
  128. return(STATUS_SUCCESS);
  129. }
  130. VOID
  131. AuditEvent( PWINSTATION pWinstation, ULONG EventId )
  132. {
  133. NTSTATUS Status, Status2;
  134. UNICODE_STRING LuidString;
  135. PWSTR StringPointerArray[6];
  136. USHORT StringIndex = 0;
  137. TOKEN_STATISTICS TokenInformation;
  138. ULONG ReturnLength;
  139. BOOLEAN WasEnabled;
  140. LUID LogonId = {0,0};
  141. AUTHZ_AUDIT_EVENT_TYPE_HANDLE hAET = NULL;
  142. if (!AuditingEnabled() )
  143. return;
  144. Status = RtlAdjustPrivilege(
  145. SE_SECURITY_PRIVILEGE,
  146. TRUE, // Enable the PRIVILEGE
  147. FALSE, // Don't Use Thread token (under impersonation)
  148. &WasEnabled
  149. );
  150. if ( Status == STATUS_NO_TOKEN ) {
  151. DBGPRINT(("TERMSRV: AuditEvent: RtlAdjustPrivilege failure 0x%x\n",Status));
  152. return;
  153. }
  154. //
  155. //AUTHZ Changes
  156. //
  157. if( !AuthzInit( 0, SE_CATEGID_LOGON, (USHORT)EventId, 6, &hAET ))
  158. goto badAuthzInit;
  159. if (pWinstation->UserName && (wcslen(pWinstation->UserName) > 0)) {
  160. StringPointerArray[StringIndex] = pWinstation->UserName;
  161. } else {
  162. StringPointerArray[StringIndex] = L"Unknown";
  163. }
  164. StringIndex++;
  165. if (pWinstation->Domain && (wcslen(pWinstation->Domain) > 0)) {
  166. StringPointerArray[StringIndex] = pWinstation->Domain;
  167. } else {
  168. StringPointerArray [StringIndex] = L"Unknown";
  169. }
  170. StringIndex++;
  171. if (pWinstation->UserToken != NULL) {
  172. Status = NtQueryInformationToken (
  173. pWinstation->UserToken,
  174. TokenStatistics,
  175. &TokenInformation,
  176. sizeof(TokenInformation),
  177. &ReturnLength
  178. );
  179. if (NT_SUCCESS(Status)) {
  180. Status = AdtBuildLuidString( &(TokenInformation.AuthenticationId), &LuidString );
  181. } else {
  182. Status = AdtBuildLuidString( &LogonId, &LuidString );
  183. }
  184. } else {
  185. Status = AdtBuildLuidString( &LogonId, &LuidString );
  186. }
  187. StringPointerArray[StringIndex] = LuidString.Buffer;
  188. StringIndex++;
  189. if (pWinstation->WinStationName && (wcslen(pWinstation->WinStationName) > 0)) {
  190. StringPointerArray[StringIndex] = pWinstation->WinStationName;
  191. } else {
  192. StringPointerArray[StringIndex] = L"Unknown" ;
  193. }
  194. StringIndex++;
  195. if (pWinstation->Client.ClientName && (wcslen(pWinstation->Client.ClientName) > 0)) {
  196. StringPointerArray[StringIndex] = pWinstation->Client.ClientName;
  197. } else {
  198. StringPointerArray[StringIndex] = L"Unknown";
  199. }
  200. StringIndex++;
  201. if (pWinstation->Client.ClientAddress && (wcslen(pWinstation->Client.ClientAddress) > 0)) {
  202. StringPointerArray[StringIndex] = pWinstation->Client.ClientAddress;
  203. } else {
  204. StringPointerArray[StringIndex] = L"Unknown";
  205. }
  206. StringIndex++;
  207. //Authz Changes
  208. Status = AuthzReportEventW( &hAET,
  209. APF_AuditSuccess,
  210. EventId,
  211. pWinstation->pUserSid,
  212. StringIndex,
  213. 0,
  214. StringPointerArray,
  215. NULL
  216. );
  217. //end authz changes
  218. if ( !NT_SUCCESS(Status))
  219. DBGPRINT(("Termsrv - failed to report event \n" ));
  220. if( !WasEnabled ) {
  221. /*
  222. * Principle of least rights says to not go around with privileges
  223. * held you do not need. So we must disable the shutdown privilege
  224. * if it was just a logoff force.
  225. */
  226. Status2 = RtlAdjustPrivilege(
  227. SE_SECURITY_PRIVILEGE,
  228. FALSE, // Disable the PRIVILEGE
  229. FALSE, // Don't Use Thread token
  230. &WasEnabled
  231. );
  232. }
  233. badAuthzInit:
  234. if( hAET != NULL )
  235. AuthziFreeAuditEventType( hAET );
  236. }
  237. /***************************************************************************\
  238. * AuditingEnabled
  239. *
  240. * Purpose : Check auditing via LSA.
  241. *
  242. * Returns: TRUE on success, FALSE on failure
  243. *
  244. * History:
  245. * 5-6-92 DaveHart Created.
  246. \***************************************************************************/
  247. BOOLEAN
  248. AuditingEnabled()
  249. {
  250. NTSTATUS Status, IgnoreStatus;
  251. PPOLICY_AUDIT_EVENTS_INFO AuditInfo;
  252. OBJECT_ATTRIBUTES ObjectAttributes;
  253. SECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
  254. LSA_HANDLE PolicyHandle;
  255. //
  256. // Set up the Security Quality Of Service for connecting to the
  257. // LSA policy object.
  258. //
  259. SecurityQualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
  260. SecurityQualityOfService.ImpersonationLevel = SecurityImpersonation;
  261. SecurityQualityOfService.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  262. SecurityQualityOfService.EffectiveOnly = FALSE;
  263. //
  264. // Set up the object attributes to open the Lsa policy object
  265. //
  266. InitializeObjectAttributes(
  267. &ObjectAttributes,
  268. NULL,
  269. 0L,
  270. NULL,
  271. NULL
  272. );
  273. ObjectAttributes.SecurityQualityOfService = &SecurityQualityOfService;
  274. //
  275. // Open the local LSA policy object
  276. //
  277. Status = LsaOpenPolicy(
  278. NULL,
  279. &ObjectAttributes,
  280. POLICY_VIEW_AUDIT_INFORMATION | POLICY_SET_AUDIT_REQUIREMENTS,
  281. &PolicyHandle
  282. );
  283. if (!NT_SUCCESS(Status)) {
  284. DBGPRINT(("Termsrv: Failed to open LsaPolicyObject Status = 0x%lx", Status));
  285. return FALSE;
  286. }
  287. Status = LsaQueryInformationPolicy(
  288. PolicyHandle,
  289. PolicyAuditEventsInformation,
  290. (PVOID *)&AuditInfo
  291. );
  292. IgnoreStatus = LsaClose(PolicyHandle);
  293. ASSERT(NT_SUCCESS(IgnoreStatus));
  294. if (!NT_SUCCESS(Status)) {
  295. DBGPRINT(("Termsrv: Failed to query audit event info Status = 0x%lx", Status));
  296. return FALSE;
  297. }
  298. return (AuditInfo->AuditingMode &&
  299. ((AuditInfo->EventAuditingOptions)[AuditCategoryLogon] &
  300. POLICY_AUDIT_EVENT_SUCCESS));
  301. }
  302. VOID WriteErrorLogEntry(
  303. IN NTSTATUS NtStatusCode,
  304. IN PVOID pRawData,
  305. IN ULONG RawDataLength
  306. )
  307. {
  308. NTSTATUS Status;
  309. ULONG Length;
  310. if ( !SystemLogHandle ) {
  311. UNICODE_STRING ModuleName;
  312. RtlInitUnicodeString( &ModuleName, L"TermService");
  313. Status = ElfRegisterEventSourceW( NULL, &ModuleName, &SystemLogHandle );
  314. if (!NT_SUCCESS(Status)) {
  315. DBGPRINT(("Termsrv - failed to open System log file\n"));
  316. return;
  317. }
  318. }
  319. if (IsAuditLogFull(SystemLogHandle))
  320. return;
  321. Status = ElfReportEventW( SystemLogHandle,
  322. EVENTLOG_ERROR_TYPE,
  323. 0,
  324. NtStatusCode,
  325. NULL,
  326. 0,
  327. RawDataLength,
  328. NULL,
  329. pRawData,
  330. 0,
  331. NULL,
  332. NULL );
  333. if ( !NT_SUCCESS(Status))
  334. DBGPRINT(("Termsrv - failed to report event \n" ));
  335. }
  336. // This function is duplicated in \nt\termsrv\sessdir\dis\tssdis.cpp.
  337. /****************************************************************************/
  338. // PostErrorValueEvent
  339. //
  340. // Utility function used to create a system log error event containing one
  341. // hex DWORD error code value.
  342. /****************************************************************************/
  343. void PostErrorValueEvent(unsigned EventCode, DWORD ErrVal)
  344. {
  345. HANDLE hLog;
  346. WCHAR hrString[128];
  347. PWSTR String = NULL;
  348. extern WCHAR gpszServiceName[];
  349. static DWORD numInstances = 0;
  350. //
  351. //count the numinstances of out of memory error, if this is more than
  352. //a specified number, we just won't log them
  353. //
  354. if( STATUS_COMMITMENT_LIMIT == ErrVal )
  355. {
  356. if( numInstances > MAX_INSTANCE_MEMORYERR )
  357. return;
  358. //
  359. //if applicable, tell the user that we won't log any more of the out of memory errors
  360. //
  361. if( numInstances >= MAX_INSTANCE_MEMORYERR - 1 ) {
  362. wsprintfW(hrString, L"0x%X. This type of error will not be logged again to avoid clutter.", ErrVal);
  363. String = hrString;
  364. }
  365. numInstances++;
  366. }
  367. hLog = RegisterEventSource(NULL, gpszServiceName);
  368. if (hLog != NULL) {
  369. if( NULL == String ) {
  370. wsprintfW(hrString, L"0x%X", ErrVal);
  371. String = hrString;
  372. }
  373. ReportEvent(hLog, EVENTLOG_ERROR_TYPE, 0, EventCode, NULL, 1, 0,
  374. (const WCHAR **)&String, NULL);
  375. DeregisterEventSource(hLog);
  376. }
  377. }
  378. /*************************************************************
  379. * AuthzInit Purpose : Initialize authz for logging an event to the security log
  380. *Flags - unused
  381. *Category Id - Security Category to which this event belongs
  382. *Audit Id - An id for the event
  383. *PArameter count - Number of parameters that will be passed to the logging function later
  384. ****************************************************************/
  385. BOOL AuthzInit( IN DWORD Flags,
  386. IN USHORT CategoryID,
  387. IN USHORT AuditID,
  388. IN USHORT ParameterCount,
  389. OUT PAUTHZ_AUDIT_EVENT_TYPE_HANDLE phAuditEventType
  390. )
  391. {
  392. BOOL fAuthzInit = TRUE;
  393. if( NULL == phAuditEventType )
  394. goto badAuthzInit;
  395. *phAuditEventType = NULL;
  396. //
  397. //only one thread can create hRM
  398. //
  399. RtlEnterCriticalSection( &g_AuthzCritSection );
  400. if( NULL == hRM )
  401. {
  402. fAuthzInit = AuthzInitializeResourceManager( 0,
  403. NULL,
  404. NULL,
  405. NULL,
  406. L"Terminal Server",
  407. &hRM
  408. );
  409. if ( !fAuthzInit )
  410. {
  411. DBGPRINT(("TERMSRV: AuditEvent: AuthzInitializeResourceManager failed with %d\n", GetLastError()));
  412. goto badAuthzInit;
  413. }
  414. }
  415. RtlLeaveCriticalSection( &g_AuthzCritSection );
  416. fAuthzInit = AuthziInitializeAuditEventType( Flags,
  417. CategoryID,
  418. AuditID,
  419. ParameterCount,
  420. phAuditEventType
  421. );
  422. if ( !fAuthzInit )
  423. {
  424. DBGPRINT(("TERMSRV: AuditEvent: AuthziInitializeAuditEventType failed with %d\n", GetLastError()));
  425. goto badAuthzInit;
  426. }
  427. badAuthzInit:
  428. if( !fAuthzInit )
  429. {
  430. if( NULL != *phAuditEventType )
  431. {
  432. if( !AuthziFreeAuditEventType( *phAuditEventType ))
  433. DBGPRINT(("TERMSRV: AuditEvent: AuthziFreeAuditEventType failed with %d\n", GetLastError()));
  434. *phAuditEventType = NULL;
  435. }
  436. }
  437. // if( fAuthzInit )
  438. // DBGPRINT(("TERMSRV: Successfully initialized authz = %d\n", AuditID));
  439. return fAuthzInit;
  440. }
  441. /*********************************************************
  442. * Purpose : Log an Event to the security log
  443. * In pHAET
  444. * Audit Event type obtained from a call to AuthzInit() above
  445. * In Flags
  446. * APF_AuditSuccess or others as listed in the header file
  447. * pUserSID - Unused
  448. * NumStrings - Number of strings contained within "Strings"
  449. * DataSize - unused
  450. * Strings- Pointer to a sequence of unicode strings
  451. * Data - unused
  452. *
  453. **********************************************************/
  454. NTSTATUS
  455. AuthzReportEventW( IN PAUTHZ_AUDIT_EVENT_TYPE_HANDLE pHAET,
  456. IN DWORD Flags,
  457. IN ULONG EventId,
  458. IN PSID pUserSID,
  459. IN USHORT NumStrings,
  460. IN ULONG DataSize OPTIONAL, //Future - DO NOT USE
  461. IN PWSTR* Strings,
  462. IN PVOID Data OPTIONAL //Future - DO NOT USE
  463. )
  464. {
  465. NTSTATUS status = STATUS_ACCESS_DENIED;
  466. AUTHZ_AUDIT_EVENT_HANDLE hAE = NULL;
  467. BOOL fSuccess = FALSE;
  468. PAUDIT_PARAMS pParams = NULL;
  469. if( NULL == hRM || NULL == pHAET || *pHAET == NULL )
  470. return status;
  471. fSuccess = AuthziAllocateAuditParams( &pParams, NumStrings );
  472. if ( !fSuccess )
  473. {
  474. DBGPRINT(("TERMSRV: AuditEvent: AuthzAllocateAuditParams failed with %d\n", GetLastError()));
  475. goto BadAuditEvent;
  476. }
  477. if( 6 == NumStrings )
  478. {
  479. fSuccess = AuthziInitializeAuditParamsWithRM( Flags,
  480. hRM,
  481. NumStrings,
  482. pParams,
  483. APT_String, Strings[0],
  484. APT_String, Strings[1],
  485. APT_String, Strings[2],
  486. APT_String, Strings[3],
  487. APT_String, Strings[4],
  488. APT_String, Strings[5]
  489. );
  490. }
  491. else if( 0 == NumStrings )
  492. {
  493. fSuccess = AuthziInitializeAuditParamsWithRM( Flags,
  494. hRM,
  495. NumStrings,
  496. pParams
  497. );
  498. }
  499. else
  500. {
  501. //we don't support anything else
  502. fSuccess = FALSE;
  503. DBGPRINT(("TERMSRV: AuditEvent: unsupported audit type \n"));
  504. goto BadAuditEvent;
  505. }
  506. if ( !fSuccess )
  507. {
  508. DBGPRINT(("TERMSRV: AuditEvent: AuthziInitializeAuditParamsWithRM failed with %d\n", GetLastError()));
  509. goto BadAuditEvent;
  510. }
  511. fSuccess = AuthziInitializeAuditEvent( 0,
  512. hRM,
  513. *pHAET,
  514. pParams,
  515. NULL,
  516. INFINITE,
  517. L"",
  518. L"",
  519. L"",
  520. L"",
  521. &hAE
  522. );
  523. if ( !fSuccess )
  524. {
  525. DBGPRINT(("TERMSRV: AuditEvent: AuthziInitializeAuditEvent failed with %d\n", GetLastError()));
  526. goto BadAuditEvent;
  527. }
  528. fSuccess = AuthziLogAuditEvent( 0,
  529. hAE,
  530. NULL
  531. );
  532. if ( !fSuccess )
  533. {
  534. DBGPRINT(("TERMSRV: AuditEvent: AuthziLogAuditEvent failed with %d\n", GetLastError()));
  535. goto BadAuditEvent;
  536. }
  537. BadAuditEvent:
  538. if( hAE )
  539. AuthzFreeAuditEvent( hAE );
  540. if( pParams )
  541. AuthziFreeAuditParams( pParams );
  542. if( fSuccess )
  543. status = STATUS_SUCCESS;
  544. //if( fSuccess )
  545. // DBGPRINT(("TERMSRV: Successfully audited event with authz= %d\n", EventId));
  546. return status;
  547. }
  548. //
  549. //should only be called once per our process
  550. //
  551. VOID AuditEnd()
  552. {
  553. if( NULL != hRM )
  554. {
  555. if( !AuthzFreeResourceManager( hRM ))
  556. DBGPRINT(("TERMSRV: AuditEvent: AuthzFreeResourceManager failed with %d\n", GetLastError()));
  557. hRM = NULL;
  558. }
  559. }