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.

2392 lines
66 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. eventlog.c
  5. Abstract:
  6. This file contains the main routines for the NT Event Logging Service.
  7. Author:
  8. Rajen Shah (rajens) 1-Jul-1991
  9. Revision History:
  10. 02-Mar-01 drbeck
  11. Modified ElfWriteProductInfoEvent to utilize GetVersionEx for OS major
  12. and minor version numbers as well as for the build number. The
  13. value CurrentBuild under the HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion
  14. registry is obsolete.
  15. 26-Jan-1994 Danl
  16. SetUpModules: Fixed memory leak where the buffers for the enumerated
  17. key names were never free'd. Also fixed problem where the size of
  18. the MULTI_SZ buffer used for the "Sources" key was calculated by
  19. using the names in the registry, while the copying was done
  20. using the names in the module list. When registry keys are deleted,
  21. the module list entry is retained until the next boot. Since the
  22. module list is larger, it would overwrite the MULTI_SZ buffer.
  23. 1-Nov-1993 Danl
  24. Make Eventlog service a DLL and attach it to services.exe.
  25. Pass in GlobalData to Elfmain. This GlobalData structure contains
  26. all well-known SIDs and pointers to the Rpc Server (Start & Stop)
  27. routines. Get rid of the service process main function.
  28. 1-Jul-1991 RajenS
  29. created
  30. --*/
  31. //
  32. // INCLUDES
  33. //
  34. #include <eventp.h>
  35. #include <ntrpcp.h>
  36. #include <elfcfg.h>
  37. #include <string.h>
  38. #include <tstr.h> // WCSSIZE
  39. #include <alertmsg.h> // ALERT_ELF manifests
  40. //
  41. // Bit Flags used for Progress Reporting in SetupDataStruct().
  42. //
  43. #define LOGFILE_OPENED 0x00000001
  44. #define MODULE_LINKED 0x00000002
  45. #define LOGFILE_LINKED 0x00000004
  46. HANDLE g_hTimestampWorkitem;
  47. HANDLE g_hTimestampEvent;
  48. ULONG g_PreviousInterval = DEFAULT_INTERVAL;
  49. long g_lNumSecurityWriters = 0;
  50. //
  51. // Local Function Prorotypes
  52. //
  53. VOID
  54. ElfInitMessageBoxTitle(
  55. VOID
  56. );
  57. NTSTATUS
  58. SetUpDataStruct (
  59. PUNICODE_STRING LogFileName,
  60. ULONG MaxFileSize,
  61. ULONG Retention,
  62. ULONG GuestAccessRestriction,
  63. PUNICODE_STRING ModuleName,
  64. HANDLE hLogFile,
  65. ELF_LOG_TYPE LogType,
  66. LOGPOPUP logpLogPopup,
  67. DWORD dwAutoBackup
  68. )
  69. /*++
  70. Routine Description:
  71. This routine sets up the information for one module. It is called from
  72. ElfSetUpConfigDataStructs for each module to be configured.
  73. Module information is passed into this routine and a LOGMODULE structure
  74. is created for it. If the logfile associated with this module doesn't
  75. exist, a LOGFILE structure is created for it, and added to the linked
  76. list of LOGFILE structures. The LOGMODULE is associated with the LOGFILE,
  77. and it is added to the linked list of LOGMODULE structures. The logfile
  78. is opened and mapped to memory.
  79. Finally, at the end, this function calls SetUpModules, which looks at
  80. all the subkeys in the registry under this logfile, and adds any new ones
  81. to the linked list, and updates the Sources MULTI_SZ for the event viewer.
  82. Arguments:
  83. LogFileName - Name of log file for this module. If this routine needs
  84. a copy of this name it will make one, so that the caller can free
  85. the name afterwards if that is desired.
  86. MaxFileSize - Max size of the log file.
  87. Retention - Max retention for the file.
  88. ModuleName - Name of module that this file is associated with.
  89. RegistryHandle - Handle to the root node for this LogFile's info
  90. in the registry. This is used to enumerate all the
  91. modules under this key.
  92. Return Value:
  93. Pointer to Module structure that is allocated in this routine.
  94. NTSTATUS
  95. Note:
  96. --*/
  97. {
  98. NTSTATUS Status = STATUS_SUCCESS;
  99. PLOGFILE pLogFile = NULL;
  100. PLOGMODULE pModule = NULL;
  101. ANSI_STRING ModuleNameA;
  102. DWORD Type;
  103. BOOL bAllocatedLogInfo = FALSE;
  104. PUNICODE_STRING SavedBackupFileName = NULL;
  105. DWORD StringLength;
  106. PLOGMODULE OldDefaultLogModule = NULL;
  107. DWORD Progress = 0L;
  108. //
  109. // Argument check.
  110. //
  111. if ((LogFileName == NULL) ||
  112. (LogFileName->Buffer == NULL) ||
  113. (ModuleName == NULL))
  114. {
  115. return(STATUS_INVALID_PARAMETER);
  116. }
  117. // If the default log file for a module is also being used by another
  118. // module, then we just link that same file structure with the other
  119. // module.
  120. //
  121. // Truncate the maximum size of the log file to a 4K boundary.
  122. // This is to allow for page granularity.
  123. //
  124. pLogFile = FindLogFileFromName (LogFileName);
  125. pModule = ElfpAllocateBuffer (sizeof (LOGMODULE) );
  126. if (pModule == NULL)
  127. {
  128. return(STATUS_NO_MEMORY);
  129. }
  130. if (pLogFile == NULL)
  131. {
  132. //
  133. //--------------------------------------
  134. // CREATE A NEW LOGFILE !!
  135. //--------------------------------------
  136. // A logfile by this name doesn't exist yet. So we will create
  137. // one so that we can add the module to it.
  138. //
  139. ELF_LOG1(TRACE,
  140. "SetupDataStruct: Create new struct for %ws log\n",
  141. LogFileName->Buffer);
  142. pLogFile = ElfpAllocateBuffer(sizeof(LOGFILE));
  143. if (pLogFile == NULL)
  144. {
  145. ELF_LOG1(ERROR,
  146. "SetupDataStruct: Unable to allocate struct for %ws log\n",
  147. LogFileName->Buffer);
  148. ElfpFreeBuffer(pModule);
  149. return STATUS_NO_MEMORY;
  150. }
  151. //
  152. // Allocate a new LogFileName that can be attached to the
  153. // new pLogFile structure.
  154. //
  155. StringLength = LogFileName->Length + sizeof(WCHAR);
  156. SavedBackupFileName = (PUNICODE_STRING) ElfpAllocateBuffer(
  157. sizeof(UNICODE_STRING) + StringLength);
  158. if (SavedBackupFileName == NULL)
  159. {
  160. ELF_LOG1(ERROR,
  161. "SetupDataStruct: Unable to allocate backup name for %ws log\n",
  162. LogFileName->Buffer);
  163. ElfpFreeBuffer(pModule);
  164. ElfpFreeBuffer(pLogFile);
  165. return STATUS_NO_MEMORY;
  166. }
  167. SavedBackupFileName->Buffer = (LPWSTR)((LPBYTE) SavedBackupFileName +
  168. sizeof(UNICODE_STRING));
  169. SavedBackupFileName->Length = LogFileName->Length;
  170. SavedBackupFileName->MaximumLength = (USHORT) StringLength;
  171. RtlMoveMemory(SavedBackupFileName->Buffer, LogFileName->Buffer,
  172. LogFileName->Length);
  173. SavedBackupFileName->Buffer[SavedBackupFileName->Length / sizeof(WCHAR)] =
  174. L'\0';
  175. //
  176. // This is the first user - RefCount gets incrememted below
  177. //
  178. pLogFile->RefCount = 0;
  179. pLogFile->FileHandle = NULL;
  180. pLogFile->LogFileName = SavedBackupFileName;
  181. pLogFile->ConfigMaxFileSize = ELFFILESIZE(MaxFileSize);
  182. pLogFile->Retention = Retention;
  183. pLogFile->ulLastPulseTime = 0;
  184. pLogFile->logpLogPopup = logpLogPopup;
  185. pLogFile->bFullAlertDone = FALSE;
  186. pLogFile->AutoBackupLogFiles = dwAutoBackup;
  187. //
  188. // Save away the default module name for this file
  189. //
  190. pLogFile->LogModuleName = ElfpAllocateBuffer(
  191. sizeof(UNICODE_STRING) + ModuleName->MaximumLength);
  192. //
  193. // This flag can be set since pLogfile->LogModuleName
  194. // will be initialized after this point
  195. //
  196. bAllocatedLogInfo = TRUE;
  197. if (pLogFile->LogModuleName == NULL)
  198. {
  199. ELF_LOG1(ERROR,
  200. "SetupDataStruct: Unable to allocate module name for %ws log\n",
  201. LogFileName->Buffer);
  202. Status = STATUS_NO_MEMORY;
  203. goto ErrorExit;
  204. }
  205. pLogFile->LogModuleName->MaximumLength = ModuleName->MaximumLength;
  206. pLogFile->LogModuleName->Buffer =
  207. (LPWSTR)(pLogFile->LogModuleName + 1);
  208. RtlCopyUnicodeString(pLogFile->LogModuleName, ModuleName);
  209. InitializeListHead (&pLogFile->Notifiees);
  210. pLogFile->NextClearMaxFileSize = pLogFile->ConfigMaxFileSize;
  211. Status = ElfpInitResource(&pLogFile->Resource);
  212. if (!NT_SUCCESS(Status))
  213. {
  214. ELF_LOG1(ERROR,
  215. "SetupDataStruct: Unable to init resource for %ws log\n",
  216. LogFileName->Buffer);
  217. goto ErrorExit;
  218. }
  219. LinkLogFile ( pLogFile ); // Link it in
  220. Progress |= LOGFILE_LINKED;
  221. } // endif (pLogfile == NULL)
  222. //--------------------------------------
  223. // ADD THE MODULE TO THE LOG MODULE LIST
  224. //--------------------------------------
  225. // Set up the module data structure for the default (which is
  226. // the same as the logfile keyname).
  227. //
  228. pLogFile->RefCount++;
  229. pModule->LogFile = pLogFile;
  230. pModule->ModuleName = (LPWSTR) ModuleName->Buffer;
  231. Status = RtlUnicodeStringToAnsiString (
  232. &ModuleNameA,
  233. ModuleName,
  234. TRUE);
  235. if (!NT_SUCCESS(Status))
  236. {
  237. ELF_LOG2(ERROR,
  238. "SetupDataStruct: Unable to convert module name %ws to Ansi %#x\n",
  239. ModuleName->Buffer,
  240. Status);
  241. pLogFile->RefCount--;
  242. goto ErrorExit;
  243. }
  244. //
  245. // Link the new module in.
  246. //
  247. LinkLogModule(pModule, &ModuleNameA);
  248. RtlFreeAnsiString (&ModuleNameA);
  249. Progress |= MODULE_LINKED;
  250. //
  251. // Open up the file and map it to memory. Impersonate the
  252. // caller so we can use UNC names
  253. //
  254. if (LogType == ElfBackupLog)
  255. {
  256. Status = RpcImpersonateClient(NULL);
  257. if (Status == RPC_S_OK)
  258. {
  259. Status = ElfOpenLogFile (pLogFile, LogType);
  260. RpcRevertToSelf();
  261. }
  262. else
  263. {
  264. ELF_LOG1(ERROR,
  265. "SetupDataStruct: RpcImpersonateClient failed %#x\n",
  266. Status);
  267. }
  268. }
  269. else
  270. {
  271. Status = ElfOpenLogFile (pLogFile, LogType);
  272. }
  273. if (!NT_SUCCESS(Status))
  274. {
  275. ELF_LOG3(ERROR,
  276. "SetupDataStruct: Couldn't open %ws for module %ws %#x\n",
  277. LogFileName->Buffer,
  278. ModuleName->Buffer,
  279. Status);
  280. if (LogType != ElfBackupLog)
  281. {
  282. ElfpCreateQueuedAlert(ALERT_ELF_LogFileNotOpened,
  283. 1,
  284. &(ModuleName->Buffer));
  285. }
  286. pLogFile->RefCount--;
  287. goto ErrorExit;
  288. }
  289. Progress |= LOGFILE_OPENED;
  290. //
  291. // If this is the application module, remember the pointer
  292. // to use if a module doesn't have an entry in the registry
  293. //
  294. if (!_wcsicmp(ModuleName->Buffer, ELF_DEFAULT_MODULE_NAME))
  295. {
  296. OldDefaultLogModule = ElfDefaultLogModule;
  297. ElfDefaultLogModule = pModule;
  298. }
  299. //
  300. // Create the security descriptor for this logfile. Only
  301. // the system and security modules are secured against
  302. // reads and writes by world. Also, make sure we never
  303. // pop up a "log full" message for the Security log -- this
  304. // would be a C2 violation.
  305. //
  306. if (!_wcsicmp(ModuleName->Buffer, ELF_SYSTEM_MODULE_NAME))
  307. {
  308. Type = ELF_LOGFILE_SYSTEM;
  309. }
  310. else if (!_wcsicmp(ModuleName->Buffer, ELF_SECURITY_MODULE_NAME))
  311. {
  312. Type = ELF_LOGFILE_SECURITY;
  313. pLogFile->logpLogPopup = LOGPOPUP_NEVER_SHOW;
  314. }
  315. else
  316. {
  317. Type = ELF_LOGFILE_APPLICATION;
  318. }
  319. //
  320. // Create a Security Descriptor for this Logfile
  321. // (RtlDeleteSecurityObject() can be used to free
  322. // pLogFile->Sd).
  323. //
  324. Status = ElfpCreateLogFileObject(pLogFile, Type, GuestAccessRestriction);
  325. if (!NT_SUCCESS(Status))
  326. {
  327. ELF_LOG2(ERROR,
  328. "SetupDataStruct: Unable to create SD for log %ws %#x\n",
  329. ModuleName->Buffer,
  330. Status);
  331. pLogFile->RefCount--;
  332. goto ErrorExit;
  333. }
  334. //
  335. // Now that we've added the default module name, see if there are any
  336. // modules configured to log to this file, and if so, create the module
  337. // structures for them.
  338. //
  339. SetUpModules(hLogFile, pLogFile, FALSE);
  340. return STATUS_SUCCESS;
  341. ErrorExit:
  342. if (Progress & LOGFILE_OPENED)
  343. {
  344. ElfpCloseLogFile(pLogFile, ELF_LOG_CLOSE_BACKUP);
  345. }
  346. if (Progress & MODULE_LINKED)
  347. {
  348. UnlinkLogModule(pModule);
  349. DeleteAtom(pModule->ModuleAtom);
  350. }
  351. if (bAllocatedLogInfo)
  352. {
  353. if (Progress & LOGFILE_LINKED)
  354. {
  355. UnlinkLogFile(pLogFile);
  356. RtlDeleteResource (&pLogFile->Resource);
  357. }
  358. ElfpFreeBuffer(pLogFile->LogModuleName);
  359. ElfpFreeBuffer(SavedBackupFileName);
  360. ElfpFreeBuffer(pLogFile);
  361. }
  362. ElfpFreeBuffer(pModule);
  363. if (OldDefaultLogModule != NULL)
  364. {
  365. ElfDefaultLogModule = OldDefaultLogModule;
  366. }
  367. return Status;
  368. }
  369. NTSTATUS
  370. SetUpModules(
  371. HANDLE hLogFile,
  372. PLOGFILE pLogFile,
  373. BOOLEAN bAllowDupes
  374. )
  375. /*++
  376. Routine Description:
  377. This routine sets up the information for all modules for a logfile.
  378. The subkeys under a logfile in the eventlog portion of the registry
  379. are enumerated. For each unique subkey, a LOGMODULE structure is
  380. created. Each new structures is added to a linked list
  381. of modules for that logfile.
  382. If there was one or more unique subkeys, meaning the list has changed
  383. since we last looked, then we go through the entire linked list of
  384. log modules, and create a MULTI_SZ list of all the modules. This list
  385. is stored in the Sources value for that logfile for the event viewer
  386. to use.
  387. NOTE: A module is never un-linked from the linked list of log modules
  388. even if the registry subkey for it is removed. This should probably
  389. be done sometime. It would make the eventlog more robust.
  390. Arguments:
  391. hLogFile - Registry key for the Log File node
  392. pLogFile - pointer to the log file structure
  393. bAllowDupes - If true, it's ok to already have a module with the same
  394. name (used when processing change notify of registry)
  395. Return Value:
  396. NTSTATUS - If unsuccessful, it is not a fatal error.
  397. Even if this status is unsuccessful, me may have been able
  398. to store some of the new subkeys in the LogModule list. Also, we
  399. may have been able to update the Sources MULTI_SZ list.
  400. --*/
  401. {
  402. NTSTATUS Status = STATUS_SUCCESS;
  403. BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
  404. PKEY_NODE_INFORMATION KeyBuffer = (PKEY_NODE_INFORMATION) Buffer;
  405. ULONG ActualSize;
  406. PWCHAR SubKeyString;
  407. UNICODE_STRING NewModule;
  408. ANSI_STRING ModuleNameA;
  409. PLOGMODULE pModule;
  410. ULONG Index = 0;
  411. ATOM Atom;
  412. PWCHAR pList;
  413. DWORD ListLength = 0;
  414. UNICODE_STRING ListName;
  415. BOOLEAN ListChanged = FALSE;
  416. PLIST_ENTRY pListEntry;
  417. //
  418. // Create the module structures for all modules under this logfile. We
  419. // don't actually need to open the key, since we don't use any information
  420. // stored there, it's existence is all we care about here. Any data is
  421. // used by the Event Viewer (or any viewing app). If this is used to
  422. // setup a backup file, hLogFile is NULL since there aren't any other
  423. // modules to map to this file.
  424. //
  425. while (NT_SUCCESS(Status) && hLogFile)
  426. {
  427. Status = NtEnumerateKey(hLogFile,
  428. Index++,
  429. KeyNodeInformation,
  430. KeyBuffer,
  431. ELF_MAX_REG_KEY_INFO_SIZE,
  432. &ActualSize);
  433. if (NT_SUCCESS(Status))
  434. {
  435. //
  436. // It turns out the Name isn't null terminated, so we need
  437. // to copy it somewhere and null terminate it before we use it
  438. //
  439. SubKeyString = ElfpAllocateBuffer(KeyBuffer->NameLength + sizeof(WCHAR));
  440. if (!SubKeyString)
  441. {
  442. return STATUS_NO_MEMORY;
  443. }
  444. memcpy(SubKeyString, KeyBuffer->Name, KeyBuffer->NameLength);
  445. SubKeyString[KeyBuffer->NameLength / sizeof(WCHAR)] = L'\0' ;
  446. //
  447. // Add the atom for this module name
  448. //
  449. RtlInitUnicodeString(&NewModule, SubKeyString);
  450. Status = RtlUnicodeStringToAnsiString (
  451. &ModuleNameA,
  452. &NewModule,
  453. TRUE);
  454. if (!NT_SUCCESS(Status))
  455. {
  456. //
  457. // We can't continue, so we will leave the modules
  458. // we've linked so far, and move on in an attempt to
  459. // create the Sources MULTI_SZ list.
  460. //
  461. ELF_LOG1(TRACE,
  462. "SetUpModules: Unable to convert name for module %ws\n",
  463. SubKeyString);
  464. ElfpFreeBuffer(SubKeyString);
  465. break;
  466. }
  467. Atom = FindAtomA(ModuleNameA.Buffer);
  468. //
  469. // Make sure we've not already added one by this name
  470. //
  471. if (FindModuleStrucFromAtom(Atom))
  472. {
  473. //
  474. // We've already encountered a module by this name. If
  475. // this is init time, it's a configuration error. Report
  476. // it and move on. If we're processing a change notify
  477. // from the registry, this is ok (it means we're rescanning
  478. // an existing Event Source for an existing log).
  479. //
  480. if (!bAllowDupes)
  481. {
  482. ELF_LOG1(ERROR,
  483. "SetUpModules: Module %ws exists in two log files.\n",
  484. SubKeyString);
  485. }
  486. RtlFreeAnsiString(&ModuleNameA);
  487. ElfpFreeBuffer(SubKeyString);
  488. continue;
  489. }
  490. ListChanged = TRUE;
  491. pModule = ElfpAllocateBuffer (sizeof (LOGMODULE) );
  492. if (!pModule)
  493. {
  494. ELF_LOG1(ERROR,
  495. "SetUpModules: Unable to allocate structure for module %ws\n",
  496. SubKeyString);
  497. RtlFreeAnsiString (&ModuleNameA);
  498. ElfpFreeBuffer(SubKeyString);
  499. return(STATUS_NO_MEMORY);
  500. }
  501. //
  502. // Set up a module data structure for this module
  503. //
  504. pModule->LogFile = pLogFile;
  505. pModule->ModuleName = SubKeyString;
  506. //
  507. // Link the new module in.
  508. //
  509. LinkLogModule(pModule, &ModuleNameA);
  510. ELF_LOG1(TRACE,
  511. "SetUpModules: Module %ws successfully created/linked\n",
  512. SubKeyString);
  513. RtlFreeAnsiString (&ModuleNameA);
  514. }
  515. }
  516. if (Status == STATUS_NO_MORE_ENTRIES)
  517. {
  518. //
  519. // It's not required that there are configured modules for a log
  520. // file.
  521. //
  522. Status = STATUS_SUCCESS;
  523. }
  524. //
  525. // If the list has changed, or if we've been called during init, and not
  526. // as the result of a changenotify on the registry (bAllowDupes == FALSE)
  527. // then create the sources key
  528. //
  529. if (hLogFile && (ListChanged || !bAllowDupes))
  530. {
  531. //
  532. // Now create a MULTI_SZ entry with all the module names for eventvwr
  533. //
  534. // STEP 1: Calculate amount of storage needed by running thru the
  535. // module list, finding any module that uses this log file.
  536. //
  537. pListEntry = LogModuleHead.Flink;
  538. while (pListEntry != &LogModuleHead)
  539. {
  540. pModule = CONTAINING_RECORD (pListEntry, LOGMODULE, ModuleList);
  541. if (pModule->LogFile == pLogFile)
  542. {
  543. //
  544. // This one is for the log we're working on, get the
  545. // size of its name.
  546. //
  547. ListLength += WCSSIZE(pModule->ModuleName);
  548. ELF_LOG2(MODULES,
  549. "SetUpModules: Adding module %ws to list for %ws log\n",
  550. pModule->ModuleName,
  551. pLogFile->LogFileName->Buffer);
  552. }
  553. pListEntry = pModule->ModuleList.Flink;
  554. }
  555. //
  556. // STEP 2: Allocate storage for the MULTI_SZ.
  557. //
  558. pList = ElfpAllocateBuffer(ListLength + sizeof(WCHAR));
  559. //
  560. // If I can't allocate the list, just press on
  561. //
  562. if (pList)
  563. {
  564. //
  565. // STEP 3: Copy all the module names for this logfile into
  566. // the MULTI_SZ string.
  567. //
  568. SubKeyString = pList; // Save this away
  569. pListEntry = LogModuleHead.Flink;
  570. while (pListEntry != &LogModuleHead)
  571. {
  572. pModule = CONTAINING_RECORD(pListEntry,
  573. LOGMODULE,
  574. ModuleList);
  575. if (pModule->LogFile == pLogFile)
  576. {
  577. //
  578. // This one is for the log we're working on, put it in the list
  579. //
  580. wcscpy(pList, pModule->ModuleName);
  581. pList += wcslen(pModule->ModuleName);
  582. pList++;
  583. }
  584. pListEntry = pModule->ModuleList.Flink;
  585. }
  586. *pList = L'\0'; // The terminating NULL
  587. RtlInitUnicodeString(&ListName, L"Sources");
  588. Status = NtSetValueKey(hLogFile,
  589. &ListName,
  590. 0,
  591. REG_MULTI_SZ,
  592. SubKeyString,
  593. ListLength + sizeof(WCHAR));
  594. ElfpFreeBuffer(SubKeyString);
  595. }
  596. else
  597. {
  598. ELF_LOG1(ERROR,
  599. "SetUpModules: Unable to allocate list for %ws log\n",
  600. pLogFile->LogFileName->Buffer);
  601. }
  602. }
  603. return Status;
  604. }
  605. NTSTATUS
  606. ElfSetUpConfigDataStructs(
  607. VOID
  608. )
  609. /*++
  610. Routine Description:
  611. This routine sets up all the necessary data structures for the eventlog
  612. service. It enumerates the keys in the Logfiles registry node to
  613. determine what to setup.
  614. Arguments:
  615. NONE
  616. Return Value:
  617. NONE
  618. Note:
  619. --*/
  620. {
  621. NTSTATUS Status = STATUS_SUCCESS;
  622. HANDLE hLogFile;
  623. OBJECT_ATTRIBUTES ObjectAttributes;
  624. UNICODE_STRING SubKeyName;
  625. PUNICODE_STRING pLogFileName = NULL;
  626. PUNICODE_STRING pModuleName = NULL;
  627. UNICODE_STRING EventlogModuleName;
  628. UNICODE_STRING EventlogSecModuleName;
  629. ULONG Index = 0;
  630. BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
  631. PKEY_NODE_INFORMATION KeyBuffer = (PKEY_NODE_INFORMATION) Buffer;
  632. ULONG ActualSize;
  633. LOG_FILE_INFO LogFileInfo;
  634. PWCHAR SubKeyString;
  635. LPWSTR ModuleName;
  636. ELF_LOG0(TRACE,
  637. "ElfSetUpConfigDataStructs: Entering\n");
  638. //
  639. // Initialize the Atom table whose size is the maximum number of
  640. // module structures possible, i.e. ELF_MAX_LOG_MODULES.
  641. //
  642. if (!InitAtomTable(ELF_MAX_LOG_MODULES))
  643. {
  644. return STATUS_UNSUCCESSFUL;
  645. }
  646. //
  647. // Get a handle to the Logfiles subkey. If it doesn't exist, just use
  648. // the hard-coded defaults.
  649. //
  650. if (hEventLogNode)
  651. {
  652. //
  653. // Loop thru the subkeys under Eventlog and set up each logfile
  654. //
  655. while (NT_SUCCESS(Status))
  656. {
  657. Status = NtEnumerateKey(hEventLogNode,
  658. Index++,
  659. KeyNodeInformation,
  660. KeyBuffer,
  661. ELF_MAX_REG_KEY_INFO_SIZE,
  662. &ActualSize);
  663. if (NT_SUCCESS(Status))
  664. {
  665. //
  666. // It turns out the Name isn't null terminated, so we need
  667. // to copy it somewhere and null terminate it before we use it
  668. //
  669. SubKeyString = ElfpAllocateBuffer(KeyBuffer->NameLength + sizeof(WCHAR));
  670. if (!SubKeyString)
  671. {
  672. return STATUS_NO_MEMORY;
  673. }
  674. memcpy(SubKeyString, KeyBuffer->Name, KeyBuffer->NameLength);
  675. SubKeyString[KeyBuffer->NameLength / sizeof(WCHAR)] = L'\0';
  676. //
  677. // Open the node for this logfile and extract the information
  678. // required by SetupDataStruct, and then call it.
  679. //
  680. RtlInitUnicodeString(&SubKeyName, SubKeyString);
  681. InitializeObjectAttributes(&ObjectAttributes,
  682. &SubKeyName,
  683. OBJ_CASE_INSENSITIVE,
  684. hEventLogNode,
  685. NULL);
  686. Status = NtOpenKey(&hLogFile,
  687. KEY_READ | KEY_SET_VALUE,
  688. &ObjectAttributes);
  689. if (!NT_SUCCESS(Status))
  690. {
  691. //
  692. // Unclear how this could happen since I just enum'ed
  693. // it, but if I can't open it, I just pretend like it
  694. // wasn't there to begin with.
  695. //
  696. ELF_LOG1(TRACE,
  697. "ElfSetUpConfigDataStructs: Unable to open key for %ws log\n",
  698. SubKeyName);
  699. ElfpFreeBuffer(SubKeyString);
  700. Status = STATUS_SUCCESS; // so we don't terminate the loop
  701. continue;
  702. }
  703. //
  704. // Get the information from the registry. Note that we have to
  705. // initialize the "log full" popup policy before doing so since
  706. // ReadRegistryInfo will compare the value found in the registry
  707. // (if there is one) to the current value.
  708. //
  709. LogFileInfo.logpLogPopup = IS_WORKSTATION() ? LOGPOPUP_NEVER_SHOW :
  710. LOGPOPUP_CLEARED;
  711. Status = ReadRegistryInfo(hLogFile,
  712. &SubKeyName,
  713. &LogFileInfo);
  714. if (NT_SUCCESS(Status))
  715. {
  716. //
  717. // Now set up the actual data structures. Failures are
  718. // dealt with in the routine. Note that the check for
  719. // the security log (i.e., for LOGPOPUP_NEVER_SHOW) is
  720. // made in SetUpDataStruct
  721. //
  722. SetUpDataStruct(LogFileInfo.LogFileName,
  723. LogFileInfo.MaxFileSize,
  724. LogFileInfo.Retention,
  725. LogFileInfo.GuestAccessRestriction,
  726. &SubKeyName,
  727. hLogFile,
  728. ElfNormalLog,
  729. LogFileInfo.logpLogPopup,
  730. LogFileInfo.dwAutoBackup);
  731. NtClose(hLogFile);
  732. }
  733. else
  734. {
  735. ELF_LOG1(ERROR,
  736. "ElfSetUpConfigdataStructs: ReadRegistryInfo failed %#x\n",
  737. Status);
  738. }
  739. }
  740. }
  741. } // if (hEventLogNode)
  742. else
  743. {
  744. LOGPOPUP logpLogPopup = IS_WORKSTATION() ? LOGPOPUP_NEVER_SHOW :
  745. LOGPOPUP_CLEARED;
  746. //
  747. // The information doesn't exist in the registry, set up the
  748. // three default logs.
  749. //
  750. pLogFileName = ElfpAllocateBuffer(sizeof(UNICODE_STRING));
  751. pModuleName = ElfpAllocateBuffer(sizeof(UNICODE_STRING));
  752. if (!pLogFileName || !pModuleName)
  753. {
  754. ElfpFreeBuffer(pLogFileName);
  755. ElfpFreeBuffer(pModuleName);
  756. return STATUS_NO_MEMORY;
  757. }
  758. //
  759. // Application log
  760. //
  761. RtlInitUnicodeString(pLogFileName, ELF_APPLICATION_DEFAULT_LOG_FILE);
  762. RtlInitUnicodeString(pModuleName, ELF_DEFAULT_MODULE_NAME);
  763. //
  764. // On success, don't free pModuleName as the pointer to it
  765. // is stored away in the LogFile struct
  766. //
  767. Status = SetUpDataStruct(pLogFileName,
  768. ELF_DEFAULT_MAX_FILE_SIZE,
  769. ELF_DEFAULT_RETENTION_PERIOD,
  770. ELF_GUEST_ACCESS_UNRESTRICTED,
  771. pModuleName,
  772. NULL,
  773. ElfNormalLog,
  774. logpLogPopup,
  775. ELF_DEFAULT_AUTOBACKUP);
  776. ElfpFreeBuffer(pLogFileName);
  777. pLogFileName = NULL;
  778. if (!NT_SUCCESS(Status))
  779. {
  780. ELF_LOG1(ERROR,
  781. "ElfSetUpConfigDatastructs: Unable to set up %ws log\n",
  782. ELF_DEFAULT_MODULE_NAME);
  783. ElfpFreeBuffer(pModuleName);
  784. pModuleName = NULL;
  785. }
  786. pLogFileName = ElfpAllocateBuffer(sizeof(UNICODE_STRING));
  787. pModuleName = ElfpAllocateBuffer(sizeof(UNICODE_STRING));
  788. if (!pLogFileName || !pModuleName)
  789. {
  790. ElfpFreeBuffer(pLogFileName);
  791. ElfpFreeBuffer(pModuleName);
  792. return(STATUS_NO_MEMORY);
  793. }
  794. //
  795. // System log
  796. //
  797. RtlInitUnicodeString(pLogFileName, ELF_SYSTEM_DEFAULT_LOG_FILE);
  798. RtlInitUnicodeString(pModuleName, ELF_SYSTEM_MODULE_NAME);
  799. Status = SetUpDataStruct(pLogFileName,
  800. ELF_DEFAULT_MAX_FILE_SIZE,
  801. ELF_DEFAULT_RETENTION_PERIOD,
  802. ELF_GUEST_ACCESS_UNRESTRICTED,
  803. pModuleName,
  804. NULL,
  805. ElfNormalLog,
  806. logpLogPopup,
  807. ELF_DEFAULT_AUTOBACKUP);
  808. ElfpFreeBuffer(pLogFileName);
  809. pLogFileName = NULL;
  810. if (!NT_SUCCESS(Status))
  811. {
  812. ELF_LOG1(ERROR,
  813. "ElfSetUpConfigDatastructs: Unable to set up %ws log\n",
  814. ELF_SYSTEM_MODULE_NAME);
  815. ElfpFreeBuffer(pModuleName);
  816. pModuleName = NULL;
  817. }
  818. pLogFileName = ElfpAllocateBuffer(sizeof(UNICODE_STRING));
  819. pModuleName = ElfpAllocateBuffer(sizeof(UNICODE_STRING));
  820. if (!pLogFileName || !pModuleName)
  821. {
  822. ElfpFreeBuffer(pLogFileName);
  823. ElfpFreeBuffer(pModuleName);
  824. return(STATUS_NO_MEMORY);
  825. }
  826. //
  827. // Security log
  828. //
  829. RtlInitUnicodeString(pLogFileName, ELF_SECURITY_DEFAULT_LOG_FILE);
  830. RtlInitUnicodeString(pModuleName, ELF_SECURITY_MODULE_NAME);
  831. Status = SetUpDataStruct(pLogFileName,
  832. ELF_DEFAULT_MAX_FILE_SIZE,
  833. ELF_DEFAULT_RETENTION_PERIOD,
  834. ELF_GUEST_ACCESS_UNRESTRICTED,
  835. pModuleName,
  836. NULL,
  837. ElfNormalLog,
  838. LOGPOPUP_NEVER_SHOW,
  839. ELF_DEFAULT_AUTOBACKUP); // Never popup for the security log
  840. ElfpFreeBuffer(pLogFileName);
  841. pLogFileName = NULL;
  842. if (!NT_SUCCESS(Status))
  843. {
  844. ELF_LOG1(ERROR,
  845. "ElfSetUpConfigDatastructs: Unable to set up %ws log\n",
  846. ELF_SECURITY_MODULE_NAME);
  847. ElfpFreeBuffer(pModuleName);
  848. pModuleName = NULL;
  849. }
  850. Status = STATUS_SUCCESS;
  851. }
  852. //
  853. // If we just ran out of keys, that's OK (unless there weren't any at all)
  854. //
  855. if (Status == STATUS_NO_MORE_ENTRIES && Index != 1)
  856. {
  857. Status = STATUS_SUCCESS;
  858. }
  859. if (NT_SUCCESS(Status))
  860. {
  861. //
  862. // Make sure we created the Application log file, since it is the
  863. // default. If it wasn't created, use the first module created
  864. // (this is at the tail of the list since I insert them at the
  865. // head). If this happens, send an alert to the admin.
  866. //
  867. if (!ElfDefaultLogModule)
  868. {
  869. ELF_LOG0(ERROR,
  870. "ElfSetUpConfigDatastructs: No Application module -- creating default\n");
  871. if (IsListEmpty(&LogModuleHead))
  872. {
  873. //
  874. // No logs were created, might as well shut down
  875. //
  876. ELF_LOG0(ERROR,
  877. "ElfSetUpConfigDatastructs: No logs created -- exiting\n");
  878. return STATUS_EVENTLOG_CANT_START;
  879. }
  880. ElfDefaultLogModule = CONTAINING_RECORD(LogModuleHead.Blink,
  881. LOGMODULE,
  882. ModuleList);
  883. ModuleName = ELF_DEFAULT_MODULE_NAME;
  884. ELF_LOG2(ERROR,
  885. "ElfSetUpConfigDatastructs: Using file/default %ws/%ws as default log\n",
  886. ElfDefaultLogModule->LogFile->LogFileName->Buffer,
  887. ElfDefaultLogModule->LogFile->LogModuleName->Buffer);
  888. ElfpCreateQueuedAlert(ALERT_ELF_DefaultLogCorrupt,
  889. 1,
  890. &(ElfDefaultLogModule->LogFile->LogModuleName->Buffer));
  891. }
  892. //
  893. // Now get the Module for the Eventlog service to use. GetModuleStruc
  894. // always succeeds, returning the default log if the requested one
  895. // isn't configured.
  896. //
  897. RtlInitUnicodeString(&EventlogModuleName, L"eventlog");
  898. ElfModule = GetModuleStruc(&EventlogModuleName);
  899. RtlInitUnicodeString(&EventlogSecModuleName, L"SECURITY");
  900. ElfSecModule = GetModuleStruc(&EventlogSecModuleName);
  901. }
  902. return Status;
  903. }
  904. VOID
  905. ElfWriteTimeStamp(
  906. TIMESTAMPEVENT EventType,
  907. BOOLEAN CheckPreviousStamp
  908. )
  909. /*++
  910. Routine Description:
  911. This routine writes a time stamp in the form of a systemtime structure
  912. to the registry which is then used to extract reliability data.
  913. Arguments:
  914. EventType - Indicates what type of event we are logging
  915. CheckPreviousStamp - Whether we should check for the existance of a previous
  916. time stamp which indicates a prior system crash.
  917. Return Value:
  918. NONE
  919. Note:
  920. --*/
  921. {
  922. SYSTEMTIME stCurrentUTCTime;
  923. SYSTEMTIME stPreviousUTCTime;
  924. SYSTEMTIME stPreviousLocalTime;
  925. DWORD dwDirtyFlag = 1;
  926. HKEY hKey;
  927. LONG rc;
  928. DWORD ValueSize;
  929. ULONG Interval = DEFAULT_INTERVAL;
  930. ULONG wchars;
  931. LPWSTR DateTimeBuffer[2];
  932. rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  933. REGSTR_PATH_RELIABILITY,
  934. 0,
  935. NULL,
  936. REG_OPTION_NON_VOLATILE,
  937. KEY_ALL_ACCESS,
  938. NULL,
  939. &hKey,
  940. NULL);
  941. if (rc != ERROR_SUCCESS)
  942. {
  943. return;
  944. }
  945. if (EventType == EVENT_NormalShutdown)
  946. {
  947. //
  948. // Delete the time stamp registry value, this is how we indicate a clean shutdown
  949. //
  950. RegDeleteValue(hKey, REGSTR_VAL_LASTALIVESTAMP);
  951. RegFlushKey(hKey);
  952. RegCloseKey(hKey);
  953. return;
  954. }
  955. //
  956. // Get the current UTC time
  957. //
  958. GetSystemTime(&stCurrentUTCTime);
  959. if (CheckPreviousStamp)
  960. {
  961. ValueSize = sizeof(SYSTEMTIME);
  962. rc = RegQueryValueEx(hKey,
  963. REGSTR_VAL_LASTALIVESTAMP,
  964. 0,
  965. NULL,
  966. (PUCHAR) &stPreviousUTCTime,
  967. &ValueSize);
  968. //
  969. // If we can successfully read a systemtime structure it indicates
  970. // that the previous shutdown was abnormal, i.e. we didn't execute
  971. // or normal shutdown cleanup code.
  972. //
  973. //
  974. // Format the time and date of the crash time stamp
  975. // appropriately for the locale and log a #6008 event
  976. //
  977. if ((rc == ERROR_SUCCESS) && (ValueSize == sizeof(SYSTEMTIME)))
  978. {
  979. SYSTEMTIME lpData[2]; // Data for the event
  980. if (!SystemTimeToTzSpecificLocalTime(NULL,
  981. &stPreviousUTCTime,
  982. &stPreviousLocalTime))
  983. {
  984. //
  985. // Couldn't convert to the active time zone -- use UTC
  986. //
  987. stPreviousLocalTime = stPreviousUTCTime;
  988. }
  989. //
  990. // Write the local time and the UTC time for the "last alive"
  991. // timestamp since NT4SP5 shipped with only the local time
  992. // as the event data. This allows tools that work on NT4SP5
  993. // to continue working on NT5.
  994. //
  995. lpData[0] = stPreviousLocalTime;
  996. lpData[1] = stPreviousUTCTime;
  997. wchars = GetTimeFormat(LOCALE_SYSTEM_DEFAULT,
  998. 0,
  999. &stPreviousLocalTime,
  1000. NULL,
  1001. NULL,
  1002. 0);
  1003. DateTimeBuffer[0] = ElfpAllocateBuffer(wchars * sizeof(WCHAR));
  1004. if (DateTimeBuffer[0])
  1005. {
  1006. GetTimeFormat(LOCALE_SYSTEM_DEFAULT,
  1007. 0,
  1008. &stPreviousLocalTime,
  1009. NULL,
  1010. DateTimeBuffer[0],
  1011. wchars);
  1012. wchars = GetDateFormat(LOCALE_SYSTEM_DEFAULT,
  1013. 0,
  1014. &stPreviousLocalTime,
  1015. NULL,
  1016. NULL,
  1017. 0);
  1018. DateTimeBuffer[1] = ElfpAllocateBuffer(wchars * sizeof(WCHAR));
  1019. if (DateTimeBuffer[1])
  1020. {
  1021. GetDateFormat(LOCALE_SYSTEM_DEFAULT,
  1022. 0,
  1023. &stPreviousLocalTime,
  1024. NULL,
  1025. DateTimeBuffer[1],
  1026. wchars);
  1027. ElfpCreateElfEvent(
  1028. EVENT_EventlogAbnormalShutdown,
  1029. EVENTLOG_ERROR_TYPE,
  1030. 0, // EventCategory
  1031. 2, // NumberOfStrings
  1032. DateTimeBuffer, // Strings
  1033. lpData, // "Last alive" times
  1034. 2 * sizeof(SYSTEMTIME), // Datalength
  1035. 0,
  1036. FALSE); // flags
  1037. ElfpFreeBuffer(DateTimeBuffer[1]);
  1038. RegSetValueEx(hKey,
  1039. L"DirtyShutDown",
  1040. 0,
  1041. REG_DWORD,
  1042. (PUCHAR) &dwDirtyFlag,
  1043. sizeof(DWORD));
  1044. }
  1045. ElfpFreeBuffer(DateTimeBuffer[0]);
  1046. }
  1047. }
  1048. }
  1049. //
  1050. // Set the current time stamp
  1051. //
  1052. RegSetValueEx(hKey,
  1053. REGSTR_VAL_LASTALIVESTAMP,
  1054. 0,
  1055. REG_BINARY,
  1056. (PUCHAR) &stCurrentUTCTime,
  1057. sizeof(SYSTEMTIME));
  1058. RegFlushKey (hKey);
  1059. RegCloseKey (hKey);
  1060. }
  1061. VOID
  1062. ElfWriteProductInfoEvent (
  1063. VOID
  1064. )
  1065. /*++
  1066. Routine Description:
  1067. This function writes an event #6009 which includes the OS version, build #,
  1068. service pack level, MP/UP, and Free/Checked.
  1069. Arguments:
  1070. NONE
  1071. Return Value:
  1072. NONE
  1073. Note:
  1074. --*/
  1075. {
  1076. #define NUM_INFO_VALUES 4 //EVENT_EventLogProductInfo requires 4 parameters
  1077. #define NUM_VERSION_SIZE 10 //Digits in a DWORD
  1078. NTSTATUS Status = STATUS_SUCCESS;
  1079. HKEY hKey = NULL;
  1080. ULONG ValueSize = 0;
  1081. LPWSTR NullString = L"";
  1082. LPWSTR StringBuffers[NUM_INFO_VALUES] = {NULL, NULL, NULL, NULL};
  1083. OSVERSIONINFOEX OsVersion;
  1084. WCHAR wszTemp[NUM_VERSION_SIZE];
  1085. UINT i;
  1086. OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1087. if( !GetVersionEx( (LPOSVERSIONINFO)&OsVersion ) )
  1088. {
  1089. return;
  1090. }
  1091. //Allocate storage
  1092. //Buffer 0 holds the version number in the format of 5.xx.
  1093. StringBuffers[0] = ElfpAllocateBuffer( (2*NUM_VERSION_SIZE + 2) * sizeof(WCHAR) );
  1094. //Buffer 1 holds the build number
  1095. StringBuffers[1] = ElfpAllocateBuffer( (NUM_VERSION_SIZE) * sizeof(WCHAR) );
  1096. //Buffer 2 holds the service pack
  1097. StringBuffers[2] = ElfpAllocateBuffer( sizeof(OsVersion.szCSDVersion) );
  1098. if( StringBuffers[0] == NULL ||
  1099. StringBuffers[1] == NULL ||
  1100. StringBuffers[2] == NULL )
  1101. {
  1102. goto ErrorExit;
  1103. }
  1104. //
  1105. //Add major version
  1106. //
  1107. _ltow (
  1108. OsVersion.dwMajorVersion,
  1109. wszTemp,
  1110. 10
  1111. );
  1112. wcscpy( StringBuffers[0], wszTemp );
  1113. wcscat( StringBuffers[0], L"." );
  1114. //
  1115. //Add minor version
  1116. //
  1117. _ltow (
  1118. OsVersion.dwMinorVersion,
  1119. wszTemp,
  1120. 10
  1121. );
  1122. if( OsVersion.dwMinorVersion < 10 )
  1123. {
  1124. wcscat( StringBuffers[0], L"0" );
  1125. }
  1126. wcscat( StringBuffers[0], wszTemp );
  1127. wcscat( StringBuffers[0], L"." );
  1128. //
  1129. //Get build number
  1130. //
  1131. _ltow (
  1132. OsVersion.dwBuildNumber,
  1133. wszTemp,
  1134. 10
  1135. );
  1136. wcscpy( StringBuffers[1], wszTemp );
  1137. //Get service pack info
  1138. wcscpy( StringBuffers[2], OsVersion.szCSDVersion );
  1139. //
  1140. // Get OS type (uniprocessor or multiprocessor chk or free)
  1141. // Open HKLM\Software\Microsoft\Windows NT\CurrentVersion
  1142. //
  1143. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1144. REGSTR_PATH_NT_CURRENTVERSION,
  1145. 0,
  1146. KEY_ALL_ACCESS,
  1147. &hKey)
  1148. != ERROR_SUCCESS)
  1149. {
  1150. goto ErrorExit;
  1151. }
  1152. //
  1153. // For each of the registry values, query for the string size, allocate storage,
  1154. // and query the actual value
  1155. //
  1156. if ((RegQueryValueEx (hKey,
  1157. REGSTR_VAL_CURRENT_TYPE,
  1158. 0,
  1159. NULL,
  1160. NULL,
  1161. &ValueSize)
  1162. == ERROR_SUCCESS)
  1163. &&
  1164. ValueSize != 0)
  1165. {
  1166. StringBuffers[3] = ElfpAllocateBuffer(ValueSize);
  1167. if (StringBuffers[3] != NULL)
  1168. {
  1169. RegQueryValueEx(hKey,
  1170. REGSTR_VAL_CURRENT_TYPE,
  1171. 0,
  1172. NULL,
  1173. (PUCHAR) StringBuffers[3],
  1174. &ValueSize);
  1175. ValueSize = 0;
  1176. }
  1177. }
  1178. else
  1179. {
  1180. StringBuffers[3] = NullString;
  1181. }
  1182. ElfpCreateElfEvent(
  1183. EVENT_EventLogProductInfo,
  1184. EVENTLOG_INFORMATION_TYPE,
  1185. 0, // EventCategory
  1186. NUM_INFO_VALUES, // NumberOfStrings
  1187. StringBuffers, // Strings
  1188. NULL, // EventData
  1189. 0, // Datalength
  1190. 0,
  1191. FALSE); // flags
  1192. ErrorExit:
  1193. for (i = 0; i < NUM_INFO_VALUES-1; i++)
  1194. {
  1195. if (StringBuffers[i] != NULL && StringBuffers[i] != NullString)
  1196. {
  1197. ElfpFreeBuffer(StringBuffers[i]);
  1198. }
  1199. }
  1200. if( hKey != NULL )
  1201. {
  1202. RegCloseKey (hKey);
  1203. }
  1204. #undef NUM_INFO_VALUES
  1205. #undef NUM_VERSION_SIZE
  1206. }
  1207. VOID
  1208. TimeStampProc(
  1209. PVOID Interval,
  1210. BOOLEAN fWaitStatus
  1211. )
  1212. {
  1213. NTSTATUS ntStatus;
  1214. HANDLE hWaitHandle;
  1215. ULONG ValueSize;
  1216. HKEY hKey;
  1217. ULONG NewInterval;
  1218. ULONG rc;
  1219. //
  1220. // Deregister the wait (note that we must do this even
  1221. // if the WT_EXECUTEONLYONCE flag is set)
  1222. //
  1223. ntStatus = RtlDeregisterWait(g_hTimestampWorkitem);
  1224. if (!NT_SUCCESS(ntStatus))
  1225. {
  1226. ELF_LOG1(ERROR,
  1227. "TimeStampProc: RtlDeregister wait failed %#x\n",
  1228. ntStatus);
  1229. }
  1230. if (fWaitStatus == FALSE)
  1231. {
  1232. //
  1233. // The event log service is stopping
  1234. //
  1235. return;
  1236. }
  1237. //
  1238. // Note: NewInterval is specified in minutes
  1239. //
  1240. NewInterval = (ULONG)((ULONG_PTR)Interval);
  1241. //
  1242. // The event timed out -- write a timestamp
  1243. //
  1244. ElfWriteTimeStamp (EVENT_AbNormalShutdown, FALSE);
  1245. //
  1246. // recheck the time stamp interval value
  1247. //
  1248. rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  1249. REGSTR_PATH_RELIABILITY,
  1250. 0,
  1251. NULL,
  1252. REG_OPTION_NON_VOLATILE,
  1253. KEY_ALL_ACCESS,
  1254. NULL,
  1255. &hKey,
  1256. NULL);
  1257. if ( rc == ERROR_SUCCESS )
  1258. {
  1259. ValueSize = sizeof (ULONG);
  1260. rc = RegQueryValueEx(hKey,
  1261. REGSTR_VAL_LASTALIVEINTERVAL,
  1262. 0,
  1263. NULL,
  1264. (PUCHAR) &NewInterval,
  1265. &ValueSize);
  1266. if ( rc != ERROR_SUCCESS )
  1267. {
  1268. //
  1269. // Couldn't get the value -- stop timestamping
  1270. //
  1271. return;
  1272. }
  1273. RegCloseKey (hKey);
  1274. }
  1275. if (NewInterval != 0)
  1276. {
  1277. //
  1278. // Reregister the wait
  1279. //
  1280. ntStatus = RtlRegisterWait(&g_hTimestampWorkitem,
  1281. g_hTimestampEvent,
  1282. TimeStampProc, // Callback
  1283. (PVOID) UlongToPtr(NewInterval), // Context
  1284. NewInterval * 60 * 1000, // Timeout, in ms
  1285. WT_EXECUTEONLYONCE);
  1286. }
  1287. if (!NT_SUCCESS(ntStatus))
  1288. {
  1289. ELF_LOG1(ERROR,
  1290. "TimeStampProc: RtlRegisterWait failed %#x\n",
  1291. ntStatus);
  1292. }
  1293. }
  1294. NTSTATUS EnsureComputerName(
  1295. )
  1296. /*++
  1297. Routine Description:
  1298. This routine ensures that the computer name.
  1299. Arguments:
  1300. Return Value:
  1301. status value, STATUS_SUCCESS if all is well.
  1302. --*/
  1303. {
  1304. NTSTATUS Status;
  1305. UNICODE_STRING ValueName;
  1306. ULONG ulActualSize;
  1307. WCHAR wComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1308. DWORD dwComputerNameLen = MAX_COMPUTERNAME_LENGTH + 1;
  1309. DWORD dwLen;
  1310. BOOL bRet;
  1311. BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
  1312. PKEY_VALUE_PARTIAL_INFORMATION ValueBuffer =
  1313. (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
  1314. RtlInitUnicodeString(&ValueName, VALUE_COMPUTERNAME);
  1315. // Determine if there is a String under the eventlog key that
  1316. // contains the current name.
  1317. Status = NtQueryValueKey(hEventLogNode,
  1318. &ValueName,
  1319. KeyValuePartialInformation,
  1320. ValueBuffer,
  1321. ELF_MAX_REG_KEY_INFO_SIZE,
  1322. &ulActualSize);
  1323. if (NT_SUCCESS(Status))
  1324. {
  1325. if(ValueBuffer->DataLength != 0)
  1326. return STATUS_SUCCESS; // all is well, there is already a string
  1327. }
  1328. // Get the computer name and write it
  1329. bRet = GetComputerName(wComputerName, &dwComputerNameLen);
  1330. if(bRet == FALSE)
  1331. {
  1332. ELF_LOG1(ERROR,
  1333. "EnsureComputerName: GetComputerName failed %#x\n",
  1334. GetLastError());
  1335. return STATUS_UNSUCCESSFUL;
  1336. }
  1337. // calc size in byte including null
  1338. dwLen = sizeof(WCHAR) * (dwComputerNameLen + 1);
  1339. Status = NtSetValueKey(hEventLogNode,
  1340. &ValueName,
  1341. 0,
  1342. REG_SZ,
  1343. wComputerName,
  1344. dwLen);
  1345. if (!NT_SUCCESS(Status))
  1346. ELF_LOG1(ERROR,
  1347. "EnsureComputerName: NtSetValueKey failed %#x\n",
  1348. Status);
  1349. return Status;
  1350. }
  1351. VOID
  1352. SvcEntry_Eventlog(
  1353. DWORD argc,
  1354. LPWSTR argv[],
  1355. PSVCS_GLOBAL_DATA SvcsGlobalData,
  1356. HANDLE SvcRefHandle
  1357. )
  1358. /*++
  1359. Routine Description:
  1360. This is the main routine for the Event Logging Service.
  1361. Arguments:
  1362. Command-line arguments.
  1363. Return Value:
  1364. NONE
  1365. --*/
  1366. {
  1367. NTSTATUS Status;
  1368. OBJECT_ATTRIBUTES ObjectAttributes;
  1369. UNICODE_STRING RootRegistryNode;
  1370. UNICODE_STRING ComputerNameRegistryNode;
  1371. ULONG Win32Error = NO_ERROR;
  1372. ELF_REQUEST_RECORD FlushRequest;
  1373. BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
  1374. PKEY_VALUE_FULL_INFORMATION ValueBuffer = (PKEY_VALUE_FULL_INFORMATION) Buffer;
  1375. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1376. HKEY hKey;
  1377. ULONG ValueSize = sizeof(ULONG);
  1378. #if DBG
  1379. UNICODE_STRING ValueName;
  1380. ULONG ulActualSize;
  1381. #endif // DBG
  1382. g_lNumSecurityWriters = 0;
  1383. //
  1384. // Set up the object that describes the root node for the eventlog service
  1385. //
  1386. RtlInitUnicodeString(&RootRegistryNode, REG_EVENTLOG_NODE_PATH);
  1387. InitializeObjectAttributes(&ObjectAttributes,
  1388. &RootRegistryNode,
  1389. OBJ_CASE_INSENSITIVE,
  1390. NULL,
  1391. NULL);
  1392. //
  1393. // If this fails, we'll just use the defaults
  1394. //
  1395. Status = NtOpenKey(&hEventLogNode, KEY_READ | KEY_NOTIFY | KEY_SET_VALUE, &ObjectAttributes);
  1396. if (NT_SUCCESS(Status))
  1397. {
  1398. Status = EnsureComputerName();
  1399. if (!NT_SUCCESS(Status))
  1400. {
  1401. //
  1402. // Not much we can do here as we don't even have a
  1403. // SERVICE_STATUS_HANDLE at this point.
  1404. //
  1405. return;
  1406. }
  1407. }
  1408. RtlInitUnicodeString(&ComputerNameRegistryNode, REG_COMPUTERNAME_NODE_PATH);
  1409. InitializeObjectAttributes(&ObjectAttributes,
  1410. &ComputerNameRegistryNode,
  1411. OBJ_CASE_INSENSITIVE,
  1412. NULL,
  1413. NULL);
  1414. Status = NtOpenKey(&hComputerNameNode, KEY_READ | KEY_NOTIFY, &ObjectAttributes);
  1415. if (!NT_SUCCESS(Status))
  1416. {
  1417. ELF_LOG1(ERROR,
  1418. "SvcEntry_Eventlog: NtOpenKey for ComputerName failed %#x -- exiting\n",
  1419. Status);
  1420. //
  1421. // Not much we can do here as we don't even have a
  1422. // SERVICE_STATUS_HANDLE at this point.
  1423. //
  1424. return;
  1425. }
  1426. ///////////////////////////////////////////////////////
  1427. #if DBG
  1428. //
  1429. // See if there's a debug value
  1430. //
  1431. RtlInitUnicodeString(&ValueName, VALUE_DEBUG);
  1432. Status = NtQueryValueKey(hEventLogNode,
  1433. &ValueName,
  1434. KeyValuePartialInformation,
  1435. ValueBuffer,
  1436. ELF_MAX_REG_KEY_INFO_SIZE,
  1437. &ulActualSize);
  1438. if (NT_SUCCESS(Status))
  1439. {
  1440. if (((PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer)->Type == REG_DWORD)
  1441. {
  1442. ElfDebugLevel = *(LPDWORD) (((PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer)->Data);
  1443. }
  1444. }
  1445. ELF_LOG1(TRACE,
  1446. "SvcEntry_Eventlog: ElfDebugLevel = %#x\n",
  1447. ElfDebugLevel);
  1448. #endif // DBG
  1449. UNREFERENCED_PARAMETER(argc);
  1450. UNREFERENCED_PARAMETER(argv);
  1451. ElfGlobalSvcRefHandle = SvcRefHandle;
  1452. ElfGlobalData = SvcsGlobalData;
  1453. //
  1454. // Initialize the list heads for the modules and log files.
  1455. //
  1456. InitializeListHead(&LogFilesHead);
  1457. InitializeListHead(&LogModuleHead);
  1458. InitializeListHead(&QueuedEventListHead);
  1459. InitializeListHead(&QueuedMessageListHead);
  1460. //
  1461. // Initialize to 0 so that we can clean up before exiting
  1462. //
  1463. EventFlags = 0;
  1464. //
  1465. // Create the Eventlog's private heap if possible. This must be
  1466. // done before any calls to ElfpAllocateBuffer are made.
  1467. //
  1468. ElfpCreateHeap();
  1469. //
  1470. // Initialize the status data.
  1471. //
  1472. Status = ElfpInitStatus();
  1473. if (!NT_SUCCESS(Status))
  1474. {
  1475. ELF_LOG1(ERROR,
  1476. "SvcEntry_Eventlog: ElfpInitStatus failed %#x -- exiting\n",
  1477. Status);
  1478. //
  1479. // Not much we can do here as we don't even have a
  1480. // SERVICE_STATUS_HANDLE at this point.
  1481. //
  1482. return;
  1483. }
  1484. //
  1485. // Set up control handler
  1486. //
  1487. if ((ElfServiceStatusHandle = RegisterServiceCtrlHandler(
  1488. EVENTLOG_SVC_NAMEW,
  1489. ElfControlResponse)) == 0)
  1490. {
  1491. Win32Error = GetLastError();
  1492. //
  1493. // If we got an error, we need to set status to uninstalled, and end the
  1494. // thread.
  1495. //
  1496. ELF_LOG1(ERROR,
  1497. "SvcEntry_Eventlog: RegisterServiceCtrlHandler failed %#x\n",
  1498. Win32Error);
  1499. goto cleanupandexit;
  1500. }
  1501. //
  1502. // Notify the Service Controller for the first time that we are alive
  1503. // and are in a start pending state
  1504. //
  1505. // *** UPDATE STATUS ***
  1506. ElfStatusUpdate(STARTING);
  1507. //
  1508. // Get the localized title for message box popups.
  1509. //
  1510. ElfInitMessageBoxTitle();
  1511. //
  1512. // Initialize a critical section for use when adding or removing
  1513. // LogFiles or LogModules. This must be done before we process any
  1514. // file information.
  1515. //
  1516. Status = ElfpInitCriticalSection(&LogFileCritSec);
  1517. if (!NT_SUCCESS(Status))
  1518. {
  1519. ELF_LOG1(ERROR,
  1520. "SvcEntry_Eventlog: Unable to create LogFileCritSec %#x\n",
  1521. Status);
  1522. goto cleanupandexit;
  1523. }
  1524. EventFlags |= ELF_INIT_LOGFILE_CRIT_SEC;
  1525. Status = ElfpInitCriticalSection(&LogModuleCritSec);
  1526. if (!NT_SUCCESS(Status))
  1527. {
  1528. ELF_LOG1(ERROR,
  1529. "SvcEntry_Eventlog: Unable to create LogModuleCritSec %#x\n",
  1530. Status);
  1531. goto cleanupandexit;
  1532. }
  1533. EventFlags |= ELF_INIT_LOGMODULE_CRIT_SEC;
  1534. Status = ElfpInitCriticalSection(&QueuedEventCritSec);
  1535. if (!NT_SUCCESS(Status))
  1536. {
  1537. ELF_LOG1(ERROR,
  1538. "SvcEntry_Eventlog: Unable to create QueuedEventCritSec %#x\n",
  1539. Status);
  1540. goto cleanupandexit;
  1541. }
  1542. EventFlags |= ELF_INIT_QUEUED_EVENT_CRIT_SEC;
  1543. Status = ElfpInitCriticalSection(&QueuedMessageCritSec);
  1544. if (!NT_SUCCESS(Status))
  1545. {
  1546. ELF_LOG1(ERROR,
  1547. "SvcEntry_Eventlog: Unable to create QueuedMessageCritSec %#x\n",
  1548. Status);
  1549. goto cleanupandexit;
  1550. }
  1551. EventFlags |= ELF_INIT_QUEUED_MESSAGE_CRIT_SEC;
  1552. //
  1553. // Initialize global anonymous logon sid for use in log ACL's.
  1554. //
  1555. Status = RtlAllocateAndInitializeSid(
  1556. &NtAuthority,
  1557. 1,
  1558. SECURITY_ANONYMOUS_LOGON_RID,
  1559. 0, 0, 0, 0, 0, 0, 0,
  1560. &AnonymousLogonSid);
  1561. if (!NT_SUCCESS(Status))
  1562. {
  1563. ELF_LOG1(ERROR,
  1564. "SvcEntry_Eventlog: Unable to create anonymous logon SID %#x\n",
  1565. Status);
  1566. goto cleanupandexit;
  1567. }
  1568. //
  1569. // Set up the data structures for the Logfiles and Modules.
  1570. //
  1571. Status = ElfSetUpConfigDataStructs();
  1572. if (!NT_SUCCESS(Status))
  1573. {
  1574. ELF_LOG1(ERROR,
  1575. "SvcEntry_Eventlog: ElfSetUpConfigDataStructs failed %#x\n",
  1576. Status);
  1577. goto cleanupandexit;
  1578. }
  1579. //
  1580. // Tell service controller that we are making progress
  1581. //
  1582. ElfStatusUpdate(STARTING);
  1583. //
  1584. // Initialize a critical section for use when adding or removing
  1585. // context handles (LogHandles).
  1586. //
  1587. Status = ElfpInitCriticalSection(&LogHandleCritSec);
  1588. if (!NT_SUCCESS(Status))
  1589. {
  1590. ELF_LOG1(ERROR,
  1591. "SvcEntry_Eventlog: Unable to create LogHandleCritSec %#x\n",
  1592. Status);
  1593. goto cleanupandexit;
  1594. }
  1595. EventFlags |= ELF_INIT_LOGHANDLE_CRIT_SEC;
  1596. //
  1597. // Initialize the context handle (log handle) list.
  1598. //
  1599. InitializeListHead( &LogHandleListHead );
  1600. //
  1601. // Initialize the Global Resource.
  1602. //
  1603. Status = ElfpInitResource(&GlobalElfResource);
  1604. if (!NT_SUCCESS(Status))
  1605. {
  1606. ELF_LOG1(ERROR,
  1607. "SvcEntry_Eventlog: Unable to create GlobalElfResource %#x\n",
  1608. Status);
  1609. goto cleanupandexit;
  1610. }
  1611. EventFlags |= ELF_INIT_GLOBAL_RESOURCE;
  1612. //
  1613. //Initialize a CritSec for clustering support
  1614. //
  1615. Status = ElfpInitCriticalSection(&gClPropCritSec);
  1616. if (!NT_SUCCESS(Status))
  1617. {
  1618. ELF_LOG1(ERROR,
  1619. "SvcEntry_Eventlog: Unable to create gClPropCritSec %#x\n",
  1620. Status);
  1621. goto cleanupandexit;
  1622. }
  1623. EventFlags |= ELF_INIT_CLUS_CRIT_SEC;
  1624. //
  1625. // Tell service controller that we are making progress
  1626. //
  1627. ElfStatusUpdate(STARTING);
  1628. // Create a thread for watching the LPC port.
  1629. //
  1630. if (!StartLPCThread())
  1631. {
  1632. ELF_LOG0(ERROR,
  1633. "SvcEntry_Eventlog: StartLPCThread failed\n");
  1634. Status = STATUS_UNSUCCESSFUL;
  1635. goto cleanupandexit;
  1636. }
  1637. EventFlags |= ELF_STARTED_LPC_THREAD;
  1638. //
  1639. // Tell service controller of that we are making progress
  1640. //
  1641. ElfStatusUpdate(STARTING);
  1642. //
  1643. // Create a thread for watching for changes in the registry.
  1644. //
  1645. if (!ElfStartRegistryMonitor())
  1646. {
  1647. ELF_LOG0(ERROR,
  1648. "SvcEntry_Eventlog: ElfStartRegistryMonitor failed\n");
  1649. Status = STATUS_UNSUCCESSFUL;
  1650. goto cleanupandexit;
  1651. }
  1652. EventFlags |= ELF_STARTED_REGISTRY_MONITOR;
  1653. //
  1654. // Write out an event that says we started
  1655. //
  1656. ElfpCreateElfEvent(EVENT_EventlogStarted,
  1657. EVENTLOG_INFORMATION_TYPE,
  1658. 0, // EventCategory
  1659. 0, // NumberOfStrings
  1660. NULL, // Strings
  1661. NULL, // Data
  1662. 0, // Datalength
  1663. 0,
  1664. FALSE); // flags
  1665. //
  1666. // Write a boot event with version info
  1667. //
  1668. ElfWriteProductInfoEvent();
  1669. // Write a computer name change event if that is applicable
  1670. ElfCheckForComputerNameChange();
  1671. //
  1672. // Read from the registry to determine the time stamp interval, default to 5 minutes
  1673. //
  1674. Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1675. REGSTR_PATH_RELIABILITY,
  1676. 0,
  1677. KEY_ALL_ACCESS,
  1678. &hKey);
  1679. if (Status == ERROR_SUCCESS)
  1680. {
  1681. RegQueryValueEx(hKey,
  1682. REGSTR_VAL_LASTALIVEINTERVAL,
  1683. 0,
  1684. NULL,
  1685. (PUCHAR) &g_PreviousInterval,
  1686. &ValueSize);
  1687. RegCloseKey (hKey);
  1688. }
  1689. //
  1690. // If this is setup, then dont do the periodic timestamp writting
  1691. // Setup has the feature where the last write is ignored and so
  1692. // the code acted as if a dirty shutdown happened.
  1693. //
  1694. if(SvcsGlobalData->fSetupInProgress)
  1695. {
  1696. g_PreviousInterval = 0; // stops the timer thread from starting
  1697. ElfWriteTimeStamp(EVENT_NormalShutdown,
  1698. FALSE); // clears out the time stamp.
  1699. }
  1700. if (g_PreviousInterval != 0)
  1701. {
  1702. //
  1703. // Write out the first timer based abnormal shutdown time stamp
  1704. //
  1705. ElfWriteTimeStamp (EVENT_AbNormalShutdown, TRUE);
  1706. }
  1707. //
  1708. // Write out any events that were queued up during initialization
  1709. //
  1710. FlushRequest.Command = ELF_COMMAND_WRITE_QUEUED;
  1711. ElfPerformRequest(&FlushRequest);
  1712. //
  1713. // Tell service controller that we are making progress
  1714. //
  1715. ElfStatusUpdate(STARTING);
  1716. //
  1717. // Finish setting up the RPC server
  1718. //
  1719. // NOTE: Now all RPC servers in services.exe share the same pipe name.
  1720. // However, in order to support communication with version 1.0 of WinNt,
  1721. // it is necessary for the Client Pipe name to remain the same as
  1722. // it was in version 1.0. Mapping to the new name is performed in
  1723. // the Named Pipe File System code.
  1724. //
  1725. Status = ElfGlobalData->StartRpcServer(
  1726. ElfGlobalData->SvcsRpcPipeName,
  1727. eventlog_ServerIfHandle);
  1728. if (!NT_SUCCESS(Status))
  1729. {
  1730. ELF_LOG1(ERROR,
  1731. "SvcEntry_Eventlog: StartRpcServer failed %#x\n",
  1732. Status);
  1733. goto cleanupandexit;
  1734. }
  1735. //
  1736. // Tell service controller that we are making progress
  1737. //
  1738. ElfStatusUpdate(RUNNING);
  1739. EventFlags |= ELF_STARTED_RPC_SERVER;
  1740. if (GetElState() == RUNNING)
  1741. {
  1742. if ( g_PreviousInterval != 0 )
  1743. {
  1744. //
  1745. // Create a thread to periodically write
  1746. // a time stamp to the registry.
  1747. //
  1748. g_hTimestampEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  1749. if (g_hTimestampEvent != NULL)
  1750. {
  1751. Status = RtlRegisterWait(&g_hTimestampWorkitem,
  1752. g_hTimestampEvent,
  1753. TimeStampProc, // Callback
  1754. (PVOID) UlongToPtr(g_PreviousInterval), // Context
  1755. 0, // Timeout
  1756. WT_EXECUTEONLYONCE);
  1757. if (!NT_SUCCESS(Status))
  1758. {
  1759. ELF_LOG1(ERROR,
  1760. "SvcEntry_Eventlog: RtlRegisterWait failed %#x\n",
  1761. Status);
  1762. }
  1763. }
  1764. else
  1765. {
  1766. ELF_LOG1(ERROR,
  1767. "SvcEntry_Eventlog: CreateEvent for timestamp failed %d\n",
  1768. GetLastError());
  1769. }
  1770. }
  1771. ELF_LOG0(TRACE,
  1772. "SvcEntry_Eventlog: Service running -- main thread returning\n");
  1773. return;
  1774. }
  1775. cleanupandexit:
  1776. //
  1777. // Come here if there is cleanup necessary.
  1778. //
  1779. ELF_LOG0(ERROR,
  1780. "SvcEntry_Eventlog: Exiting on error\n");
  1781. if (Win32Error == NO_ERROR)
  1782. {
  1783. Win32Error = RtlNtStatusToDosError(Status);
  1784. }
  1785. ElfBeginForcedShutdown(PENDING, Win32Error, Status);
  1786. //
  1787. // If the registry monitor has been initialized, then
  1788. // let it do the shutdown cleanup. All we need to do
  1789. // here is wake it up.
  1790. // Otherwise, this thread will do the cleanup.
  1791. //
  1792. if (EventFlags & ELF_STARTED_REGISTRY_MONITOR)
  1793. {
  1794. StopRegistryMonitor();
  1795. }
  1796. else
  1797. {
  1798. ElfpCleanUp(EventFlags);
  1799. }
  1800. return;
  1801. }
  1802. VOID
  1803. ElfInitMessageBoxTitle(
  1804. VOID
  1805. )
  1806. /*++
  1807. Routine Description:
  1808. Obtains the title text for the message box used to display messages.
  1809. If the title is successfully obtained from the message file, then
  1810. that title is pointed to by GlobalAllocatedMsgTitle and
  1811. GlobalMessageBoxTitle. If unsuccessful, then GlobalMessageBoxTitle
  1812. left pointing to the DefaultMessageBoxTitle.
  1813. NOTE: If successful, a buffer is allocated by this function. The
  1814. pointer stored in GlobalAllocatedMsgTitle and it should be freed when
  1815. done with this buffer.
  1816. Arguments:
  1817. Return Value:
  1818. none
  1819. --*/
  1820. {
  1821. LPVOID hModule;
  1822. DWORD msgSize;
  1823. //
  1824. // This function should be called only once during initialization. Note
  1825. // that it needs to be called before the Eventlog's RPC server is started
  1826. // or else it's possible for the log to fill up, which will generate a
  1827. // "log full" popup with no title (since GlobalMessageBoxTitle is NULL).
  1828. //
  1829. ASSERT(GlobalMessageBoxTitle == NULL);
  1830. hModule = LoadLibraryEx(L"netevent.dll",
  1831. NULL,
  1832. LOAD_LIBRARY_AS_DATAFILE);
  1833. if ( hModule == NULL)
  1834. {
  1835. ELF_LOG1(ERROR,
  1836. "ElfInitMessageBoxTitle: LoadLibrary of netevent.dll failed %d\n",
  1837. GetLastError());
  1838. return;
  1839. }
  1840. msgSize = FormatMessageW(
  1841. FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
  1842. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  1843. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1844. hModule,
  1845. TITLE_EventlogMessageBox, // MessageId
  1846. 0, // dwLanguageId
  1847. (LPWSTR) &GlobalMessageBoxTitle, // lpBuffer
  1848. 0, // nSize
  1849. NULL);
  1850. if (msgSize == 0)
  1851. {
  1852. ELF_LOG2(ERROR,
  1853. "ElfInitMessageBoxTitle: FormatMessage failed %d -- using %ws\n",
  1854. GetLastError(),
  1855. ELF_DEFAULT_MESSAGE_BOX_TITLE);
  1856. GlobalMessageBoxTitle = ELF_DEFAULT_MESSAGE_BOX_TITLE;
  1857. }
  1858. FreeLibrary(hModule);
  1859. return;
  1860. }
  1861. #ifdef EXIT_PROCESS
  1862. //
  1863. // This code is compiled into the Eventlog to track down a DLL that's loaded
  1864. // into services.exe and calls ExitProcess. Since this DLL should never be
  1865. // unloaded, we break into the debugger on DLL_PROCESS_DETACH. To use this,
  1866. // the following need to be added to the sources file:
  1867. //
  1868. // DLLENTRY= DllInit
  1869. //
  1870. // -DEXIT_PROCESS (to the C_DEFINES line)
  1871. //
  1872. BOOL
  1873. DllInit(
  1874. IN HINSTANCE hDll,
  1875. IN DWORD dwReason,
  1876. IN PCONTEXT pContext OPTIONAL
  1877. )
  1878. {
  1879. switch (dwReason) {
  1880. case DLL_PROCESS_ATTACH:
  1881. //
  1882. // No notification of THREAD_ATTACH and THREAD_DETACH
  1883. //
  1884. DisableThreadLibraryCalls(hDll);
  1885. break;
  1886. case DLL_PROCESS_DETACH:
  1887. //
  1888. // This should NEVER happen -- it means services.exe
  1889. // is exiting via an ExitProcess call
  1890. //
  1891. DebugBreak();
  1892. break;
  1893. }
  1894. return TRUE;
  1895. }
  1896. #endif // EXIT_PROCESS