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.

777 lines
19 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. eventlog.c
  5. Abstract:
  6. This module provides support routines for eventlogging.
  7. Author:
  8. Madan Appiah (madana) 27-Jul-1992
  9. Environment:
  10. Contains NT specific code.
  11. Revision History:
  12. --*/
  13. #include <nt.h>
  14. #include <ntrtl.h>
  15. #include <nturtl.h>
  16. #include <windef.h> // DWORD.
  17. #include <winbase.h> // event log apis
  18. #include <winerror.h> // NO_ERROR
  19. #include <lmcons.h> // NET_API_STATUS.
  20. #include <lmalert.h> // Alert defines
  21. #include <netlib.h> // These routines
  22. #include <netlogon.h> // needed by logonp.h
  23. #include <logonp.h> // NetpLogon routines
  24. #include <tstr.h> // ultow()
  25. //
  26. // Structure describing the entire list of logged events.
  27. //
  28. typedef struct _NL_EVENT_LIST {
  29. CRITICAL_SECTION EventListCritSect;
  30. LIST_ENTRY EventList;
  31. // Number of milli-seconds to keep EventList entry for.
  32. ULONG DuplicateEventlogTimeout;
  33. // Event source
  34. LPWSTR Source;
  35. } NL_EVENT_LIST, *PNL_EVENT_LIST;
  36. //
  37. // Structure describing an event that has already been logged.
  38. //
  39. typedef struct _NL_EVENT_ENTRY {
  40. LIST_ENTRY Next;
  41. LARGE_INTEGER FirstLogTime;
  42. DWORD EventId;
  43. DWORD EventType;
  44. DWORD EventCategory;
  45. LPBYTE RawDataBuffer;
  46. DWORD RawDataSize;
  47. LPWSTR *StringArray;
  48. DWORD StringCount;
  49. DWORD EventsLogged; // total times event encountered.
  50. } NL_EVENT_ENTRY, *PNL_EVENT_ENTRY;
  51. DWORD
  52. NetpWriteEventlogEx(
  53. LPWSTR Source,
  54. DWORD EventID,
  55. DWORD EventType,
  56. DWORD EventCategory,
  57. DWORD NumStrings,
  58. LPWSTR *Strings,
  59. DWORD DataLength,
  60. LPVOID Data
  61. )
  62. /*++
  63. Routine Description:
  64. This function writes the specified (EventID) log at the end of the
  65. eventlog.
  66. Arguments:
  67. Source - Points to a null-terminated string that specifies the name
  68. of the module referenced. The node must exist in the
  69. registration database, and the module name has the
  70. following format:
  71. \EventLog\System\Lanmanworkstation
  72. EventID - The specific event identifier. This identifies the
  73. message that goes with this event.
  74. EventType - Specifies the type of event being logged. This
  75. parameter can have one of the following
  76. values:
  77. Value Meaning
  78. EVENTLOG_ERROR_TYPE Error event
  79. EVENTLOG_WARNING_TYPE Warning event
  80. EVENTLOG_INFORMATION_TYPE Information event
  81. NumStrings - Specifies the number of strings that are in the array
  82. at 'Strings'. A value of zero indicates no strings
  83. are present.
  84. Strings - Points to a buffer containing an array of null-terminated
  85. strings that are merged into the message before
  86. displaying to the user. This parameter must be a valid
  87. pointer (or NULL), even if cStrings is zero.
  88. DataLength - Specifies the number of bytes of event-specific raw
  89. (binary) data to write to the log. If cbData is
  90. zero, no event-specific data is present.
  91. Data - Buffer containing the raw data. This parameter must be a
  92. valid pointer (or NULL), even if cbData is zero.
  93. Return Value:
  94. Returns the WIN32 extended error obtained by GetLastError().
  95. NOTE : This function works slow since it calls the open and close
  96. eventlog source everytime.
  97. --*/
  98. {
  99. HANDLE EventlogHandle;
  100. DWORD ReturnCode;
  101. //
  102. // open eventlog section.
  103. //
  104. EventlogHandle = RegisterEventSourceW(
  105. NULL,
  106. Source
  107. );
  108. if (EventlogHandle == NULL) {
  109. ReturnCode = GetLastError();
  110. goto Cleanup;
  111. }
  112. //
  113. // Log the error code specified
  114. //
  115. if( !ReportEventW(
  116. EventlogHandle,
  117. (WORD)EventType,
  118. (WORD)EventCategory, // event category
  119. EventID,
  120. NULL,
  121. (WORD)NumStrings,
  122. DataLength,
  123. Strings,
  124. Data
  125. ) ) {
  126. ReturnCode = GetLastError();
  127. goto Cleanup;
  128. }
  129. ReturnCode = NO_ERROR;
  130. Cleanup:
  131. if( EventlogHandle != NULL ) {
  132. DeregisterEventSource(EventlogHandle);
  133. }
  134. return ReturnCode;
  135. }
  136. DWORD
  137. NetpWriteEventlog(
  138. LPWSTR Source,
  139. DWORD EventID,
  140. DWORD EventType,
  141. DWORD NumStrings,
  142. LPWSTR *Strings,
  143. DWORD DataLength,
  144. LPVOID Data
  145. )
  146. {
  147. return NetpWriteEventlogEx(
  148. Source,
  149. EventID,
  150. EventType,
  151. 0,
  152. NumStrings,
  153. Strings,
  154. DataLength,
  155. Data
  156. );
  157. }
  158. DWORD
  159. NetpRaiseAlert(
  160. IN LPWSTR ServiceName,
  161. IN DWORD alert_no,
  162. IN LPWSTR *string_array
  163. )
  164. /*++
  165. Routine Description:
  166. Raise NETLOGON specific Admin alerts.
  167. Arguments:
  168. alert_no - The alert to be raised, text in alertmsg.h
  169. string_array - array of strings terminated by NULL string.
  170. Return Value:
  171. None.
  172. --*/
  173. {
  174. NET_API_STATUS NetStatus;
  175. LPWSTR *SArray;
  176. PCHAR Next;
  177. PCHAR End;
  178. char message[ALERTSZ + sizeof(ADMIN_OTHER_INFO)];
  179. PADMIN_OTHER_INFO admin = (PADMIN_OTHER_INFO) message;
  180. //
  181. // Build the variable data
  182. //
  183. admin->alrtad_errcode = alert_no;
  184. admin->alrtad_numstrings = 0;
  185. Next = (PCHAR) ALERT_VAR_DATA(admin);
  186. End = Next + ALERTSZ;
  187. //
  188. // now take care of (optional) char strings
  189. //
  190. for( SArray = string_array; *SArray != NULL; SArray++ ) {
  191. DWORD StringLen;
  192. StringLen = (wcslen(*SArray) + 1) * sizeof(WCHAR);
  193. if( Next + StringLen < End ) {
  194. //
  195. // copy next string.
  196. //
  197. RtlCopyMemory(Next, *SArray, StringLen);
  198. Next += StringLen;
  199. admin->alrtad_numstrings++;
  200. } else {
  201. return ERROR_BUFFER_OVERFLOW;
  202. }
  203. }
  204. //
  205. // Call alerter.
  206. //
  207. NetStatus = NetAlertRaiseEx(
  208. ALERT_ADMIN_EVENT,
  209. message,
  210. (DWORD)((PCHAR)Next - (PCHAR)message),
  211. ServiceName );
  212. return NetStatus;
  213. }
  214. HANDLE
  215. NetpEventlogOpen (
  216. IN LPWSTR Source,
  217. IN ULONG DuplicateEventlogTimeout
  218. )
  219. /*++
  220. Routine Description:
  221. This routine open a context that keeps track of events that have been logged
  222. in the recent past.
  223. Arguments:
  224. Source - Name of the service opening the eventlog
  225. DuplicateEventlogTimeout - Number of milli-seconds to keep EventList entry for.
  226. Return Value:
  227. Handle to be passed to related routines.
  228. NULL: if memory could not be allocated.
  229. --*/
  230. {
  231. PNL_EVENT_LIST EventList;
  232. LPBYTE Where;
  233. //
  234. // Allocate a buffer to keep the context in.
  235. //
  236. EventList = LocalAlloc( 0,
  237. sizeof(NL_EVENT_LIST) +
  238. wcslen(Source) * sizeof(WCHAR) + sizeof(WCHAR) );
  239. if ( EventList == NULL ) {
  240. return NULL;
  241. }
  242. //
  243. // Initialize the critical section
  244. //
  245. try {
  246. InitializeCriticalSection( &EventList->EventListCritSect );
  247. } except( EXCEPTION_EXECUTE_HANDLER ) {
  248. LocalFree( EventList );
  249. return NULL;
  250. }
  251. //
  252. // Initialize the buffer
  253. //
  254. InitializeListHead( &EventList->EventList );
  255. EventList->DuplicateEventlogTimeout = DuplicateEventlogTimeout;
  256. //
  257. // Copy the service name into the buffer
  258. //
  259. Where = (LPBYTE)(EventList + 1);
  260. wcscpy( (LPWSTR)Where, Source );
  261. EventList->Source = (LPWSTR) Where;
  262. return EventList;
  263. }
  264. DWORD
  265. NetpEventlogWriteEx (
  266. IN HANDLE NetpEventHandle,
  267. IN DWORD EventType,
  268. IN DWORD EventCategory,
  269. IN DWORD EventId,
  270. IN DWORD StringCount,
  271. IN DWORD RawDataSize,
  272. IN LPWSTR *StringArray,
  273. IN LPVOID pvRawDataBuffer OPTIONAL
  274. )
  275. /*++
  276. Routine Description:
  277. Stub routine for calling writing Event Log and skipping duplicates
  278. Arguments:
  279. NetpEventHandle - Handle from NetpEventlogOpen
  280. EventId - event log ID.
  281. EventType - Type of event.
  282. RawDataBuffer - Data to be logged with the error.
  283. numbyte - Size in bytes of "RawDataBuffer"
  284. StringArray - array of null-terminated strings.
  285. StringCount - number of zero terminated strings in "StringArray". The following
  286. flags can be OR'd in to the count:
  287. NETP_LAST_MESSAGE_IS_NTSTATUS
  288. NETP_LAST_MESSAGE_IS_NETSTATUS
  289. NETP_ALLOW_DUPLICATE_EVENTS
  290. NETP_RAISE_ALERT_TOO
  291. Return Value:
  292. Win 32 status of the operation.
  293. ERROR_ALREAY_EXISTS: Success status indicating the message was already logged
  294. --*/
  295. {
  296. DWORD ErrorCode;
  297. DWORD AlertErrorCode = NO_ERROR;
  298. WCHAR ErrorNumberBuffer[25];
  299. PLIST_ENTRY ListEntry;
  300. ULONG StringIndex;
  301. BOOLEAN AllowDuplicateEvents;
  302. BOOLEAN RaiseAlertToo;
  303. PNL_EVENT_ENTRY EventEntry;
  304. PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
  305. LPBYTE RawDataBuffer = (LPBYTE)pvRawDataBuffer;
  306. //
  307. // Remove sundry flags
  308. //
  309. EnterCriticalSection( &EventList->EventListCritSect );
  310. AllowDuplicateEvents = (StringCount & NETP_ALLOW_DUPLICATE_EVENTS) != 0;
  311. StringCount &= ~NETP_ALLOW_DUPLICATE_EVENTS;
  312. RaiseAlertToo = (StringCount & NETP_RAISE_ALERT_TOO) != 0;
  313. StringCount &= ~NETP_RAISE_ALERT_TOO;
  314. //
  315. // If an NT status code was passed in,
  316. // convert it to a net status code.
  317. //
  318. if ( StringCount & NETP_LAST_MESSAGE_IS_NTSTATUS ) {
  319. StringCount &= ~NETP_LAST_MESSAGE_IS_NTSTATUS;
  320. //
  321. // Do the "better" error mapping when eventviewer ParameterMessageFile
  322. // can be a list of files. Then, add netmsg.dll to the list.
  323. //
  324. // StringArray[((StringCount&NETP_STRING_COUNT_MASK)-1] = (LPWSTR) NetpNtStatusToApiStatus( (NTSTATUS) StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1] );
  325. StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1] = (LPWSTR) (ULONG_PTR) RtlNtStatusToDosError( (NTSTATUS) ((ULONG_PTR)StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1]) );
  326. StringCount |= NETP_LAST_MESSAGE_IS_NETSTATUS;
  327. }
  328. //
  329. // If a net/windows status code was passed in,
  330. // convert to the the %%N format the eventviewer knows.
  331. //
  332. if ( StringCount & NETP_LAST_MESSAGE_IS_NETSTATUS ) {
  333. StringCount &= ~NETP_LAST_MESSAGE_IS_NETSTATUS;
  334. wcscpy( ErrorNumberBuffer, L"%%" );
  335. ultow( (ULONG) ((ULONG_PTR)StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1]), ErrorNumberBuffer+2, 10 );
  336. StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1] = ErrorNumberBuffer;
  337. }
  338. //
  339. // Check to see if this problem has already been reported.
  340. //
  341. if ( !AllowDuplicateEvents ) {
  342. for ( ListEntry = EventList->EventList.Flink ;
  343. ListEntry != &EventList->EventList ;
  344. ) {
  345. EventEntry =
  346. CONTAINING_RECORD( ListEntry, NL_EVENT_ENTRY, Next );
  347. // Entry might be freed (or moved) below
  348. ListEntry = ListEntry->Flink;
  349. //
  350. // If the entry is too old,
  351. // ditch it.
  352. //
  353. if ( NetpLogonTimeHasElapsed( EventEntry->FirstLogTime,
  354. EventList->DuplicateEventlogTimeout ) ) {
  355. // NlPrint((NL_MISC, "Ditched a duplicate event. %ld\n", EventEntry->EventId ));
  356. RemoveEntryList( &EventEntry->Next );
  357. LocalFree( EventEntry );
  358. continue;
  359. }
  360. //
  361. // Compare this event to the one being logged.
  362. //
  363. if ( EventEntry->EventId == EventId &&
  364. EventEntry->EventType == EventType &&
  365. EventEntry->EventCategory == EventCategory &&
  366. EventEntry->RawDataSize == RawDataSize &&
  367. EventEntry->StringCount == StringCount ) {
  368. if ( RawDataSize != 0 &&
  369. !RtlEqualMemory( EventEntry->RawDataBuffer, RawDataBuffer, RawDataSize ) ) {
  370. continue;
  371. }
  372. for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) {
  373. if ( EventEntry->StringArray[StringIndex] == NULL) {
  374. if ( StringArray[StringIndex] != NULL ) {
  375. break;
  376. }
  377. } else {
  378. if ( StringArray[StringIndex] == NULL ) {
  379. break;
  380. }
  381. if ( wcscmp( EventEntry->StringArray[StringIndex],
  382. StringArray[StringIndex] ) != 0 ) {
  383. break;
  384. }
  385. }
  386. }
  387. //
  388. // If the event has already been logged,
  389. // skip this one.
  390. //
  391. if ( StringIndex == StringCount ) {
  392. RemoveEntryList( &EventEntry->Next );
  393. InsertHeadList( &EventList->EventList, &EventEntry->Next );
  394. ErrorCode = ERROR_ALREADY_EXISTS;
  395. //
  396. // update count of events logged.
  397. //
  398. EventEntry->EventsLogged ++;
  399. goto Cleanup;
  400. }
  401. }
  402. }
  403. }
  404. //
  405. // Raise an alert if one is needed.
  406. //
  407. if ( RaiseAlertToo ) {
  408. ASSERT( StringArray[StringCount] == NULL );
  409. if ( StringArray[StringCount] == NULL ) {
  410. AlertErrorCode = NetpRaiseAlert( EventList->Source, EventId, StringArray );
  411. }
  412. }
  413. //
  414. // write event
  415. //
  416. ErrorCode = NetpWriteEventlogEx(
  417. EventList->Source,
  418. EventId,
  419. EventType,
  420. EventCategory,
  421. StringCount,
  422. StringArray,
  423. RawDataSize,
  424. RawDataBuffer);
  425. if( ErrorCode != NO_ERROR ) {
  426. goto Cleanup;
  427. }
  428. //
  429. // Save the event for later
  430. // (Only cache events while the service is starting or running.)
  431. //
  432. if ( !AllowDuplicateEvents ) {
  433. ULONG EventEntrySize;
  434. //
  435. // Compute the size of the allocated block.
  436. //
  437. EventEntrySize = sizeof(NL_EVENT_ENTRY) + RawDataSize;
  438. for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) {
  439. EventEntrySize += sizeof(LPWSTR);
  440. if ( StringArray[StringIndex] != NULL ) {
  441. EventEntrySize += wcslen(StringArray[StringIndex]) * sizeof(WCHAR) + sizeof(WCHAR);
  442. }
  443. }
  444. //
  445. // Allocate a block for the entry
  446. //
  447. EventEntry = LocalAlloc( 0, EventEntrySize );
  448. //
  449. // Copy the description of this event into the allocated block.
  450. //
  451. if ( EventEntry != NULL ) {
  452. LPBYTE Where;
  453. EventEntry->EventId = EventId;
  454. EventEntry->EventType = EventType;
  455. EventEntry->EventCategory = EventCategory;
  456. EventEntry->RawDataSize = RawDataSize;
  457. EventEntry->StringCount = StringCount;
  458. EventEntry->EventsLogged = 1;
  459. GetSystemTimeAsFileTime( (PFILETIME)&EventEntry->FirstLogTime );
  460. Where = (LPBYTE)(EventEntry+1);
  461. EventEntry->StringArray = (LPWSTR *)Where;
  462. Where += StringCount * sizeof(LPWSTR);
  463. for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) {
  464. if ( StringArray[StringIndex] == NULL ) {
  465. EventEntry->StringArray[StringIndex] = NULL;
  466. } else {
  467. EventEntry->StringArray[StringIndex] = (LPWSTR) Where;
  468. wcscpy( (LPWSTR)Where, StringArray[StringIndex] );
  469. Where += wcslen( StringArray[StringIndex] ) * sizeof(WCHAR) + sizeof(WCHAR);
  470. }
  471. }
  472. if ( RawDataSize != 0 ) {
  473. EventEntry->RawDataBuffer = Where;
  474. RtlCopyMemory( Where, RawDataBuffer, RawDataSize );
  475. }
  476. InsertHeadList( &EventList->EventList, &EventEntry->Next );
  477. }
  478. }
  479. Cleanup:
  480. LeaveCriticalSection( &EventList->EventListCritSect );
  481. return (ErrorCode == NO_ERROR) ? AlertErrorCode : ErrorCode;
  482. }
  483. DWORD
  484. NetpEventlogWrite (
  485. IN HANDLE NetpEventHandle,
  486. IN DWORD EventId,
  487. IN DWORD EventType,
  488. IN LPBYTE RawDataBuffer OPTIONAL,
  489. IN DWORD RawDataSize,
  490. IN LPWSTR *StringArray,
  491. IN DWORD StringCount
  492. )
  493. {
  494. return NetpEventlogWriteEx (
  495. NetpEventHandle,
  496. EventType, // wType
  497. 0, // wCategory
  498. EventId, // dwEventID
  499. StringCount,
  500. RawDataSize,
  501. StringArray,
  502. RawDataBuffer
  503. );
  504. }
  505. VOID
  506. NetpEventlogClearList (
  507. IN HANDLE NetpEventHandle
  508. )
  509. /*++
  510. Routine Description:
  511. This routine clears the list of events that have already been logged.
  512. Arguments:
  513. NetpEventHandle - Handle from NetpEventlogOpen
  514. Return Value:
  515. None.
  516. --*/
  517. {
  518. PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
  519. EnterCriticalSection(&EventList->EventListCritSect);
  520. while (!IsListEmpty(&EventList->EventList)) {
  521. PNL_EVENT_ENTRY EventEntry = CONTAINING_RECORD(EventList->EventList.Flink, NL_EVENT_ENTRY, Next);
  522. RemoveEntryList( &EventEntry->Next );
  523. LocalFree( EventEntry );
  524. }
  525. LeaveCriticalSection(&EventList->EventListCritSect);
  526. }
  527. VOID
  528. NetpEventlogSetTimeout (
  529. IN HANDLE NetpEventHandle,
  530. IN ULONG DuplicateEventlogTimeout
  531. )
  532. /*++
  533. Routine Description:
  534. This routine sets a new timeout for logged events
  535. Arguments:
  536. NetpEventHandle - Handle from NetpEventlogOpen
  537. DuplicateEventlogTimeout - Number of milli-seconds to keep EventList entry for.
  538. Return Value:
  539. None.
  540. --*/
  541. {
  542. PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
  543. EventList->DuplicateEventlogTimeout = DuplicateEventlogTimeout;
  544. }
  545. VOID
  546. NetpEventlogClose (
  547. IN HANDLE NetpEventHandle
  548. )
  549. /*++
  550. Routine Description:
  551. This routine closes the handle returned from NetpEventlogOpen
  552. Arguments:
  553. NetpEventHandle - Handle from NetpEventlogOpen
  554. Return Value:
  555. None.
  556. --*/
  557. {
  558. PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
  559. //
  560. // Clear the list of logged events.
  561. //
  562. NetpEventlogClearList( NetpEventHandle );
  563. //
  564. // Delete the critsect
  565. //
  566. DeleteCriticalSection( &EventList->EventListCritSect );
  567. //
  568. // Free the allocated buffer.
  569. //
  570. LocalFree( EventList );
  571. }