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.

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