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.

2280 lines
55 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. ELFUTIL.C
  5. Abstract:
  6. This file contains all the utility routines for the Eventlog service.
  7. Author:
  8. Rajen Shah (rajens) 16-Jul-1991
  9. Revision History:
  10. 01-May-2001 a-jyotig
  11. CurrentTime is initialized to 0 in function WriteQueuedEvents.
  12. Refer to prefix bug# 318163
  13. --*/
  14. //
  15. // INCLUDES
  16. //
  17. #include <eventp.h>
  18. #include <elfcfg.h>
  19. #include <lmalert.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <tstr.h>
  23. extern DWORD ElState;
  24. PLOGMODULE
  25. FindModuleStrucFromAtom(
  26. ATOM Atom
  27. )
  28. /*++
  29. Routine Description:
  30. This routine scans the list of module structures and finds the one
  31. that matches the module atom.
  32. Arguments:
  33. Atom contains the atom matching the module name.
  34. Return Value:
  35. A pointer to the log module structure is returned.
  36. NULL if no matching atom is found.
  37. Note:
  38. --*/
  39. {
  40. PLOGMODULE ModuleStruc;
  41. //
  42. // Lock the linked list
  43. //
  44. RtlEnterCriticalSection(&LogModuleCritSec);
  45. ModuleStruc = CONTAINING_RECORD(LogModuleHead.Flink,
  46. LOGMODULE,
  47. ModuleList);
  48. while ((ModuleStruc->ModuleList.Flink != &LogModuleHead)
  49. &&
  50. (ModuleStruc->ModuleAtom != Atom))
  51. {
  52. ModuleStruc = CONTAINING_RECORD(ModuleStruc->ModuleList.Flink,
  53. LOGMODULE,
  54. ModuleList);
  55. }
  56. //
  57. // Unlock the linked list
  58. //
  59. RtlLeaveCriticalSection(&LogModuleCritSec);
  60. return (ModuleStruc->ModuleAtom == Atom ? ModuleStruc : NULL);
  61. }
  62. PLOGMODULE
  63. GetModuleStruc(
  64. PUNICODE_STRING ModuleName
  65. )
  66. /*++
  67. Routine Description:
  68. This routine returns a pointer to the log module structure for the
  69. module specified in ModuleName. If none exists, the default structure
  70. for application is returned.
  71. Arguments:
  72. ModuleName contains the name of the module.
  73. Return Value:
  74. A pointer to the log module structure is returned.
  75. Note:
  76. --*/
  77. {
  78. NTSTATUS Status;
  79. ATOM ModuleAtom;
  80. ANSI_STRING ModuleNameA;
  81. PLOGMODULE pModule;
  82. Status = RtlUnicodeStringToAnsiString(&ModuleNameA,
  83. ModuleName,
  84. TRUE);
  85. if (!NT_SUCCESS(Status))
  86. {
  87. //
  88. // Not much else we can do here...
  89. //
  90. ELF_LOG2(ERROR,
  91. "GetModuleStruc: Unable to convert Unicode string %ws to Ansi %#x\n",
  92. ModuleName->Buffer,
  93. Status);
  94. return ElfDefaultLogModule;
  95. }
  96. //
  97. // Guarantee that it's NULL terminated
  98. //
  99. ModuleNameA.Buffer[ModuleNameA.Length] = '\0';
  100. ModuleAtom = FindAtomA(ModuleNameA.Buffer);
  101. RtlFreeAnsiString(&ModuleNameA);
  102. if (ModuleAtom == (ATOM)0)
  103. {
  104. ELF_LOG1(TRACE,
  105. "GetModuleStruc: No atom found for module %ws -- defaulting to Application\n",
  106. ModuleName->Buffer);
  107. return ElfDefaultLogModule;
  108. }
  109. pModule = FindModuleStrucFromAtom(ModuleAtom);
  110. return (pModule != NULL ? pModule : ElfDefaultLogModule);
  111. }
  112. VOID
  113. UnlinkContextHandle(
  114. IELF_HANDLE LogHandle
  115. )
  116. /*++
  117. Routine Description:
  118. This routine unlinks the LogHandle specified from the linked list of
  119. context handles.
  120. In order to protect against multiple thread/process access to the
  121. list at the same time, we use a critical section.
  122. Arguments:
  123. LogHandle points to a context handle structure.
  124. Return Value:
  125. NONE
  126. Note:
  127. --*/
  128. {
  129. //
  130. // Lock the linked list
  131. //
  132. RtlEnterCriticalSection(&LogHandleCritSec);
  133. //
  134. // Remove this entry
  135. //
  136. RemoveEntryList(&LogHandle->Next);
  137. //
  138. // Unlock the linked list
  139. //
  140. RtlLeaveCriticalSection(&LogHandleCritSec);
  141. }
  142. VOID
  143. LinkContextHandle(
  144. IELF_HANDLE LogHandle
  145. )
  146. /*++
  147. Routine Description:
  148. This routine links the LogHandle specified into the linked list of
  149. context handles.
  150. In order to protect against multiple thread/process access to the
  151. list at the same time, we use a critical section.
  152. Arguments:
  153. LogHandle points to a context handle structure.
  154. Return Value:
  155. NONE
  156. Note:
  157. --*/
  158. {
  159. ASSERT(LogHandle->Signature == ELF_CONTEXTHANDLE_SIGN);
  160. //
  161. // Lock the linked list
  162. //
  163. RtlEnterCriticalSection(&LogHandleCritSec);
  164. //
  165. // Place structure at the beginning of the list.
  166. //
  167. InsertHeadList(&LogHandleListHead, &LogHandle->Next);
  168. //
  169. // Unlock the linked list
  170. //
  171. RtlLeaveCriticalSection(&LogHandleCritSec);
  172. }
  173. VOID
  174. UnlinkQueuedEvent(
  175. PELF_QUEUED_EVENT QueuedEvent
  176. )
  177. /*++
  178. Routine Description:
  179. This routine unlinks the QueuedEvent specified from the linked list of
  180. QueuedEvents.
  181. In order to protect against multiple thread/process access to the
  182. list at the same time, we use a critical section.
  183. Arguments:
  184. QueuedEvent - The request to remove from the linked list
  185. Return Value:
  186. NONE
  187. Note:
  188. --*/
  189. {
  190. //
  191. // Lock the linked list
  192. //
  193. RtlEnterCriticalSection(&QueuedEventCritSec);
  194. //
  195. // Remove this entry
  196. //
  197. RemoveEntryList(&QueuedEvent->Next);
  198. //
  199. // Unlock the linked list
  200. //
  201. RtlLeaveCriticalSection(&QueuedEventCritSec);
  202. }
  203. VOID
  204. LinkQueuedEvent(
  205. PELF_QUEUED_EVENT QueuedEvent
  206. )
  207. /*++
  208. Routine Description:
  209. This routine links the QueuedEvent specified into the linked list of
  210. QueuedEvents.
  211. In order to protect against multiple thread/process access to the
  212. list at the same time, we use a critical section.
  213. Arguments:
  214. QueuedEvent - The request to add from the linked list
  215. Return Value:
  216. NONE
  217. Note:
  218. --*/
  219. {
  220. //
  221. // Lock the linked list
  222. //
  223. RtlEnterCriticalSection(&QueuedEventCritSec);
  224. //
  225. // Place structure at the beginning of the list.
  226. //
  227. InsertHeadList(&QueuedEventListHead, &QueuedEvent->Next);
  228. //
  229. // Unlock the linked list
  230. //
  231. RtlLeaveCriticalSection(&QueuedEventCritSec);
  232. }
  233. DWORD
  234. WINAPI
  235. ElfpSendMessage(
  236. LPVOID UnUsed
  237. )
  238. /*++
  239. Routine Description:
  240. This routines just uses MessageBox to pop up a message.
  241. This is it's own routine so we can spin a thread to do this, in case the
  242. user doesn't hit the OK button for a while.
  243. Arguments:
  244. NONE
  245. Return Value:
  246. NONE
  247. Note:
  248. --*/
  249. {
  250. PVOID MessageBuffer;
  251. HANDLE hLibrary;
  252. LPWSTR * StringPointers;
  253. DWORD i;
  254. PELF_QUEUED_EVENT QueuedEvent;
  255. PELF_QUEUED_EVENT FlushEvent;
  256. //
  257. // If we are shutting down, we need to return
  258. // and allow resources to be freed
  259. //
  260. if (ElState == STOPPING || ElState == STOPPED)
  261. {
  262. ELF_LOG1(TRACE,
  263. "ElfpSendMessage: Skipping SendMessage since ElState is %ws\n",
  264. (ElState == STOPPING ? L"STOPPING" :
  265. L"STOPPED"));
  266. return 0;
  267. }
  268. RtlEnterCriticalSection(&QueuedMessageCritSec);
  269. //
  270. // First get a handle to the message file used for the message text
  271. //
  272. hLibrary = LoadLibraryEx(L"NETMSG.DLL",
  273. NULL,
  274. LOAD_LIBRARY_AS_DATAFILE);
  275. if (hLibrary != NULL)
  276. {
  277. //
  278. // Walk the linked list and process each element
  279. //
  280. QueuedEvent = CONTAINING_RECORD(QueuedMessageListHead.Flink,
  281. struct _ELF_QUEUED_EVENT,
  282. Next);
  283. while (QueuedEvent->Next.Flink != QueuedMessageListHead.Flink)
  284. {
  285. ASSERT(QueuedEvent->Type == Message);
  286. //
  287. // Unlock the linked list -- normally not a safe thing since we're
  288. // about to play with a pointer to an element in it, but:
  289. //
  290. // a. This is the only routine where a list item can be removed/deleted
  291. //
  292. // b. We don't touch the only potentially-volatile structure member
  293. // (QueuedEvent->Next) until we're in the critsec again below
  294. //
  295. // c. Only one thread at a time executes this code (enforced by
  296. // MBThreadHandle, which is only read/written inside the critsec)
  297. //
  298. RtlLeaveCriticalSection(&QueuedMessageCritSec);
  299. //
  300. // Build the array of pointers to the insertion strings
  301. //
  302. StringPointers =
  303. (LPWSTR *) ElfpAllocateBuffer(QueuedEvent->Event.Message.NumberOfStrings
  304. * sizeof(LPWSTR));
  305. if (StringPointers)
  306. {
  307. //
  308. // Build the array of pointers to the insertion string(s)
  309. //
  310. if (QueuedEvent->Event.Message.NumberOfStrings)
  311. {
  312. StringPointers[0] = (LPWSTR) ((PBYTE) &QueuedEvent->Event.Message +
  313. sizeof(ELF_MESSAGE_RECORD));
  314. for (i = 1;
  315. i < QueuedEvent->Event.Message.NumberOfStrings;
  316. i++)
  317. {
  318. StringPointers[i] = StringPointers[i-1]
  319. + wcslen(StringPointers[i - 1])
  320. + 1;
  321. }
  322. }
  323. //
  324. // Call FormatMessage to build the message
  325. //
  326. if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  327. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  328. FORMAT_MESSAGE_FROM_HMODULE,
  329. hLibrary,
  330. QueuedEvent->Event.Message.MessageId,
  331. 0, // Default language ID
  332. (LPWSTR) &MessageBuffer,
  333. 0, // Min # of bytes to allocate
  334. (va_list *) StringPointers))
  335. {
  336. //
  337. // Now actually display it
  338. //
  339. MessageBoxW(NULL,
  340. (LPWSTR) MessageBuffer,
  341. GlobalMessageBoxTitle,
  342. MB_OK |
  343. MB_SETFOREGROUND |
  344. MB_ICONEXCLAMATION |
  345. MB_SERVICE_NOTIFICATION);
  346. LocalFree(MessageBuffer);
  347. }
  348. else
  349. {
  350. ELF_LOG1(ERROR,
  351. "ElfpSendMessage: FormatMessage failed %d\n",
  352. GetLastError());
  353. }
  354. ElfpFreeBuffer(StringPointers);
  355. }
  356. //
  357. // If we are shutting down, we need to break out of this loop
  358. // and allow resources to be freed
  359. //
  360. if (ElState == STOPPING || ElState == STOPPED)
  361. {
  362. ELF_LOG1(TRACE,
  363. "ElfpSendMessage: Aborting SendMessage since ElState is %ws\n",
  364. (ElState == STOPPING ? L"STOPPING" :
  365. L"STOPPED"));
  366. FreeLibrary(hLibrary);
  367. MBThreadHandle = NULL;
  368. return 0;
  369. }
  370. RtlEnterCriticalSection (&QueuedMessageCritSec);
  371. //
  372. // Move to the next one, saving this one to delete it
  373. //
  374. FlushEvent = QueuedEvent;
  375. QueuedEvent = CONTAINING_RECORD(QueuedEvent->Next.Flink,
  376. struct _ELF_QUEUED_EVENT,
  377. Next);
  378. //
  379. // Now remove this from the queue and free it if we successfully
  380. // processed it
  381. //
  382. RemoveEntryList (&FlushEvent->Next);
  383. }
  384. FreeLibrary(hLibrary);
  385. }
  386. else
  387. {
  388. //
  389. // We couldn't load the message DLL -- leave the queued event
  390. // on the list and try it the next time this thread spins up.
  391. //
  392. ELF_LOG1(ERROR,
  393. "ElfpSendMessage: LoadLibraryEx of netmsg.dll failed %d\n",
  394. GetLastError());
  395. }
  396. MBThreadHandle = NULL;
  397. //
  398. // Unlock the linked list
  399. //
  400. RtlLeaveCriticalSection (&QueuedMessageCritSec);
  401. ELF_LOG0(TRACE, "ElfpSendMessage: MessageBox thread exiting\n");
  402. return 0;
  403. }
  404. VOID
  405. LinkQueuedMessage (
  406. PELF_QUEUED_EVENT QueuedEvent
  407. )
  408. /*++
  409. Routine Description:
  410. This routine links the QueuedEvent specified into the linked list of
  411. QueuedMessages. If there's not already a messagebox thread running,
  412. it starts one.
  413. In order to protect against multiple thread/process access to the
  414. list at the same time, we use a critical section.
  415. Arguments:
  416. QueuedEvent - The request to add from the linked list
  417. Return Value:
  418. NONE
  419. Note:
  420. --*/
  421. {
  422. DWORD ThreadId;
  423. // Lock the linked list
  424. RtlEnterCriticalSection(&QueuedMessageCritSec);
  425. // Place structure at the end of the list.
  426. InsertTailList(&QueuedMessageListHead, &QueuedEvent->Next);
  427. if (!MBThreadHandle)
  428. {
  429. ELF_LOG0(TRACE,
  430. "LinkQueuedMessage: Spinning up a MessageBox thread\n");
  431. //
  432. // Since the user can just let this sit on their screen,
  433. // spin a thread for this
  434. //
  435. MBThreadHandle = CreateThread(NULL, // lpThreadAttributes
  436. 0, // dwStackSize
  437. ElfpSendMessage, // lpStartAddress
  438. NULL, // lpParameter
  439. 0L, // dwCreationFlags
  440. &ThreadId); // lpThreadId
  441. }
  442. //
  443. // Unlock the linked list
  444. //
  445. RtlLeaveCriticalSection(&QueuedMessageCritSec);
  446. }
  447. VOID
  448. NotifyChange(
  449. PLOGFILE pLogFile
  450. )
  451. /*++
  452. Routine Description:
  453. This routine runs the list of events that are registered with
  454. ElfChangeNotify to be notified when a log has changed, and pulses
  455. the event.
  456. In order to protect against multiple thread/process access to the
  457. list at the same time, we use an exclusive resource.
  458. Arguments:
  459. LogHandle points to a context handle structure.
  460. Return Value:
  461. NONE
  462. Note:
  463. --*/
  464. {
  465. //
  466. // How frequently will I try to pulse the events? How about every
  467. // 5 seconds
  468. //
  469. #define MINIMUM_PULSE_TIME 5
  470. PNOTIFIEE Notifiee;
  471. LARGE_INTEGER Time;
  472. ULONG CurrentTime = 0;
  473. NTSTATUS Status;
  474. //
  475. // Get exclusive access to the log file. This will ensure no one
  476. // else is accessing the file.
  477. //
  478. RtlAcquireResourceExclusive(&pLogFile->Resource,
  479. TRUE); // Wait until available
  480. //
  481. // See if we've done this in the last MINIMUM_PULSE_TIME seconds
  482. //
  483. Status = NtQuerySystemTime(&Time);
  484. if (NT_SUCCESS(Status))
  485. {
  486. RtlTimeToSecondsSince1970(&Time, &CurrentTime);
  487. if (CurrentTime > pLogFile->ulLastPulseTime + MINIMUM_PULSE_TIME)
  488. {
  489. ELF_LOG1(TRACE,
  490. "NotifyChange: Pulsing ChangeNotify events -- current time is %ul\n",
  491. CurrentTime);
  492. //
  493. // Remember that we pulsed
  494. //
  495. pLogFile->ulLastPulseTime = CurrentTime;
  496. //
  497. // Walk the linked list and and pulse any events
  498. //
  499. Notifiee = CONTAINING_RECORD(pLogFile->Notifiees.Flink,
  500. struct _NOTIFIEE,
  501. Next);
  502. while (Notifiee->Next.Flink != pLogFile->Notifiees.Flink)
  503. {
  504. //
  505. // Pulse each event as we get to it.
  506. //
  507. NtPulseEvent(Notifiee->Event,NULL);
  508. Notifiee = CONTAINING_RECORD(Notifiee->Next.Flink,
  509. struct _NOTIFIEE,
  510. Next);
  511. }
  512. }
  513. }
  514. else
  515. {
  516. ELF_LOG1(ERROR,
  517. "NotifyChange: NtQuerySystemTime failed %#x\n",
  518. Status);
  519. }
  520. //
  521. // Free the resource
  522. //
  523. RtlReleaseResource ( &pLogFile->Resource );
  524. }
  525. VOID
  526. WriteQueuedEvents(
  527. VOID
  528. )
  529. /*++
  530. Routine Description:
  531. This routine runs the list of queued events and writes them.
  532. In order to protect against multiple thread/process access to the
  533. list at the same time, we use an exclusive resource.
  534. Arguments:
  535. NONE
  536. Return Value:
  537. NONE
  538. Note:
  539. --*/
  540. {
  541. PELF_QUEUED_EVENT QueuedEvent;
  542. PELF_QUEUED_EVENT FlushEvent;
  543. BOOLEAN bFlushEvent;
  544. LARGE_INTEGER Time;
  545. ULONG CurrentTime = 0;
  546. static ULONG LastAlertTried = 0;
  547. static BOOLEAN LastAlertFailed = FALSE;
  548. // Lock the linked list, you must get the System Log File Resource
  549. // first, it is the higher level lock
  550. RtlAcquireResourceExclusive(&ElfModule->LogFile->Resource,
  551. TRUE); // Wait until available
  552. RtlAcquireResourceExclusive(&ElfSecModule->LogFile->Resource,
  553. TRUE); // Wait until available
  554. RtlEnterCriticalSection(&QueuedEventCritSec);
  555. //
  556. // Walk the linked list and process each element
  557. //
  558. QueuedEvent = CONTAINING_RECORD(QueuedEventListHead.Flink,
  559. struct _ELF_QUEUED_EVENT,
  560. Next);
  561. while (QueuedEvent->Next.Flink != QueuedEventListHead.Flink)
  562. {
  563. //
  564. // Default is to flush the event after processing
  565. //
  566. bFlushEvent = TRUE;
  567. // on occasion, an event is writting before the ElfModule is even intialized. In that
  568. // case, set the value here.
  569. if(QueuedEvent->Event.Request.Module == NULL)
  570. QueuedEvent->Event.Request.Module = ElfModule;
  571. if(QueuedEvent->Event.Request.LogFile == NULL && ElfModule)
  572. QueuedEvent->Event.Request.LogFile = ElfModule->LogFile;
  573. //
  574. // Do the appropriate thing
  575. //
  576. if (QueuedEvent->Type == Event)
  577. {
  578. PerformWriteRequest(&QueuedEvent->Event.Request);
  579. }
  580. else if (QueuedEvent->Type == Alert)
  581. {
  582. //
  583. // Don't even try to send failed alerts quicker than once a minute
  584. //
  585. NtQuerySystemTime(&Time);
  586. RtlTimeToSecondsSince1970(&Time, &CurrentTime);
  587. if (!LastAlertFailed || CurrentTime > LastAlertTried + 60)
  588. {
  589. ELF_LOG1(TRACE,
  590. "WriteQueuedEvents: Sending alert -- current time is %ul\n",
  591. CurrentTime);
  592. LastAlertFailed =
  593. !SendAdminAlert(QueuedEvent->Event.Alert.MessageId,
  594. QueuedEvent->Event.Alert.NumberOfStrings,
  595. (PUNICODE_STRING) ((PBYTE) QueuedEvent
  596. + FIELD_OFFSET(ELF_QUEUED_EVENT, Event)
  597. + sizeof(ELF_ALERT_RECORD)));
  598. LastAlertTried = CurrentTime;
  599. }
  600. //
  601. // Only try to write it for 5 minutes, then give up (the
  602. // alerter service may not be configured to run)
  603. //
  604. if (LastAlertFailed
  605. &&
  606. QueuedEvent->Event.Alert.TimeOut > CurrentTime)
  607. {
  608. ELF_LOG1(TRACE,
  609. "WriteQueuedEvents: Alert failed -- will retry until timeout at %ul\n",
  610. QueuedEvent->Event.Alert.TimeOut);
  611. bFlushEvent = FALSE;
  612. }
  613. }
  614. //
  615. // Move to the next one, saving this one to delete it
  616. //
  617. FlushEvent = QueuedEvent;
  618. QueuedEvent = CONTAINING_RECORD(QueuedEvent->Next.Flink,
  619. struct _ELF_QUEUED_EVENT,
  620. Next);
  621. //
  622. // Now remove this from the queue and free it if we successfully
  623. // processed it
  624. //
  625. if (bFlushEvent)
  626. {
  627. UnlinkQueuedEvent(FlushEvent);
  628. ElfpFreeBuffer(FlushEvent);
  629. }
  630. }
  631. //
  632. // Unlock the linked list
  633. //
  634. RtlLeaveCriticalSection(&QueuedEventCritSec);
  635. RtlReleaseResource(&ElfSecModule->LogFile->Resource);
  636. RtlReleaseResource(&ElfModule->LogFile->Resource);
  637. }
  638. VOID
  639. FlushQueuedEvents(
  640. VOID
  641. )
  642. /*++
  643. Routine Description:
  644. This routine runs the list of queued events and frees them.
  645. In order to protect against multiple thread/process access to the
  646. list at the same time, we use an exclusive resource.
  647. Arguments:
  648. NONE
  649. Return Value:
  650. NONE
  651. Note:
  652. --*/
  653. {
  654. PELF_QUEUED_EVENT QueuedEvent;
  655. PELF_QUEUED_EVENT FlushEvent;
  656. // Lock the linked list
  657. RtlEnterCriticalSection(&QueuedEventCritSec);
  658. //
  659. // Walk the linked list and and free the memory for any events
  660. //
  661. QueuedEvent = CONTAINING_RECORD(QueuedEventListHead.Flink,
  662. struct _ELF_QUEUED_EVENT,
  663. Next);
  664. while (QueuedEvent->Next.Flink != QueuedEventListHead.Flink)
  665. {
  666. //
  667. // Free each event as we get to it.
  668. //
  669. FlushEvent = QueuedEvent;
  670. QueuedEvent = CONTAINING_RECORD(QueuedEvent->Next.Flink,
  671. struct _ELF_QUEUED_EVENT,
  672. Next);
  673. ElfpFreeBuffer(FlushEvent);
  674. }
  675. //
  676. // Unlock the linked list
  677. //
  678. RtlLeaveCriticalSection(&QueuedEventCritSec);
  679. }
  680. VOID
  681. UnlinkLogModule(
  682. PLOGMODULE LogModule
  683. )
  684. /*++
  685. Routine Description:
  686. This routine unlinks the LogModule specified from the linked list.
  687. In order to protect against multiple thread/process access to the
  688. list at the same time, we use a critical section.
  689. Arguments:
  690. LogModule points to a context handle structure.
  691. Return Value:
  692. NONE
  693. Note:
  694. --*/
  695. {
  696. //
  697. // Lock the linked list
  698. //
  699. RtlEnterCriticalSection(&LogModuleCritSec);
  700. //
  701. // Remove this entry
  702. //
  703. RemoveEntryList(&LogModule->ModuleList);
  704. //
  705. // Unlock the linked list
  706. //
  707. RtlLeaveCriticalSection(&LogModuleCritSec);
  708. }
  709. VOID
  710. LinkLogModule (
  711. PLOGMODULE LogModule,
  712. ANSI_STRING * pModuleNameA
  713. )
  714. /*++
  715. Routine Description:
  716. This routine links the LogModule specified into the linked list.
  717. In order to protect against multiple thread/process access to the
  718. list at the same time, we use a critical section.
  719. Arguments:
  720. LogModule points to a context handle structure.
  721. ANSI LogModule name.
  722. Return Value:
  723. NONE
  724. Note:
  725. --*/
  726. {
  727. //
  728. // Lock the linked list
  729. //
  730. RtlEnterCriticalSection(&LogModuleCritSec);
  731. //
  732. // Add the atom for this module.
  733. //
  734. LogModule->ModuleAtom = AddAtomA(pModuleNameA->Buffer);
  735. //
  736. // Place structure at the beginning of the list.
  737. //
  738. InsertHeadList(&LogModuleHead, &LogModule->ModuleList);
  739. //
  740. // Unlock the linked list
  741. //
  742. RtlLeaveCriticalSection(&LogModuleCritSec);
  743. }
  744. VOID
  745. UnlinkLogFile(
  746. PLOGFILE pLogFile
  747. )
  748. /*++
  749. Routine Description:
  750. This routine unlinks the LogFile structure specified from the linked
  751. list of log files;
  752. In order to protect against multiple thread/process access to the
  753. list at the same time, we use a critical section.
  754. Arguments:
  755. pLogFile points to a log file structure.
  756. Return Value:
  757. NONE
  758. Note:
  759. --*/
  760. {
  761. //
  762. // Lock the linked list
  763. //
  764. RtlEnterCriticalSection(&LogFileCritSec);
  765. //
  766. // Remove this entry
  767. //
  768. RemoveEntryList(&pLogFile->FileList);
  769. //
  770. // Unlock the linked list
  771. //
  772. RtlLeaveCriticalSection(&LogFileCritSec);
  773. }
  774. VOID
  775. LinkLogFile (
  776. PLOGFILE pLogFile
  777. )
  778. /*++
  779. Routine Description:
  780. This routine links the LogFile specified into the linked list of
  781. log files.
  782. In order to protect against multiple thread/process access to the
  783. list at the same time, we use a critical section.
  784. Arguments:
  785. pLogFile points to a context handle structure.
  786. Return Value:
  787. NONE
  788. Note:
  789. --*/
  790. {
  791. //
  792. // Lock the linked list
  793. //
  794. RtlEnterCriticalSection(&LogFileCritSec);
  795. //
  796. // Place structure at the beginning of the list.
  797. //
  798. InsertHeadList(&LogFilesHead, &pLogFile->FileList);
  799. //
  800. // Unlock the linked list
  801. //
  802. RtlLeaveCriticalSection(&LogFileCritSec);
  803. }
  804. VOID
  805. GetGlobalResource (
  806. DWORD Type
  807. )
  808. /*++
  809. Routine Description:
  810. This routine takes the global resource either for shared access or
  811. exclusive access depending on the value of Type. It waits forever for
  812. the resource to become available.
  813. Arguments:
  814. Type is one of ELF_GLOBAL_SHARED or ELF_GLOBAL_EXCLUSIVE.
  815. Return Value:
  816. NONE
  817. Note:
  818. --*/
  819. {
  820. BOOL Acquired;
  821. if (Type & ELF_GLOBAL_SHARED)
  822. {
  823. Acquired = RtlAcquireResourceShared(&GlobalElfResource,
  824. TRUE); // Wait forever
  825. }
  826. else
  827. {
  828. //
  829. // Assume EXCLUSIVE
  830. //
  831. Acquired = RtlAcquireResourceExclusive(&GlobalElfResource,
  832. TRUE); // Wait forever
  833. }
  834. ASSERT(Acquired); // This must always be TRUE.
  835. }
  836. VOID
  837. ReleaseGlobalResource(
  838. VOID
  839. )
  840. /*++
  841. Routine Description:
  842. This routine releases the global resource.
  843. Arguments:
  844. NONE
  845. Return Value:
  846. NONE
  847. Note:
  848. --*/
  849. {
  850. RtlReleaseResource(&GlobalElfResource);
  851. }
  852. VOID
  853. InvalidateContextHandlesForLogFile(
  854. PLOGFILE pLogFile
  855. )
  856. /*++
  857. Routine Description:
  858. This routine walks through the context handles and marks the ones
  859. that point to the LogFile passed in as "invalid for read".
  860. Arguments:
  861. Pointer to log file structure.
  862. Return Value:
  863. NONE.
  864. Note:
  865. --*/
  866. {
  867. IELF_HANDLE LogHandle;
  868. PLOGMODULE pLogModule;
  869. //
  870. // Lock the context handle list
  871. //
  872. RtlEnterCriticalSection(&LogHandleCritSec);
  873. //
  874. // Walk the linked list and mark any matching context handles as
  875. // invalid.
  876. //
  877. LogHandle = CONTAINING_RECORD(LogHandleListHead.Flink,
  878. struct _IELF_HANDLE,
  879. Next);
  880. while (LogHandle->Next.Flink != LogHandleListHead.Flink)
  881. {
  882. pLogModule = FindModuleStrucFromAtom(LogHandle->Atom);
  883. ASSERT(pLogModule);
  884. if (pLogModule && (pLogFile == pLogModule->LogFile))
  885. {
  886. LogHandle->Flags |= ELF_LOG_HANDLE_INVALID_FOR_READ;
  887. }
  888. LogHandle = CONTAINING_RECORD(LogHandle->Next.Flink,
  889. struct _IELF_HANDLE,
  890. Next);
  891. }
  892. //
  893. // Unlock the context handle list
  894. //
  895. RtlLeaveCriticalSection(&LogHandleCritSec);
  896. }
  897. VOID
  898. FixContextHandlesForRecord(
  899. DWORD RecordOffset,
  900. DWORD NewRecordOffset,
  901. PLOGFILE pLogFile
  902. )
  903. /*++
  904. Routine Description:
  905. This routine makes sure that the record starting at RecordOffset isn't
  906. the current record for any open handle. If it is, the handle is adjusted
  907. to point to the next record.
  908. Arguments:
  909. RecordOffset - The byte offset in the log of the record that is about
  910. to be overwritten.
  911. NewStartingRecord - The new location to point the handle to (this is the
  912. new first record)
  913. Return Value:
  914. NONE.
  915. Note:
  916. --*/
  917. {
  918. IELF_HANDLE LogHandle;
  919. PLOGMODULE Module;
  920. //
  921. // Lock the context handle list
  922. //
  923. RtlEnterCriticalSection(&LogHandleCritSec);
  924. //
  925. // Walk the linked list and fix any matching context handles
  926. //
  927. LogHandle = CONTAINING_RECORD(LogHandleListHead.Flink,
  928. struct _IELF_HANDLE,
  929. Next);
  930. while (LogHandle->Next.Flink != LogHandleListHead.Flink)
  931. {
  932. if (LogHandle->SeekBytePos == RecordOffset)
  933. {
  934. Module = FindModuleStrucFromAtom (LogHandle->Atom);
  935. if(Module && Module->LogFile == pLogFile)
  936. {
  937. LogHandle->SeekBytePos = NewRecordOffset;
  938. }
  939. }
  940. LogHandle = CONTAINING_RECORD(LogHandle->Next.Flink,
  941. struct _IELF_HANDLE,
  942. Next);
  943. }
  944. //
  945. // Unlock the context handle list
  946. //
  947. RtlLeaveCriticalSection(&LogHandleCritSec);
  948. }
  949. PLOGFILE
  950. FindLogFileFromName(
  951. PUNICODE_STRING pFileName
  952. )
  953. /*++
  954. Routine Description:
  955. This routine looks at all the log files to find one that matches
  956. the name passed in.
  957. Arguments:
  958. Pointer to name of file.
  959. Return Value:
  960. Matching LOGFILE structure if file in use.
  961. Note:
  962. --*/
  963. {
  964. PLOGFILE pLogFile;
  965. //
  966. // Lock the linked list
  967. //
  968. RtlEnterCriticalSection(&LogFileCritSec);
  969. pLogFile = CONTAINING_RECORD(LogFilesHead.Flink,
  970. LOGFILE,
  971. FileList);
  972. while (pLogFile->FileList.Flink != LogFilesHead.Flink)
  973. {
  974. //
  975. // BUGBUG: This should probably be _wcsicmp() since the log module
  976. // names are assumed to be case insensitive (so the log
  977. // file names should be as well else we can get weirdness
  978. // with overlapping module names if somebody creates a log
  979. // named something like "application" or "system")
  980. //
  981. if (wcscmp(pLogFile->LogFileName->Buffer, pFileName->Buffer) == 0)
  982. break;
  983. pLogFile = CONTAINING_RECORD(pLogFile->FileList.Flink,
  984. LOGFILE,
  985. FileList);
  986. }
  987. //
  988. // Unlock the linked list
  989. //
  990. RtlLeaveCriticalSection(&LogFileCritSec);
  991. return (pLogFile->FileList.Flink == LogFilesHead.Flink ? NULL : pLogFile);
  992. }
  993. PLOGFILE
  994. FindLogFileByModName(
  995. LPWSTR pwsLogDefModName)
  996. /*++
  997. Routine Description:
  998. This routine looks at all the log files to find one that has the
  999. same default module name
  1000. Arguments:
  1001. Pointer to name of file.
  1002. Return Value:
  1003. Matching LOGFILE structure if file in use.
  1004. Note:
  1005. --*/
  1006. {
  1007. PLOGFILE pLogFile;
  1008. //
  1009. // Lock the linked list
  1010. //
  1011. RtlEnterCriticalSection(&LogFileCritSec);
  1012. pLogFile = CONTAINING_RECORD(LogFilesHead.Flink,
  1013. LOGFILE,
  1014. FileList);
  1015. while (pLogFile->FileList.Flink != LogFilesHead.Flink)
  1016. {
  1017. if (_wcsicmp(pLogFile->LogModuleName->Buffer, pwsLogDefModName) == 0)
  1018. break;
  1019. pLogFile = CONTAINING_RECORD(pLogFile->FileList.Flink,
  1020. LOGFILE,
  1021. FileList);
  1022. }
  1023. //
  1024. // Unlock the linked list
  1025. //
  1026. RtlLeaveCriticalSection(&LogFileCritSec);
  1027. return (pLogFile->FileList.Flink == LogFilesHead.Flink ? NULL : pLogFile);
  1028. }
  1029. #define ELF_MODULE_NAME L"EventLog"
  1030. #define ELFSEC_MODULE_NAME L"SECURITY"
  1031. VOID
  1032. ElfpCreateElfEvent(
  1033. IN ULONG EventId,
  1034. IN USHORT EventType,
  1035. IN USHORT EventCategory,
  1036. IN USHORT NumStrings,
  1037. IN LPWSTR * Strings,
  1038. IN LPVOID Data,
  1039. IN ULONG DataSize,
  1040. IN USHORT Flags,
  1041. IN BOOL ForSecurity
  1042. )
  1043. /*++
  1044. Routine Description:
  1045. This creates an request packet to write an event on behalf of the event
  1046. log service itself. It then queues this packet to a linked list for
  1047. writing later.
  1048. Arguments:
  1049. The fields to use to create the event record
  1050. Return Value:
  1051. None
  1052. Note:
  1053. --*/
  1054. {
  1055. PELF_QUEUED_EVENT QueuedEvent;
  1056. PWRITE_PKT WritePkt;
  1057. PEVENTLOGRECORD EventLogRecord;
  1058. PBYTE BinaryData;
  1059. ULONG RecordLength;
  1060. ULONG StringOffset, DataOffset;
  1061. USHORT StringsSize = 0;
  1062. USHORT i;
  1063. ULONG PadSize;
  1064. ULONG ModuleNameLen; // Length in bytes
  1065. ULONG zero = 0; // For pad bytes
  1066. LARGE_INTEGER Time;
  1067. ULONG LogTimeWritten;
  1068. PWSTR ReplaceStrings;
  1069. WCHAR LocalComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1070. ULONG ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  1071. BOOL bOK;
  1072. LPWSTR pwcModule;
  1073. LPWSTR pwFirstString;
  1074. if(ForSecurity)
  1075. pwcModule = ELFSEC_MODULE_NAME;
  1076. else
  1077. pwcModule = ELF_MODULE_NAME;
  1078. // Get the computer name
  1079. bOK = GetComputerNameW(LocalComputerName, &ComputerNameLength);
  1080. if(bOK == FALSE)
  1081. {
  1082. ELF_LOG1(ERROR,
  1083. "ElfpCreateElfEvent: failed calling GetComputerNameW, last error 0x%x\n",
  1084. GetLastError());
  1085. return;
  1086. }
  1087. ComputerNameLength = (ComputerNameLength+1)*sizeof(WCHAR);
  1088. ELF_LOG1(TRACE,
  1089. "ElfpCreateElfEvent: Logging event ID %d\n",
  1090. EventId);
  1091. //
  1092. // LogTimeWritten
  1093. // We need to generate a time when the log is written. This
  1094. // gets written in the log so that we can use it to test the
  1095. // retention period when wrapping the file.
  1096. //
  1097. NtQuerySystemTime(&Time);
  1098. RtlTimeToSecondsSince1970(&Time,
  1099. &LogTimeWritten);
  1100. //
  1101. // Figure out how big a buffer to allocate
  1102. //
  1103. ModuleNameLen = (wcslen(pwcModule) + 1) * sizeof (WCHAR);
  1104. ELF_LOG1(TRACE,
  1105. "ElfpCreateElfEvent: Length of module name is %d\n",
  1106. ModuleNameLen);
  1107. StringOffset = sizeof(EVENTLOGRECORD)
  1108. + ModuleNameLen
  1109. + ComputerNameLength;
  1110. //
  1111. // Calculate the length of strings so that we can see how
  1112. // much space is needed for that.
  1113. //
  1114. for (i = 0; i < NumStrings; i++)
  1115. {
  1116. StringsSize += wcslen(Strings[i]) + 1;
  1117. ELF_LOG2(TRACE,
  1118. "ElfpCreateElfEvent: Length of string %d (including NULL) is %d\n",
  1119. i,
  1120. wcslen(Strings[i]) + 1);
  1121. }
  1122. //
  1123. // DATA OFFSET:
  1124. //
  1125. DataOffset = StringOffset + StringsSize * sizeof(WCHAR);
  1126. //
  1127. // Determine how big a buffer is needed for the queued event record.
  1128. //
  1129. RecordLength = sizeof(ELF_QUEUED_EVENT)
  1130. + sizeof(WRITE_PKT)
  1131. + DataOffset
  1132. + DataSize
  1133. + sizeof(RecordLength); // Size excluding pad bytes
  1134. ELF_LOG1(TRACE,
  1135. "ElfpCreateElfEvent: RecordLength (no pad bytes) is %d\n",
  1136. RecordLength);
  1137. //
  1138. // Determine how many pad bytes are needed to align to a DWORD
  1139. // boundary.
  1140. //
  1141. PadSize = sizeof(ULONG) - (RecordLength % sizeof(ULONG));
  1142. RecordLength += PadSize; // True size needed
  1143. ELF_LOG2(TRACE,
  1144. "ElfpCreateElfEvent: RecordLength (with %d pad bytes) is %d\n",
  1145. PadSize,
  1146. RecordLength);
  1147. //
  1148. // Allocate the buffer for the Eventlog record
  1149. //
  1150. QueuedEvent = (PELF_QUEUED_EVENT) ElfpAllocateBuffer(RecordLength);
  1151. WritePkt = (PWRITE_PKT) (QueuedEvent + 1);
  1152. if (QueuedEvent != NULL)
  1153. {
  1154. //
  1155. // Fill up the event record
  1156. //
  1157. RecordLength -= (sizeof(ELF_QUEUED_EVENT) + sizeof(WRITE_PKT));
  1158. EventLogRecord = (PEVENTLOGRECORD) (WritePkt + 1);
  1159. EventLogRecord->Length = RecordLength;
  1160. EventLogRecord->TimeGenerated = LogTimeWritten;
  1161. EventLogRecord->Reserved = ELF_LOG_FILE_SIGNATURE;
  1162. EventLogRecord->TimeWritten = LogTimeWritten;
  1163. EventLogRecord->EventID = EventId;
  1164. EventLogRecord->EventType = EventType;
  1165. EventLogRecord->EventCategory = EventCategory;
  1166. EventLogRecord->ReservedFlags = 0;
  1167. EventLogRecord->ClosingRecordNumber = 0;
  1168. EventLogRecord->NumStrings = NumStrings;
  1169. EventLogRecord->StringOffset = StringOffset;
  1170. EventLogRecord->DataLength = DataSize;
  1171. EventLogRecord->DataOffset = DataOffset;
  1172. EventLogRecord->UserSidLength = 0;
  1173. EventLogRecord->UserSidOffset = StringOffset;
  1174. //
  1175. // Fill in the variable-length fields
  1176. //
  1177. //
  1178. // STRINGS
  1179. //
  1180. ReplaceStrings = (PWSTR) ((PBYTE) EventLogRecord
  1181. + StringOffset);
  1182. pwFirstString = ReplaceStrings;
  1183. for (i = 0; i < NumStrings; i++)
  1184. {
  1185. ELF_LOG2(TRACE,
  1186. "ElfpCreateElfEvent: Copying string %d (%ws) into record\n",
  1187. i,
  1188. Strings[i]);
  1189. StringCchCopyW(ReplaceStrings, StringsSize - (ReplaceStrings - pwFirstString), Strings[i]);
  1190. ReplaceStrings += wcslen(Strings[i]) + 1;
  1191. }
  1192. //
  1193. // MODULENAME
  1194. //
  1195. BinaryData = (PBYTE) EventLogRecord + sizeof(EVENTLOGRECORD);
  1196. RtlCopyMemory(BinaryData,
  1197. pwcModule,
  1198. ModuleNameLen);
  1199. //
  1200. // COMPUTERNAME
  1201. //
  1202. BinaryData += ModuleNameLen; // Now point to computername
  1203. RtlCopyMemory(BinaryData,
  1204. LocalComputerName,
  1205. ComputerNameLength);
  1206. //
  1207. // BINARY DATA
  1208. //
  1209. BinaryData = (PBYTE) ((PBYTE) EventLogRecord + DataOffset);
  1210. RtlCopyMemory(BinaryData, Data, DataSize);
  1211. //
  1212. // PAD - Fill with zeros
  1213. //
  1214. BinaryData += DataSize;
  1215. RtlCopyMemory(BinaryData, &zero, PadSize);
  1216. //
  1217. // LENGTH at end of record
  1218. //
  1219. BinaryData += PadSize; // Point after pad bytes
  1220. ((PULONG) BinaryData)[0] = RecordLength;
  1221. //
  1222. // Build the QueuedEvent Packet
  1223. //
  1224. QueuedEvent->Type = Event;
  1225. QueuedEvent->Event.Request.Pkt.WritePkt = WritePkt;
  1226. if(ForSecurity)
  1227. {
  1228. QueuedEvent->Event.Request.Module = ElfSecModule;
  1229. QueuedEvent->Event.Request.LogFile = ElfSecModule->LogFile;
  1230. }
  1231. else
  1232. {
  1233. if(ElfModule)
  1234. {
  1235. QueuedEvent->Event.Request.Module = ElfModule;
  1236. QueuedEvent->Event.Request.LogFile = ElfModule->LogFile;
  1237. }
  1238. else
  1239. {
  1240. QueuedEvent->Event.Request.Module = NULL;
  1241. QueuedEvent->Event.Request.LogFile = NULL;
  1242. }
  1243. }
  1244. QueuedEvent->Event.Request.Flags = Flags;
  1245. QueuedEvent->Event.Request.Command = ELF_COMMAND_WRITE;
  1246. QueuedEvent->Event.Request.Pkt.WritePkt->Buffer = EventLogRecord;
  1247. QueuedEvent->Event.Request.Pkt.WritePkt->Datasize = RecordLength;
  1248. //
  1249. // Now Queue it on the linked list
  1250. //
  1251. LinkQueuedEvent(QueuedEvent);
  1252. }
  1253. else
  1254. {
  1255. ELF_LOG0(ERROR,
  1256. "ElfpCreateElfEvent: Unable to allocate memory for QueuedEvent\n");
  1257. }
  1258. }
  1259. VOID
  1260. ElfpCreateQueuedAlert(
  1261. DWORD MessageId,
  1262. DWORD NumberOfStrings,
  1263. LPWSTR Strings[]
  1264. )
  1265. {
  1266. DWORD i;
  1267. DWORD RecordLength;
  1268. PELF_QUEUED_EVENT QueuedEvent;
  1269. PUNICODE_STRING UnicodeStrings;
  1270. LPWSTR pString;
  1271. PBYTE ptr;
  1272. LARGE_INTEGER Time;
  1273. ULONG CurrentTime;
  1274. ELF_LOG1(TRACE,
  1275. "ElfpCreateQueuedAlert: Creating alert for message ID %d\n",
  1276. MessageId);
  1277. //
  1278. // Turn the input strings into UNICODE_STRINGS and figure out how
  1279. // big to make the buffer to allocate
  1280. //
  1281. RecordLength = sizeof(UNICODE_STRING) * NumberOfStrings;
  1282. UnicodeStrings = ElfpAllocateBuffer(RecordLength);
  1283. if (!UnicodeStrings)
  1284. {
  1285. ELF_LOG0(TRACE,
  1286. "ElfpCreateQueuedAlert: Unable to allocate memory for UnicodeStrings\n");
  1287. return;
  1288. }
  1289. RecordLength += FIELD_OFFSET(ELF_QUEUED_EVENT, Event) +
  1290. sizeof(ELF_ALERT_RECORD);
  1291. for (i = 0; i < NumberOfStrings; i++)
  1292. {
  1293. RtlInitUnicodeString(&UnicodeStrings[i], Strings[i]);
  1294. RecordLength += UnicodeStrings[i].MaximumLength;
  1295. ELF_LOG2(TRACE,
  1296. "ElfpCreateQueuedAlert: Length of string %d is %d\n",
  1297. i,
  1298. UnicodeStrings[i].MaximumLength);
  1299. }
  1300. //
  1301. // Now allocate what will be the real queued event
  1302. //
  1303. QueuedEvent = ElfpAllocateBuffer(RecordLength);
  1304. if (!QueuedEvent)
  1305. {
  1306. ELF_LOG0(ERROR,
  1307. "ElfpCreateQueuedAlert: Unable to allocate memory for QueuedEvent\n");
  1308. ElfpFreeBuffer(UnicodeStrings);
  1309. return;
  1310. }
  1311. QueuedEvent->Type = Alert;
  1312. QueuedEvent->Event.Alert.MessageId = MessageId;
  1313. QueuedEvent->Event.Alert.NumberOfStrings = NumberOfStrings;
  1314. //
  1315. // If we can't send the alert in 5 minutes, give up
  1316. //
  1317. NtQuerySystemTime(&Time);
  1318. RtlTimeToSecondsSince1970(&Time, &CurrentTime);
  1319. QueuedEvent->Event.Alert.TimeOut = CurrentTime + 300;
  1320. //
  1321. // Move the array of UNICODE_STRINGS into the queued event and
  1322. // point UnicodeStrings at it. Then fix up the Buffer pointers.
  1323. //
  1324. ptr = (PBYTE) QueuedEvent
  1325. + FIELD_OFFSET(ELF_QUEUED_EVENT, Event)
  1326. + sizeof(ELF_ALERT_RECORD);
  1327. RtlCopyMemory(ptr,
  1328. UnicodeStrings,
  1329. sizeof(UNICODE_STRING) * NumberOfStrings);
  1330. ElfpFreeBuffer(UnicodeStrings);
  1331. UnicodeStrings = (PUNICODE_STRING) ptr;
  1332. pString = (LPWSTR) (ptr + sizeof(UNICODE_STRING) * NumberOfStrings);
  1333. for (i = 0; i < NumberOfStrings; i++)
  1334. {
  1335. ELF_LOG3(TRACE,
  1336. "ElfpCreateQueuedAlert: Copying string %d (%*ws) into QueuedEvent record\n",
  1337. i,
  1338. UnicodeStrings[i].MaximumLength / sizeof(WCHAR),
  1339. UnicodeStrings[i].Buffer);
  1340. RtlCopyMemory(pString,
  1341. UnicodeStrings[i].Buffer,
  1342. UnicodeStrings[i].MaximumLength);
  1343. UnicodeStrings[i].Buffer = pString;
  1344. pString = (LPWSTR) ((PBYTE) pString + UnicodeStrings[i].MaximumLength);
  1345. }
  1346. LinkQueuedEvent(QueuedEvent);
  1347. }
  1348. VOID
  1349. ElfpCreateQueuedMessage(
  1350. DWORD MessageId,
  1351. DWORD NumberOfStrings,
  1352. LPWSTR Strings[]
  1353. )
  1354. {
  1355. DWORD i;
  1356. DWORD RecordLength = 0;
  1357. PELF_QUEUED_EVENT QueuedEvent;
  1358. LPWSTR pString;
  1359. DWORD StringsSize = 0;
  1360. LPWSTR pwFirstString;
  1361. ELF_LOG1(TRACE,
  1362. "ElfpCreateQueuedMessage: Creating message for message ID %d\n",
  1363. MessageId);
  1364. //
  1365. // Figure out how big to make the buffer to allocate
  1366. //
  1367. RecordLength = sizeof(ELF_QUEUED_EVENT);
  1368. for (i = 0; i < NumberOfStrings; i++)
  1369. {
  1370. StringsSize += (wcslen(Strings[i]) + 1) * sizeof(WCHAR);
  1371. ELF_LOG2(TRACE,
  1372. "ElfpCreateQueuedMessage: Length of string %d (including NULL) is %d\n",
  1373. i,
  1374. wcslen(Strings[i]) + 1);
  1375. }
  1376. RecordLength += StringsSize;
  1377. //
  1378. // Now allocate what will be the real queued event
  1379. //
  1380. QueuedEvent = ElfpAllocateBuffer(RecordLength);
  1381. if (!QueuedEvent)
  1382. {
  1383. ELF_LOG0(ERROR,
  1384. "ElfpCreateQueuedMessage: Unable to allocate memory for QueuedEvent\n");
  1385. return;
  1386. }
  1387. QueuedEvent->Type = Message;
  1388. QueuedEvent->Event.Message.MessageId = MessageId;
  1389. QueuedEvent->Event.Message.NumberOfStrings = NumberOfStrings;
  1390. //
  1391. // Move the array of UNICODE strings into the queued event
  1392. //
  1393. pString = (LPWSTR) ((PBYTE) QueuedEvent
  1394. + FIELD_OFFSET(ELF_QUEUED_EVENT, Event)
  1395. + sizeof(ELF_MESSAGE_RECORD));
  1396. pwFirstString = pString;
  1397. for (i = 0; i < NumberOfStrings; i++)
  1398. {
  1399. StringCchCopyW(pString, StringsSize - (pString - pwFirstString) ,Strings[i]);
  1400. pString += wcslen(Strings[i]) + 1;
  1401. ELF_LOG2(TRACE,
  1402. "ElfpCreateQueuedMessage: Copying string %d (%ws) into QueuedEvent buffer\n",
  1403. i,
  1404. Strings[i]);
  1405. }
  1406. LinkQueuedMessage(QueuedEvent);
  1407. }
  1408. NTSTATUS
  1409. ElfpInitCriticalSection(
  1410. PRTL_CRITICAL_SECTION pCritsec
  1411. )
  1412. {
  1413. NTSTATUS ntStatus;
  1414. //
  1415. // RtlInitializeCriticalSection will raise an exception
  1416. // if it runs out of resources
  1417. //
  1418. try
  1419. {
  1420. ntStatus = RtlInitializeCriticalSection(pCritsec);
  1421. if (!NT_SUCCESS(ntStatus))
  1422. {
  1423. ELF_LOG1(ERROR,
  1424. "ElfpInitCriticalSection: RtlInitializeCriticalSection failed %#x\n",
  1425. ntStatus);
  1426. }
  1427. }
  1428. except(EXCEPTION_EXECUTE_HANDLER)
  1429. {
  1430. ELF_LOG1(ERROR,
  1431. "ElfpInitCriticalSection: Exception %#x caught initializing critsec\n",
  1432. GetExceptionCode());
  1433. ntStatus = STATUS_NO_MEMORY;
  1434. }
  1435. return ntStatus;
  1436. }
  1437. NTSTATUS
  1438. ElfpInitResource(
  1439. PRTL_RESOURCE pResource
  1440. )
  1441. {
  1442. NTSTATUS ntStatus = STATUS_SUCCESS;
  1443. //
  1444. // RtlInitializeResource will raise an exception
  1445. // if it runs out of resources
  1446. //
  1447. try
  1448. {
  1449. RtlInitializeResource(pResource);
  1450. }
  1451. except(EXCEPTION_EXECUTE_HANDLER)
  1452. {
  1453. ELF_LOG1(ERROR,
  1454. "ElfpInitResource: Exception %#x caught initializing resource\n",
  1455. GetExceptionCode());
  1456. ntStatus = STATUS_NO_MEMORY;
  1457. }
  1458. return ntStatus;
  1459. }
  1460. DWORD EstimateEventSize(
  1461. DWORD dwStringEst,
  1462. DWORD dwDataEst,
  1463. LPWSTR pwsModuleName
  1464. )
  1465. /*++
  1466. Routine Description:
  1467. This estimates the number of bytes needed to hold an event..
  1468. Arguments:
  1469. dwStringEst - Callers estimate of the amount of space to be needed for strings
  1470. dwDataEst - Callers estimate of the amount of space to be needed for data
  1471. ModuleName - Module name
  1472. Return Value:
  1473. Estimated size
  1474. Note:
  1475. --*/
  1476. {
  1477. WCHAR LocalComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1478. BOOL bOK;
  1479. ULONG ComputerNameLength = MAX_COMPUTERNAME_LENGTH + 1;
  1480. DWORD dwPadSize;
  1481. DWORD dwSize = 0;
  1482. static long lNameSize = 0;
  1483. dwSize += sizeof(EVENTLOGRECORD);
  1484. if(pwsModuleName)
  1485. {
  1486. dwSize += sizeof(WCHAR) * (wcslen(pwsModuleName) + 1);
  1487. }
  1488. if(lNameSize == 0)
  1489. {
  1490. bOK = GetComputerNameW(LocalComputerName, &ComputerNameLength);
  1491. if(bOK)
  1492. lNameSize = sizeof(WCHAR) * (ComputerNameLength + 1);
  1493. else
  1494. lNameSize = sizeof(WCHAR) * (MAX_COMPUTERNAME_LENGTH + 1);
  1495. }
  1496. dwSize += lNameSize;
  1497. ALIGN_UP_64(dwSize, sizeof(PVOID));
  1498. // assume worst case sid. Max of 15 sub authorities, so size is 1+1+6+15*sizeof(DWORD)
  1499. dwSize += 68;
  1500. dwSize += dwStringEst;
  1501. dwSize += dwDataEst;
  1502. // finally add in the terminating length and padding
  1503. dwSize += sizeof(DWORD);
  1504. dwPadSize = sizeof(DWORD) - (dwSize % sizeof(DWORD));
  1505. dwSize += dwPadSize;
  1506. return dwSize;
  1507. }
  1508. ULONG
  1509. GetNoonEventSystemUptime(
  1510. )
  1511. /*++
  1512. Routine Description:
  1513. This routine called NtQuerySystemInformation to get the system uptime.
  1514. Arguments:
  1515. NONE
  1516. Return Value:
  1517. Uptime in seconds.
  1518. Note:
  1519. --*/
  1520. {
  1521. NTSTATUS status;
  1522. SYSTEM_TIMEOFDAY_INFORMATION TimeOfDayInfo;
  1523. ULONG ulBootTime;
  1524. ULONG ulCurrentTime;
  1525. ULONG ulUptime = 0;
  1526. //
  1527. // Get system uptime.
  1528. //
  1529. status = NtQuerySystemInformation( SystemTimeOfDayInformation,
  1530. &TimeOfDayInfo,
  1531. sizeof(SYSTEM_TIMEOFDAY_INFORMATION),
  1532. NULL);
  1533. if ( NT_SUCCESS(status) )
  1534. {
  1535. RtlTimeToSecondsSince1980( &TimeOfDayInfo.CurrentTime, &ulCurrentTime);
  1536. RtlTimeToSecondsSince1980( &TimeOfDayInfo.BootTime, &ulBootTime);
  1537. ulUptime = ulCurrentTime - ulBootTime;
  1538. }
  1539. return ulUptime;
  1540. }
  1541. ULONG GetNextNoonEventDelay(
  1542. )
  1543. /*++
  1544. Routine Description:
  1545. This routine calculate how long the thread need to wait before the next noon.
  1546. Arguments:
  1547. Return Value:
  1548. Time in Seconds.
  1549. Note:
  1550. --*/
  1551. {
  1552. SYSTEMTIME localTime;
  1553. DWORD dwWaitSecs;
  1554. #define NOON_EVENT_HOUR 12
  1555. GetLocalTime( &localTime );
  1556. if ( localTime.wHour >= NOON_EVENT_HOUR )
  1557. {
  1558. dwWaitSecs = ( (24 + NOON_EVENT_HOUR) - localTime.wHour - 1) * 60;
  1559. }
  1560. else
  1561. {
  1562. dwWaitSecs = (NOON_EVENT_HOUR - localTime.wHour - 1) * 60;
  1563. }
  1564. dwWaitSecs = (dwWaitSecs + (60 - localTime.wMinute) - 1) * 60 + (60 - localTime.wSecond);
  1565. #undef NOON_EVENTHOUR
  1566. ELF_LOG1(TRACE,
  1567. "NextNoonEvent Delay: %d seconds\n",
  1568. dwWaitSecs );
  1569. return dwWaitSecs;
  1570. }
  1571. ULONG GetNoonEventTimeStamp(
  1572. )
  1573. /*++
  1574. Routine Description:
  1575. This routine retrieves the timestamp interval information from the registry.
  1576. It will first check the policy key, if the TimeStampInterval is not set or not
  1577. configured, we will check our private TimeStamp key.
  1578. Arguments:
  1579. NONE
  1580. Return Value:
  1581. time stamp interval in seconds.
  1582. Note:
  1583. --*/
  1584. {
  1585. const WCHAR RELIABILITY_TIMESTAMP[] = L"TimeStampInterval";
  1586. const WCHAR RELIABILITY_TIMESTAMP_ENABLED[] = L"TimeStampEnabled";
  1587. const ULONG MAX_ALLOWED_TIME_STAMP_INTERVAL = 86400; //24 hours.
  1588. HKEY hPolicyKey;
  1589. HKEY hPrivateKey;
  1590. DWORD dwResult = 0;
  1591. DWORD dwNewInterval = 0;
  1592. DWORD dwPolicyEnabled = 0;
  1593. DWORD cbData = 0;
  1594. //
  1595. // POLICY
  1596. //
  1597. if ( !(dwResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1598. REGSTR_PATH_RELIABILITY_POLICY,
  1599. 0,
  1600. KEY_READ,
  1601. &hPolicyKey ) ) )
  1602. {
  1603. //
  1604. // 1. check if the policy is enabled or not. (by accessing key:
  1605. // RELIABLITY_TIMESTAMP_ENABLED )
  1606. // 2. if policy is enabled, read the RELIABLITY_TIMESTAMP key
  1607. // for time stamp interval.
  1608. // 3. if policy is disable, return 0.
  1609. // 4. if policy is not configured, read the private key.
  1610. //
  1611. cbData = sizeof( DWORD );
  1612. if ( !(dwResult = RegQueryValueEx(hPolicyKey,
  1613. RELIABILITY_TIMESTAMP_ENABLED,
  1614. 0,
  1615. NULL,
  1616. (LPBYTE)&dwPolicyEnabled,
  1617. &cbData) ) )
  1618. {
  1619. if ( !dwPolicyEnabled )
  1620. {
  1621. //
  1622. // Policy is disabled.
  1623. //
  1624. RegCloseKey( hPolicyKey );
  1625. return dwNewInterval;
  1626. }
  1627. cbData = sizeof( DWORD );
  1628. dwResult = RegQueryValueEx( hPolicyKey,
  1629. RELIABILITY_TIMESTAMP,
  1630. 0,
  1631. NULL,
  1632. (LPBYTE)&dwNewInterval,
  1633. &cbData );
  1634. if ( dwNewInterval > MAX_ALLOWED_TIME_STAMP_INTERVAL )
  1635. {
  1636. dwResult = ERROR_INVALID_PARAMETER;
  1637. dwNewInterval = 0;
  1638. }
  1639. }
  1640. else
  1641. {
  1642. //
  1643. // the key is not there (Policy Not Configured)
  1644. //
  1645. }
  1646. RegCloseKey( hPolicyKey );
  1647. }
  1648. //
  1649. // PRIVATE KEY
  1650. //
  1651. if ( dwResult &&
  1652. !(dwResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1653. REGSTR_PATH_RELIABILITY,
  1654. 0,
  1655. KEY_READ,
  1656. &hPrivateKey ) ) )
  1657. {
  1658. cbData = sizeof( DWORD );
  1659. if ( !RegQueryValueEx( hPrivateKey,
  1660. REGSTR_VAL_LASTALIVEINTERVAL,
  1661. 0,
  1662. NULL,
  1663. (LPBYTE) &dwNewInterval,
  1664. &cbData ) )
  1665. {
  1666. //
  1667. // Note: this private interval is in MINUTEs, while the policy
  1668. // controlled interval is in SECONDS.
  1669. //
  1670. dwNewInterval *= 60;
  1671. if ( dwNewInterval > MAX_ALLOWED_TIME_STAMP_INTERVAL )
  1672. dwNewInterval = 0;
  1673. }
  1674. RegCloseKey( hPrivateKey );
  1675. }
  1676. return dwNewInterval;
  1677. }
  1678. DWORD
  1679. GetModuleType(LPWSTR pwsModuleName)
  1680. {
  1681. if (!_wcsicmp(pwsModuleName, ELF_SYSTEM_MODULE_NAME))
  1682. {
  1683. return ELF_LOGFILE_SYSTEM;
  1684. }
  1685. else if (!_wcsicmp(pwsModuleName, ELF_SECURITY_MODULE_NAME))
  1686. {
  1687. return ELF_LOGFILE_SECURITY;
  1688. }
  1689. else if (!_wcsicmp(pwsModuleName, ELF_APPLICATION_MODULE_NAME))
  1690. {
  1691. return ELF_LOGFILE_APPLICATION;
  1692. }
  1693. else
  1694. {
  1695. return ELF_LOGFILE_CUSTOM;
  1696. }
  1697. }