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.

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