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.

827 lines
21 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. NetpEventlogWriteEx2 (
  266. IN HANDLE NetpEventHandle,
  267. IN DWORD EventType,
  268. IN DWORD EventCategory,
  269. IN DWORD EventId,
  270. IN DWORD StringCount,
  271. IN DWORD StatusMessageIndex,
  272. IN DWORD RawDataSize,
  273. IN LPWSTR *StringArray,
  274. IN LPVOID pvRawDataBuffer OPTIONAL
  275. )
  276. /*++
  277. Routine Description:
  278. Stub routine for calling writing Event Log and skipping duplicates
  279. Arguments:
  280. NetpEventHandle - Handle from NetpEventlogOpen
  281. EventId - event log ID.
  282. EventType - Type of event.
  283. RawDataBuffer - Data to be logged with the error.
  284. numbyte - Size in bytes of "RawDataBuffer"
  285. StringArray - array of null-terminated strings.
  286. StringCount - number of zero terminated strings in "StringArray". The following
  287. flags can be OR'd in to the count:
  288. NETP_LAST_MESSAGE_IS_NTSTATUS
  289. NETP_LAST_MESSAGE_IS_NETSTATUS
  290. NETP_ALLOW_DUPLICATE_EVENTS
  291. NETP_RAISE_ALERT_TOO
  292. StatusMessageIndex - Specifies the index of the message that is
  293. a Net or NT status in the StringArray. Used only if
  294. NETP_LAST_MESSAGE_IS_NETSTATUS or NETP_LAST_MESSAGE_IS_NTSTATUS
  295. are set in StringCount. If this parameter is MAXULONG and either
  296. of these flags is set, the default is assumed which is the last
  297. message in the list.
  298. Return Value:
  299. Win 32 status of the operation.
  300. ERROR_ALREAY_EXISTS: Success status indicating the message was already logged
  301. --*/
  302. {
  303. DWORD ErrorCode;
  304. DWORD AlertErrorCode = NO_ERROR;
  305. WCHAR ErrorNumberBuffer[25];
  306. PLIST_ENTRY ListEntry;
  307. ULONG StringIndex;
  308. DWORD LocalStatusMessageIndex = StatusMessageIndex;
  309. BOOLEAN AllowDuplicateEvents;
  310. BOOLEAN RaiseAlertToo;
  311. PNL_EVENT_ENTRY EventEntry;
  312. PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
  313. LPBYTE RawDataBuffer = (LPBYTE)pvRawDataBuffer;
  314. //
  315. // Remove sundry flags
  316. //
  317. EnterCriticalSection( &EventList->EventListCritSect );
  318. AllowDuplicateEvents = (StringCount & NETP_ALLOW_DUPLICATE_EVENTS) != 0;
  319. StringCount &= ~NETP_ALLOW_DUPLICATE_EVENTS;
  320. RaiseAlertToo = (StringCount & NETP_RAISE_ALERT_TOO) != 0;
  321. StringCount &= ~NETP_RAISE_ALERT_TOO;
  322. //
  323. // Check if the status message index in the list
  324. // should be assigned the default value
  325. //
  326. if ( (StringCount & NETP_LAST_MESSAGE_IS_NETSTATUS) != 0 ||
  327. (StringCount & NETP_LAST_MESSAGE_IS_NTSTATUS) != 0 ) {
  328. if ( LocalStatusMessageIndex == MAXULONG ) {
  329. LocalStatusMessageIndex = (StringCount & NETP_STRING_COUNT_MASK) - 1;
  330. }
  331. }
  332. //
  333. // If an NT status code was passed in,
  334. // convert it to a net status code.
  335. //
  336. if ( StringCount & NETP_LAST_MESSAGE_IS_NTSTATUS ) {
  337. StringCount &= ~NETP_LAST_MESSAGE_IS_NTSTATUS;
  338. //
  339. // Do the "better" error mapping when eventviewer ParameterMessageFile
  340. // can be a list of files. Then, add netmsg.dll to the list.
  341. //
  342. // StringArray[((StringCount&NETP_STRING_COUNT_MASK)-1] = (LPWSTR) NetpNtStatusToApiStatus( (NTSTATUS) StringArray[(StringCount&NETP_STRING_COUNT_MASK)-1] );
  343. StringArray[LocalStatusMessageIndex] = (LPWSTR) (ULONG_PTR) RtlNtStatusToDosError( (NTSTATUS) ((ULONG_PTR)StringArray[LocalStatusMessageIndex]) );
  344. StringCount |= NETP_LAST_MESSAGE_IS_NETSTATUS;
  345. }
  346. //
  347. // If a net/windows status code was passed in,
  348. // convert to the the %%N format the eventviewer knows.
  349. //
  350. if ( StringCount & NETP_LAST_MESSAGE_IS_NETSTATUS ) {
  351. StringCount &= ~NETP_LAST_MESSAGE_IS_NETSTATUS;
  352. wcscpy( ErrorNumberBuffer, L"%%" );
  353. ultow( (ULONG) ((ULONG_PTR)StringArray[LocalStatusMessageIndex]), ErrorNumberBuffer+2, 10 );
  354. StringArray[LocalStatusMessageIndex] = ErrorNumberBuffer;
  355. }
  356. //
  357. // Check to see if this problem has already been reported.
  358. //
  359. if ( !AllowDuplicateEvents ) {
  360. for ( ListEntry = EventList->EventList.Flink ;
  361. ListEntry != &EventList->EventList ;
  362. ) {
  363. EventEntry =
  364. CONTAINING_RECORD( ListEntry, NL_EVENT_ENTRY, Next );
  365. // Entry might be freed (or moved) below
  366. ListEntry = ListEntry->Flink;
  367. //
  368. // If the entry is too old,
  369. // ditch it.
  370. //
  371. if ( NetpLogonTimeHasElapsed( EventEntry->FirstLogTime,
  372. EventList->DuplicateEventlogTimeout ) ) {
  373. // NlPrint((NL_MISC, "Ditched a duplicate event. %ld\n", EventEntry->EventId ));
  374. RemoveEntryList( &EventEntry->Next );
  375. LocalFree( EventEntry );
  376. continue;
  377. }
  378. //
  379. // Compare this event to the one being logged.
  380. //
  381. if ( EventEntry->EventId == EventId &&
  382. EventEntry->EventType == EventType &&
  383. EventEntry->EventCategory == EventCategory &&
  384. EventEntry->RawDataSize == RawDataSize &&
  385. EventEntry->StringCount == StringCount ) {
  386. if ( RawDataSize != 0 &&
  387. !RtlEqualMemory( EventEntry->RawDataBuffer, RawDataBuffer, RawDataSize ) ) {
  388. continue;
  389. }
  390. for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) {
  391. if ( EventEntry->StringArray[StringIndex] == NULL) {
  392. if ( StringArray[StringIndex] != NULL ) {
  393. break;
  394. }
  395. } else {
  396. if ( StringArray[StringIndex] == NULL ) {
  397. break;
  398. }
  399. if ( wcscmp( EventEntry->StringArray[StringIndex],
  400. StringArray[StringIndex] ) != 0 ) {
  401. break;
  402. }
  403. }
  404. }
  405. //
  406. // If the event has already been logged,
  407. // skip this one.
  408. //
  409. if ( StringIndex == StringCount ) {
  410. RemoveEntryList( &EventEntry->Next );
  411. InsertHeadList( &EventList->EventList, &EventEntry->Next );
  412. ErrorCode = ERROR_ALREADY_EXISTS;
  413. //
  414. // update count of events logged.
  415. //
  416. EventEntry->EventsLogged ++;
  417. goto Cleanup;
  418. }
  419. }
  420. }
  421. }
  422. //
  423. // Raise an alert if one is needed.
  424. //
  425. if ( RaiseAlertToo ) {
  426. ASSERT( StringArray[StringCount] == NULL );
  427. if ( StringArray[StringCount] == NULL ) {
  428. AlertErrorCode = NetpRaiseAlert( EventList->Source, EventId, StringArray );
  429. }
  430. }
  431. //
  432. // write event
  433. //
  434. ErrorCode = NetpWriteEventlogEx(
  435. EventList->Source,
  436. EventId,
  437. EventType,
  438. EventCategory,
  439. StringCount,
  440. StringArray,
  441. RawDataSize,
  442. RawDataBuffer);
  443. if( ErrorCode != NO_ERROR ) {
  444. goto Cleanup;
  445. }
  446. //
  447. // Save the event for later
  448. // (Only cache events while the service is starting or running.)
  449. //
  450. if ( !AllowDuplicateEvents ) {
  451. ULONG EventEntrySize;
  452. //
  453. // Compute the size of the allocated block.
  454. //
  455. EventEntrySize = sizeof(NL_EVENT_ENTRY) + RawDataSize;
  456. for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) {
  457. EventEntrySize += sizeof(LPWSTR);
  458. if ( StringArray[StringIndex] != NULL ) {
  459. EventEntrySize += wcslen(StringArray[StringIndex]) * sizeof(WCHAR) + sizeof(WCHAR);
  460. }
  461. }
  462. //
  463. // Allocate a block for the entry
  464. //
  465. EventEntry = LocalAlloc( 0, EventEntrySize );
  466. //
  467. // Copy the description of this event into the allocated block.
  468. //
  469. if ( EventEntry != NULL ) {
  470. LPBYTE Where;
  471. EventEntry->EventId = EventId;
  472. EventEntry->EventType = EventType;
  473. EventEntry->EventCategory = EventCategory;
  474. EventEntry->RawDataSize = RawDataSize;
  475. EventEntry->StringCount = StringCount;
  476. EventEntry->EventsLogged = 1;
  477. GetSystemTimeAsFileTime( (PFILETIME)&EventEntry->FirstLogTime );
  478. Where = (LPBYTE)(EventEntry+1);
  479. EventEntry->StringArray = (LPWSTR *)Where;
  480. Where += StringCount * sizeof(LPWSTR);
  481. for ( StringIndex=0; StringIndex < StringCount; StringIndex ++ ) {
  482. if ( StringArray[StringIndex] == NULL ) {
  483. EventEntry->StringArray[StringIndex] = NULL;
  484. } else {
  485. EventEntry->StringArray[StringIndex] = (LPWSTR) Where;
  486. wcscpy( (LPWSTR)Where, StringArray[StringIndex] );
  487. Where += wcslen( StringArray[StringIndex] ) * sizeof(WCHAR) + sizeof(WCHAR);
  488. }
  489. }
  490. if ( RawDataSize != 0 ) {
  491. EventEntry->RawDataBuffer = Where;
  492. RtlCopyMemory( Where, RawDataBuffer, RawDataSize );
  493. }
  494. InsertHeadList( &EventList->EventList, &EventEntry->Next );
  495. }
  496. }
  497. Cleanup:
  498. LeaveCriticalSection( &EventList->EventListCritSect );
  499. return (ErrorCode == NO_ERROR) ? AlertErrorCode : ErrorCode;
  500. }
  501. DWORD
  502. NetpEventlogWriteEx (
  503. IN HANDLE NetpEventHandle,
  504. IN DWORD EventType,
  505. IN DWORD EventCategory,
  506. IN DWORD EventId,
  507. IN DWORD StringCount,
  508. IN DWORD RawDataSize,
  509. IN LPWSTR *StringArray,
  510. IN LPVOID pvRawDataBuffer OPTIONAL
  511. )
  512. {
  513. return NetpEventlogWriteEx2 (
  514. NetpEventHandle,
  515. EventType, // wType
  516. EventCategory,
  517. EventId, // dwEventID
  518. StringCount,
  519. MAXULONG, // default status message index
  520. RawDataSize,
  521. StringArray,
  522. pvRawDataBuffer
  523. );
  524. }
  525. DWORD
  526. NetpEventlogWrite (
  527. IN HANDLE NetpEventHandle,
  528. IN DWORD EventId,
  529. IN DWORD EventType,
  530. IN LPBYTE RawDataBuffer OPTIONAL,
  531. IN DWORD RawDataSize,
  532. IN LPWSTR *StringArray,
  533. IN DWORD StringCount
  534. )
  535. {
  536. return NetpEventlogWriteEx2 (
  537. NetpEventHandle,
  538. EventType, // wType
  539. 0, // wCategory
  540. EventId, // dwEventID
  541. StringCount,
  542. MAXULONG, // default status message index
  543. RawDataSize,
  544. StringArray,
  545. RawDataBuffer
  546. );
  547. }
  548. VOID
  549. NetpEventlogClearList (
  550. IN HANDLE NetpEventHandle
  551. )
  552. /*++
  553. Routine Description:
  554. This routine clears the list of events that have already been logged.
  555. Arguments:
  556. NetpEventHandle - Handle from NetpEventlogOpen
  557. Return Value:
  558. None.
  559. --*/
  560. {
  561. PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
  562. EnterCriticalSection(&EventList->EventListCritSect);
  563. while (!IsListEmpty(&EventList->EventList)) {
  564. PNL_EVENT_ENTRY EventEntry = CONTAINING_RECORD(EventList->EventList.Flink, NL_EVENT_ENTRY, Next);
  565. RemoveEntryList( &EventEntry->Next );
  566. LocalFree( EventEntry );
  567. }
  568. LeaveCriticalSection(&EventList->EventListCritSect);
  569. }
  570. VOID
  571. NetpEventlogSetTimeout (
  572. IN HANDLE NetpEventHandle,
  573. IN ULONG DuplicateEventlogTimeout
  574. )
  575. /*++
  576. Routine Description:
  577. This routine sets a new timeout for logged events
  578. Arguments:
  579. NetpEventHandle - Handle from NetpEventlogOpen
  580. DuplicateEventlogTimeout - Number of milli-seconds to keep EventList entry for.
  581. Return Value:
  582. None.
  583. --*/
  584. {
  585. PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
  586. EventList->DuplicateEventlogTimeout = DuplicateEventlogTimeout;
  587. }
  588. VOID
  589. NetpEventlogClose (
  590. IN HANDLE NetpEventHandle
  591. )
  592. /*++
  593. Routine Description:
  594. This routine closes the handle returned from NetpEventlogOpen
  595. Arguments:
  596. NetpEventHandle - Handle from NetpEventlogOpen
  597. Return Value:
  598. None.
  599. --*/
  600. {
  601. PNL_EVENT_LIST EventList = (PNL_EVENT_LIST)NetpEventHandle;
  602. //
  603. // Clear the list of logged events.
  604. //
  605. NetpEventlogClearList( NetpEventHandle );
  606. //
  607. // Delete the critsect
  608. //
  609. DeleteCriticalSection( &EventList->EventListCritSect );
  610. //
  611. // Free the allocated buffer.
  612. //
  613. LocalFree( EventList );
  614. }