Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3077 lines
90 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_hNoonEventWorkitem;
  48. HANDLE g_hTimestampEvent;
  49. ULONG g_PreviousInterval = DEFAULT_INTERVAL;
  50. ULONG g_TimeStampEnabled = 0;
  51. #define TIME_STAMP_ENABLED 0x1
  52. #define TIME_STAMP_DISABLED 0x0
  53. long g_lNumSecurityWriters = 0;
  54. //
  55. // Noon Event PData Constant and Data Structure
  56. //
  57. #define MAX_OS_INFO_LENGTH 64
  58. #define MAX_HARDWARE_INFO_LENGTH 128
  59. #define NUM_OF_CHAR( x ) (sizeof( x ) / sizeof( *x ))
  60. #define VERSION_ID_SIZE 5
  61. typedef struct _Noon_Event_Data
  62. {
  63. WCHAR szVersionId[ VERSION_ID_SIZE ]; // 1.0 or 1.1 or 1.11
  64. LONG lBootMode;
  65. WCHAR szOSName[ MAX_OS_INFO_LENGTH ];
  66. WCHAR szOSVersion[ MAX_OS_INFO_LENGTH + 128 ]; // + 128 for the szCSDVersion
  67. WCHAR szOSBuildType[ MAX_OS_INFO_LENGTH ];
  68. WCHAR szOSBuildString[ MAX_OS_INFO_LENGTH ];
  69. ULONG ulOriginalInstallDate;
  70. LPWSTR szHotFixes;
  71. WCHAR szSystemManufacturer[ MAX_HARDWARE_INFO_LENGTH ];
  72. WCHAR szSystemModel[ MAX_HARDWARE_INFO_LENGTH ];
  73. ULONG ulSystemType;
  74. ULONG ulProcessorNum;
  75. ULONG ulPhysicalMemory;
  76. ULONG ulSystemLangID;
  77. WCHAR szFQDN[ MAX_PATH ];
  78. }Noon_Event_Data, * PNoon_Event_Data;
  79. //
  80. // if added any new number field to the noon event structure, change this as well.
  81. //
  82. #define TOTAL_NUM_IN_NOON_EVENT 7
  83. #define TOTAL_FIELD_IN_NOON_EVENT 17
  84. #define NUM_OF_CHAR_IN_ULONG 12
  85. //
  86. // if we couldn't get some of the system information, we will use "UNKONW_STRING"
  87. // instead. (since the string is in PDATA(binary data), I think we don't need
  88. // localize it.
  89. //
  90. const WCHAR UNKNOWN_STRING[] = L"Not Available";
  91. //
  92. // pData contains all the constant information about the system. (those information
  93. // won't change until next reboot.)
  94. //
  95. typedef struct _Noon_Event_Info
  96. {
  97. LPWSTR pData;
  98. DWORD dwNumOfWChar;
  99. } Noon_Event_Info, *PNoon_Event_Info;
  100. Noon_Event_Info g_NoonEventInfo = {0};
  101. //
  102. // Local Function Prorotypes
  103. //
  104. VOID
  105. ElfInitMessageBoxTitle(
  106. VOID
  107. );
  108. NTSTATUS
  109. SetUpDataStruct (
  110. PUNICODE_STRING LogFileName,
  111. ULONG MaxFileSize,
  112. ULONG Retention,
  113. PUNICODE_STRING ModuleName,
  114. HANDLE hLogFile,
  115. ELF_LOG_TYPE LogType,
  116. LOGPOPUP logpLogPopup,
  117. DWORD dwAutoBackup
  118. )
  119. /*++
  120. Routine Description:
  121. This routine sets up the information for one module. It is called from
  122. ElfSetUpConfigDataStructs for each module to be configured.
  123. Module information is passed into this routine and a LOGMODULE structure
  124. is created for it. If the logfile associated with this module doesn't
  125. exist, a LOGFILE structure is created for it, and added to the linked
  126. list of LOGFILE structures. The LOGMODULE is associated with the LOGFILE,
  127. and it is added to the linked list of LOGMODULE structures. The logfile
  128. is opened and mapped to memory.
  129. Finally, at the end, this function calls SetUpModules, which looks at
  130. all the subkeys in the registry under this logfile, and adds any new ones
  131. to the linked list, and updates the Sources MULTI_SZ for the event viewer.
  132. Arguments:
  133. LogFileName - Name of log file for this module. If this routine needs
  134. a copy of this name it will make one, so that the caller can free
  135. the name afterwards if that is desired.
  136. MaxFileSize - Max size of the log file.
  137. Retention - Max retention for the file.
  138. ModuleName - Name of module that this file is associated with.
  139. RegistryHandle - Handle to the root node for this LogFile's info
  140. in the registry. This is used to enumerate all the
  141. modules under this key.
  142. Return Value:
  143. Pointer to Module structure that is allocated in this routine.
  144. NTSTATUS
  145. Note:
  146. --*/
  147. {
  148. NTSTATUS Status = STATUS_SUCCESS;
  149. PLOGFILE pLogFile = NULL;
  150. PLOGMODULE pModule = NULL;
  151. ANSI_STRING ModuleNameA;
  152. DWORD Type;
  153. BOOL bAllocatedLogInfo = FALSE;
  154. PUNICODE_STRING SavedBackupFileName = NULL;
  155. DWORD StringLength;
  156. PLOGMODULE OldDefaultLogModule = NULL;
  157. DWORD Progress = 0L;
  158. BOOL bNeedToReleaseResource = FALSE;
  159. BOOL bNoChange;
  160. //
  161. // Argument check.
  162. //
  163. if ((LogFileName == NULL) ||
  164. (LogFileName->Buffer == NULL) ||
  165. (ModuleName == NULL))
  166. {
  167. return(STATUS_INVALID_PARAMETER);
  168. }
  169. Status = VerifyUnicodeString(ModuleName);
  170. if (!NT_SUCCESS(Status))
  171. {
  172. return(STATUS_INVALID_PARAMETER);
  173. }
  174. // If the default log file for a module is also being used by another
  175. // module, then we just link that same file structure with the other
  176. // module.
  177. //
  178. // Truncate the maximum size of the log file to a 4K boundary.
  179. // This is to allow for page granularity.
  180. //
  181. pModule = ElfpAllocateBuffer (sizeof (LOGMODULE) );
  182. if (pModule == NULL)
  183. {
  184. return(STATUS_NO_MEMORY);
  185. }
  186. RtlEnterCriticalSection(&LogFileCritSec);
  187. pLogFile = FindLogFileFromName (LogFileName);
  188. if (pLogFile == NULL)
  189. {
  190. //
  191. //--------------------------------------
  192. // CREATE A NEW LOGFILE !!
  193. //--------------------------------------
  194. // A logfile by this name doesn't exist yet. So we will create
  195. // one so that we can add the module to it.
  196. //
  197. ELF_LOG1(TRACE,
  198. "SetupDataStruct: Create new struct for %ws log\n",
  199. LogFileName->Buffer);
  200. pLogFile = ElfpAllocateBuffer(sizeof(LOGFILE));
  201. if (pLogFile == NULL)
  202. {
  203. ELF_LOG1(ERROR,
  204. "SetupDataStruct: Unable to allocate struct for %ws log\n",
  205. LogFileName->Buffer);
  206. ElfpFreeBuffer(pModule);
  207. RtlLeaveCriticalSection(&LogFileCritSec);
  208. return STATUS_NO_MEMORY;
  209. }
  210. //
  211. // Allocate a new LogFileName that can be attached to the
  212. // new pLogFile structure.
  213. //
  214. StringLength = LogFileName->Length + sizeof(WCHAR);
  215. SavedBackupFileName = (PUNICODE_STRING) ElfpAllocateBuffer(
  216. sizeof(UNICODE_STRING) + StringLength);
  217. if (SavedBackupFileName == NULL)
  218. {
  219. ELF_LOG1(ERROR,
  220. "SetupDataStruct: Unable to allocate backup name for %ws log\n",
  221. LogFileName->Buffer);
  222. ElfpFreeBuffer(pModule);
  223. ElfpFreeBuffer(pLogFile);
  224. RtlLeaveCriticalSection(&LogFileCritSec);
  225. return STATUS_NO_MEMORY;
  226. }
  227. SavedBackupFileName->Buffer = (LPWSTR)((LPBYTE) SavedBackupFileName +
  228. sizeof(UNICODE_STRING));
  229. SavedBackupFileName->Length = LogFileName->Length;
  230. SavedBackupFileName->MaximumLength = (USHORT) StringLength;
  231. RtlMoveMemory(SavedBackupFileName->Buffer, LogFileName->Buffer,
  232. LogFileName->Length);
  233. SavedBackupFileName->Buffer[SavedBackupFileName->Length / sizeof(WCHAR)] =
  234. L'\0';
  235. //
  236. // This is the first user - RefCount gets incrememted below
  237. //
  238. pLogFile->RefCount = 0;
  239. pLogFile->FileHandle = NULL;
  240. pLogFile->LogFileName = SavedBackupFileName;
  241. pLogFile->ConfigMaxFileSize = ELFFILESIZE(MaxFileSize);
  242. pLogFile->Retention = Retention;
  243. pLogFile->ulLastPulseTime = 0;
  244. pLogFile->logpLogPopup = logpLogPopup;
  245. pLogFile->bHosedByClear = FALSE;
  246. pLogFile->LastStatus = 0;
  247. pLogFile->bFullAlertDone = FALSE;
  248. pLogFile->AutoBackupLogFiles = 0;
  249. pLogFile->pwsCurrCustomSD = 0;
  250. pLogFile->AutoBackupLogFiles = dwAutoBackup;
  251. pLogFile->ViewSize = 0;
  252. pLogFile->SectionHandle = NULL;
  253. pLogFile->bFailedExpansion = FALSE;
  254. //
  255. // Save away the default module name for this file
  256. //
  257. pLogFile->LogModuleName = ElfpAllocateBuffer(
  258. sizeof(UNICODE_STRING) + ModuleName->MaximumLength);
  259. //
  260. // This flag can be set since pLogfile->LogModuleName
  261. // will be initialized after this point
  262. //
  263. bAllocatedLogInfo = TRUE;
  264. if (pLogFile->LogModuleName == NULL)
  265. {
  266. ELF_LOG1(ERROR,
  267. "SetupDataStruct: Unable to allocate module name for %ws log\n",
  268. LogFileName->Buffer);
  269. Status = STATUS_NO_MEMORY;
  270. goto ErrorExit;
  271. }
  272. pLogFile->LogModuleName->MaximumLength = ModuleName->MaximumLength;
  273. pLogFile->LogModuleName->Buffer =
  274. (LPWSTR)(pLogFile->LogModuleName + 1);
  275. RtlCopyUnicodeString(pLogFile->LogModuleName, ModuleName);
  276. InitializeListHead (&pLogFile->Notifiees);
  277. pLogFile->NextClearMaxFileSize = pLogFile->ConfigMaxFileSize;
  278. Status = ElfpInitResource(&pLogFile->Resource);
  279. if (!NT_SUCCESS(Status))
  280. {
  281. ELF_LOG1(ERROR,
  282. "SetupDataStruct: Unable to init resource for %ws log\n",
  283. LogFileName->Buffer);
  284. goto ErrorExit;
  285. }
  286. LinkLogFile ( pLogFile ); // Link it in
  287. Progress |= LOGFILE_LINKED;
  288. } // endif (pLogfile == NULL)
  289. else
  290. {
  291. bNeedToReleaseResource = TRUE;
  292. RtlAcquireResourceExclusive (&pLogFile->Resource,
  293. TRUE); // Wait until available
  294. }
  295. //--------------------------------------
  296. // ADD THE MODULE TO THE LOG MODULE LIST
  297. //--------------------------------------
  298. // Set up the module data structure for the default (which is
  299. // the same as the logfile keyname).
  300. //
  301. pLogFile->RefCount++;
  302. pModule->LogFile = pLogFile;
  303. pModule->ModuleName = (LPWSTR) ModuleName->Buffer;
  304. Status = RtlUnicodeStringToAnsiString (
  305. &ModuleNameA,
  306. ModuleName,
  307. TRUE);
  308. if (!NT_SUCCESS(Status))
  309. {
  310. ELF_LOG2(ERROR,
  311. "SetupDataStruct: Unable to convert module name %ws to Ansi %#x\n",
  312. ModuleName->Buffer,
  313. Status);
  314. pLogFile->RefCount--;
  315. goto ErrorExit;
  316. }
  317. //
  318. // Link the new module in.
  319. //
  320. LinkLogModule(pModule, &ModuleNameA);
  321. RtlFreeAnsiString (&ModuleNameA);
  322. Progress |= MODULE_LINKED;
  323. //
  324. // Open up the file and map it to memory. Impersonate the
  325. // caller so we can use UNC names
  326. //
  327. if (LogType == ElfBackupLog)
  328. {
  329. Status = I_RpcMapWin32Status(RpcImpersonateClient(NULL));
  330. if (NT_SUCCESS(Status))
  331. {
  332. Status = VerifyFileIsFile(pLogFile->LogFileName);
  333. if (!NT_SUCCESS(Status))
  334. {
  335. ELF_LOG1(ERROR,
  336. "SetupDataStruct: VerifyFileIsFile failed %#x\n",
  337. Status);
  338. }
  339. else
  340. Status = ElfOpenLogFile (pLogFile, LogType);
  341. RpcRevertToSelf();
  342. }
  343. else
  344. {
  345. ELF_LOG1(ERROR,
  346. "SetupDataStruct: RpcImpersonateClient failed %#x\n",
  347. Status);
  348. }
  349. }
  350. else
  351. {
  352. Status = ElfOpenLogFile (pLogFile, LogType);
  353. }
  354. if (!NT_SUCCESS(Status))
  355. {
  356. ELF_LOG3(ERROR,
  357. "SetupDataStruct: Couldn't open %ws for module %ws %#x\n",
  358. LogFileName->Buffer,
  359. ModuleName->Buffer,
  360. Status);
  361. if (LogType != ElfBackupLog)
  362. {
  363. ElfpCreateQueuedAlert(ALERT_ELF_LogFileNotOpened,
  364. 1,
  365. &(ModuleName->Buffer));
  366. }
  367. pLogFile->RefCount--;
  368. goto ErrorExit;
  369. }
  370. Progress |= LOGFILE_OPENED;
  371. //
  372. // If this is the application module, remember the pointer
  373. // to use if a module doesn't have an entry in the registry
  374. //
  375. if (!_wcsicmp(ModuleName->Buffer, ELF_DEFAULT_MODULE_NAME))
  376. {
  377. OldDefaultLogModule = ElfDefaultLogModule;
  378. ElfDefaultLogModule = pModule;
  379. }
  380. //
  381. // Create the security descriptor for this logfile. Only
  382. // the system and security modules are secured against
  383. // reads and writes by interactive. Also, make sure we never
  384. // pop up a "log full" message for the Security log -- this
  385. // would be a C2 violation.
  386. //
  387. Type = GetModuleType(ModuleName->Buffer);
  388. if (Type == ELF_LOGFILE_SECURITY)
  389. pLogFile->logpLogPopup = LOGPOPUP_NEVER_SHOW;
  390. //
  391. // Create a Security Descriptor for this Logfile
  392. // (RtlDeleteSecurityObject() can be used to free
  393. // pLogFile->Sd).
  394. //
  395. Status = ElfpCreateLogFileObject(pLogFile, Type, hLogFile, TRUE, &bNoChange);
  396. if (!NT_SUCCESS(Status))
  397. {
  398. ELF_LOG2(ERROR,
  399. "SetupDataStruct: Unable to create SD for log %ws %#x\n",
  400. ModuleName->Buffer,
  401. Status);
  402. // Dont decrease the ref count here. The progress has the LOGFILE_OPENED
  403. // bit set and so ElfpCloseLogFile will be called which decrements.
  404. goto ErrorExit;
  405. }
  406. //
  407. // Now that we've added the default module name, see if there are any
  408. // modules configured to log to this file, and if so, create the module
  409. // structures for them.
  410. //
  411. SetUpModules(hLogFile, pLogFile, FALSE);
  412. if(bNeedToReleaseResource)
  413. RtlReleaseResource(&pLogFile->Resource);
  414. RtlLeaveCriticalSection(&LogFileCritSec);
  415. return STATUS_SUCCESS;
  416. ErrorExit:
  417. if (Progress & LOGFILE_OPENED)
  418. {
  419. ElfpCloseLogFile(pLogFile, ELF_LOG_CLOSE_BACKUP, FALSE);
  420. }
  421. if (Progress & MODULE_LINKED)
  422. {
  423. UnlinkLogModule(pModule);
  424. DeleteAtom(pModule->ModuleAtom);
  425. }
  426. if (bAllocatedLogInfo)
  427. {
  428. if (Progress & LOGFILE_LINKED)
  429. {
  430. UnlinkLogFile(pLogFile);
  431. RtlDeleteResource (&pLogFile->Resource);
  432. ELF_LOG1(TRACE,
  433. "SetupDataStruct: is unlinking log file 0x%x\n",pLogFile);
  434. }
  435. ElfpFreeBuffer(pLogFile->LogModuleName);
  436. ElfpFreeBuffer(SavedBackupFileName);
  437. ElfpFreeBuffer(pLogFile);
  438. }
  439. ElfpFreeBuffer(pModule);
  440. if (OldDefaultLogModule != NULL)
  441. {
  442. ElfDefaultLogModule = OldDefaultLogModule;
  443. }
  444. if(bNeedToReleaseResource)
  445. RtlReleaseResource(&pLogFile->Resource);
  446. RtlLeaveCriticalSection(&LogFileCritSec);
  447. return Status;
  448. }
  449. NTSTATUS
  450. SetUpModules(
  451. HANDLE hLogFile,
  452. PLOGFILE pLogFile,
  453. BOOLEAN bAllowDupes
  454. )
  455. /*++
  456. Routine Description:
  457. This routine sets up the information for all modules for a logfile.
  458. The subkeys under a logfile in the eventlog portion of the registry
  459. are enumerated. For each unique subkey, a LOGMODULE structure is
  460. created. Each new structures is added to a linked list
  461. of modules for that logfile.
  462. If there was one or more unique subkeys, meaning the list has changed
  463. since we last looked, then we go through the entire linked list of
  464. log modules, and create a MULTI_SZ list of all the modules. This list
  465. is stored in the Sources value for that logfile for the event viewer
  466. to use.
  467. NOTE: A module is never un-linked from the linked list of log modules
  468. even if the registry subkey for it is removed. This should probably
  469. be done sometime. It would make the eventlog more robust.
  470. Arguments:
  471. hLogFile - Registry key for the Log File node
  472. pLogFile - pointer to the log file structure
  473. bAllowDupes - If true, it's ok to already have a module with the same
  474. name (used when processing change notify of registry)
  475. Return Value:
  476. NTSTATUS - If unsuccessful, it is not a fatal error.
  477. Even if this status is unsuccessful, me may have been able
  478. to store some of the new subkeys in the LogModule list. Also, we
  479. may have been able to update the Sources MULTI_SZ list.
  480. --*/
  481. {
  482. NTSTATUS Status = STATUS_SUCCESS;
  483. BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
  484. PKEY_NODE_INFORMATION KeyBuffer = (PKEY_NODE_INFORMATION) Buffer;
  485. ULONG ActualSize;
  486. PWCHAR SubKeyString;
  487. UNICODE_STRING NewModule;
  488. ANSI_STRING ModuleNameA;
  489. PLOGMODULE pModule;
  490. ULONG Index = 0;
  491. ATOM Atom;
  492. PWCHAR pList;
  493. PWCHAR pListStart;
  494. DWORD dwListNumByte = 0;
  495. DWORD ListLength = 0;
  496. DWORD dwBytes = 0;
  497. UNICODE_STRING ListName;
  498. BOOLEAN ListChanged = FALSE;
  499. PLIST_ENTRY pListEntry;
  500. //
  501. // Create the module structures for all modules under this logfile. We
  502. // don't actually need to open the key, since we don't use any information
  503. // stored there, it's existence is all we care about here. Any data is
  504. // used by the Event Viewer (or any viewing app). If this is used to
  505. // setup a backup file, hLogFile is NULL since there aren't any other
  506. // modules to map to this file.
  507. //
  508. while (NT_SUCCESS(Status) && hLogFile)
  509. {
  510. Status = NtEnumerateKey(hLogFile,
  511. Index++,
  512. KeyNodeInformation,
  513. KeyBuffer,
  514. ELF_MAX_REG_KEY_INFO_SIZE,
  515. &ActualSize);
  516. if (NT_SUCCESS(Status))
  517. {
  518. //
  519. // It turns out the Name isn't null terminated, so we need
  520. // to copy it somewhere and null terminate it before we use it
  521. //
  522. SubKeyString = ElfpAllocateBuffer(KeyBuffer->NameLength + sizeof(WCHAR));
  523. if (!SubKeyString)
  524. {
  525. return STATUS_NO_MEMORY;
  526. }
  527. memcpy(SubKeyString, KeyBuffer->Name, KeyBuffer->NameLength);
  528. SubKeyString[KeyBuffer->NameLength / sizeof(WCHAR)] = L'\0' ;
  529. //
  530. // Add the atom for this module name
  531. //
  532. RtlInitUnicodeString(&NewModule, SubKeyString);
  533. Status = RtlUnicodeStringToAnsiString (
  534. &ModuleNameA,
  535. &NewModule,
  536. TRUE);
  537. if (!NT_SUCCESS(Status))
  538. {
  539. //
  540. // We can't continue, so we will leave the modules
  541. // we've linked so far, and move on in an attempt to
  542. // create the Sources MULTI_SZ list.
  543. //
  544. ELF_LOG1(TRACE,
  545. "SetUpModules: Unable to convert name for module %ws\n",
  546. SubKeyString);
  547. ElfpFreeBuffer(SubKeyString);
  548. break;
  549. }
  550. Atom = FindAtomA(ModuleNameA.Buffer);
  551. //
  552. // Make sure we've not already added one by this name
  553. //
  554. if (FindModuleStrucFromAtom(Atom))
  555. {
  556. //
  557. // We've already encountered a module by this name. If
  558. // this is init time, it's a configuration error. Report
  559. // it and move on. If we're processing a change notify
  560. // from the registry, this is ok (it means we're rescanning
  561. // an existing Event Source for an existing log).
  562. //
  563. if (!bAllowDupes)
  564. {
  565. ELF_LOG1(ERROR,
  566. "SetUpModules: Module %ws exists in two log files.\n",
  567. SubKeyString);
  568. }
  569. RtlFreeAnsiString(&ModuleNameA);
  570. ElfpFreeBuffer(SubKeyString);
  571. continue;
  572. }
  573. ListChanged = TRUE;
  574. pModule = ElfpAllocateBuffer (sizeof (LOGMODULE) );
  575. if (!pModule)
  576. {
  577. ELF_LOG1(ERROR,
  578. "SetUpModules: Unable to allocate structure for module %ws\n",
  579. SubKeyString);
  580. RtlFreeAnsiString (&ModuleNameA);
  581. ElfpFreeBuffer(SubKeyString);
  582. return(STATUS_NO_MEMORY);
  583. }
  584. //
  585. // Set up a module data structure for this module
  586. //
  587. pModule->LogFile = pLogFile;
  588. pModule->ModuleName = SubKeyString;
  589. //
  590. // Link the new module in.
  591. //
  592. LinkLogModule(pModule, &ModuleNameA);
  593. ELF_LOG1(TRACE,
  594. "SetUpModules: Module %ws successfully created/linked\n",
  595. SubKeyString);
  596. RtlFreeAnsiString (&ModuleNameA);
  597. }
  598. }
  599. if (Status == STATUS_NO_MORE_ENTRIES)
  600. {
  601. //
  602. // It's not required that there are configured modules for a log
  603. // file.
  604. //
  605. Status = STATUS_SUCCESS;
  606. }
  607. //
  608. // If the list has changed, or if we've been called during init, and not
  609. // as the result of a changenotify on the registry (bAllowDupes == FALSE)
  610. // then create the sources key
  611. //
  612. if (hLogFile && (ListChanged || !bAllowDupes))
  613. {
  614. //
  615. // Now create a MULTI_SZ entry with all the module names for eventvwr
  616. //
  617. // STEP 1: Calculate amount of storage needed by running thru the
  618. // module list, finding any module that uses this log file.
  619. //
  620. pListEntry = LogModuleHead.Flink;
  621. while (pListEntry != &LogModuleHead)
  622. {
  623. pModule = CONTAINING_RECORD (pListEntry, LOGMODULE, ModuleList);
  624. if (pModule->LogFile == pLogFile)
  625. {
  626. //
  627. // This one is for the log we're working on, get the
  628. // size of its name.
  629. //
  630. ListLength += WCSSIZE(pModule->ModuleName);
  631. ELF_LOG2(MODULES,
  632. "SetUpModules: Adding module %ws to list for %ws log\n",
  633. pModule->ModuleName,
  634. pLogFile->LogFileName->Buffer);
  635. }
  636. pListEntry = pModule->ModuleList.Flink;
  637. }
  638. //
  639. // STEP 2: Allocate storage for the MULTI_SZ.
  640. //
  641. if(ListLength > 0)
  642. {
  643. dwListNumByte = ListLength + sizeof(WCHAR);
  644. pList = ElfpAllocateBuffer(dwListNumByte);
  645. pListStart = pList;
  646. //
  647. // If I can't allocate the list, just press on
  648. //
  649. if (pList)
  650. {
  651. //
  652. // STEP 3: Copy all the module names for this logfile into
  653. // the MULTI_SZ string.
  654. //
  655. SubKeyString = pList; // Save this away
  656. pListEntry = LogModuleHead.Flink;
  657. while (pListEntry != &LogModuleHead)
  658. {
  659. pModule = CONTAINING_RECORD(pListEntry,
  660. LOGMODULE,
  661. ModuleList);
  662. if (pModule->LogFile == pLogFile)
  663. {
  664. //
  665. // This one is for the log we're working on, put it in the list
  666. //
  667. dwBytes = dwListNumByte/sizeof(WCHAR) - (pList-pListStart);
  668. StringCchCopyW(pList, dwBytes, pModule->ModuleName);
  669. pList += wcslen(pModule->ModuleName);
  670. pList++;
  671. }
  672. pListEntry = pModule->ModuleList.Flink;
  673. }
  674. *pList = L'\0'; // The terminating NULL
  675. RtlInitUnicodeString(&ListName, L"Sources");
  676. Status = NtSetValueKey(hLogFile,
  677. &ListName,
  678. 0,
  679. REG_MULTI_SZ,
  680. SubKeyString,
  681. ListLength + sizeof(WCHAR));
  682. ElfpFreeBuffer(SubKeyString);
  683. }
  684. else
  685. {
  686. ELF_LOG1(ERROR,
  687. "SetUpModules: Unable to allocate list for %ws log\n",
  688. pLogFile->LogFileName->Buffer);
  689. }
  690. }
  691. }
  692. return Status;
  693. }
  694. NTSTATUS
  695. CreateDefaultDataStruct(
  696. LPWSTR pwsLogFileName,
  697. LPWSTR pwsDefModuleName,
  698. LOGPOPUP logpLogPopup
  699. )
  700. /*++
  701. Routine Description:
  702. This routine creates a default module. This is used in the case where some
  703. essential log, such a security is not present in the registry.
  704. Arguments:
  705. pwsLogFileName Log file name
  706. pwsDefModuleName Default module name
  707. logpLogPopup What to do when log is full
  708. Return Value:
  709. Status
  710. Note:
  711. IF SUCCESSFUL, THE MODULE NAME IS NOT DELETED HERE, BUT IS DELETED WHEN
  712. THE DATA STRUCT IS RELEASED!!!
  713. --*/
  714. {
  715. NTSTATUS Status;
  716. PUNICODE_STRING pModuleName = NULL;
  717. UNICODE_STRING usUnexpanded, usExpandedName;
  718. WCHAR wExpandedPath[MAX_PATH+1];
  719. DWORD NumberOfBytes;
  720. UNICODE_STRING NTFormatName;
  721. NumberOfBytes = sizeof(wExpandedPath);
  722. NTFormatName.Buffer = NULL;
  723. if(pwsLogFileName == NULL || pwsDefModuleName == NULL)
  724. return STATUS_INVALID_PARAMETER;
  725. // First take the default string, that has environment variables in it,
  726. // and expand it.
  727. RtlInitUnicodeString(&usUnexpanded, pwsLogFileName);
  728. usExpandedName.Length = usExpandedName.MaximumLength = (USHORT)NumberOfBytes;
  729. usExpandedName.Buffer = (LPWSTR) wExpandedPath;
  730. Status = RtlExpandEnvironmentStrings_U(NULL,
  731. &usUnexpanded,
  732. &usExpandedName,
  733. &NumberOfBytes);
  734. if (!NT_SUCCESS(Status))
  735. {
  736. ELF_LOG1(ERROR,
  737. "CreateDefaultDataStruct: RtlExpandEnvironmentStrings_U failed, status=0x%x\n",
  738. Status);
  739. return Status;
  740. }
  741. // Convert the expanded string into nt file format
  742. if (!RtlDosPathNameToNtPathName_U(usExpandedName.Buffer,
  743. &NTFormatName,
  744. NULL,
  745. NULL))
  746. {
  747. ELF_LOG0(ERROR,
  748. "CreateDefaultDataStruct: RtlDosPathNameToNtPathName_U failed\n");
  749. return STATUS_UNSUCCESSFUL;
  750. }
  751. pModuleName = ElfpAllocateBuffer(sizeof(UNICODE_STRING));
  752. if (pModuleName == NULL)
  753. {
  754. RtlFreeHeap(RtlProcessHeap(), 0, NTFormatName.Buffer);
  755. return STATUS_NO_MEMORY;
  756. }
  757. RtlInitUnicodeString(pModuleName, pwsDefModuleName);
  758. //
  759. // On success, don't free pModuleName as the pointer to it
  760. // is stored away in the LogFile struct
  761. //
  762. Status = SetUpDataStruct(&NTFormatName,
  763. ELF_DEFAULT_MAX_FILE_SIZE,
  764. ELF_DEFAULT_RETENTION_PERIOD,
  765. pModuleName,
  766. NULL,
  767. ElfNormalLog,
  768. logpLogPopup,
  769. ELF_DEFAULT_AUTOBACKUP);
  770. RtlFreeHeap(RtlProcessHeap(), 0, NTFormatName.Buffer);
  771. if (!NT_SUCCESS(Status))
  772. {
  773. ELF_LOG1(ERROR,
  774. "CreateDefaultDataStruct: Unable to set up %ws log\n",
  775. pwsLogFileName);
  776. ElfpFreeBuffer(pModuleName);
  777. pModuleName = NULL;
  778. }
  779. return Status;
  780. }
  781. NTSTATUS
  782. ElfSetUpConfigDataStructs(
  783. VOID
  784. )
  785. /*++
  786. Routine Description:
  787. This routine sets up all the necessary data structures for the eventlog
  788. service. It enumerates the keys in the Logfiles registry node to
  789. determine what to setup.
  790. Arguments:
  791. NONE
  792. Return Value:
  793. NONE
  794. Note:
  795. --*/
  796. {
  797. NTSTATUS Status = STATUS_SUCCESS;
  798. HANDLE hLogFile;
  799. OBJECT_ATTRIBUTES ObjectAttributes;
  800. UNICODE_STRING SubKeyName;
  801. UNICODE_STRING uTestString;
  802. LOGPOPUP logpLogPopup;
  803. UNICODE_STRING EventlogModuleName;
  804. UNICODE_STRING EventlogSecModuleName;
  805. ULONG Index = 0;
  806. BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
  807. PKEY_NODE_INFORMATION KeyBuffer = (PKEY_NODE_INFORMATION) Buffer;
  808. ULONG ActualSize;
  809. LOG_FILE_INFO LogFileInfo;
  810. PWCHAR SubKeyString;
  811. LPWSTR ModuleName;
  812. ELF_LOG0(TRACE,
  813. "ElfSetUpConfigDataStructs: Entering\n");
  814. //
  815. // Initialize the Atom table whose size is the maximum number of
  816. // module structures possible, i.e. ELF_MAX_LOG_MODULES.
  817. //
  818. if (!InitAtomTable(ELF_MAX_LOG_MODULES))
  819. {
  820. return STATUS_UNSUCCESSFUL;
  821. }
  822. //
  823. // Get a handle to the Logfiles subkey. If it doesn't exist, just use
  824. // the hard-coded defaults.
  825. //
  826. if (hEventLogNode)
  827. {
  828. //
  829. // Loop thru the subkeys under Eventlog and set up each logfile
  830. //
  831. while (NT_SUCCESS(Status))
  832. {
  833. Status = NtEnumerateKey(hEventLogNode,
  834. Index++,
  835. KeyNodeInformation,
  836. KeyBuffer,
  837. ELF_MAX_REG_KEY_INFO_SIZE,
  838. &ActualSize);
  839. if (NT_SUCCESS(Status))
  840. {
  841. //
  842. // It turns out the Name isn't null terminated, so we need
  843. // to copy it somewhere and null terminate it before we use it
  844. //
  845. SubKeyString = ElfpAllocateBuffer(KeyBuffer->NameLength + sizeof(WCHAR));
  846. if (!SubKeyString)
  847. {
  848. return STATUS_NO_MEMORY;
  849. }
  850. memcpy(SubKeyString, KeyBuffer->Name, KeyBuffer->NameLength);
  851. SubKeyString[KeyBuffer->NameLength / sizeof(WCHAR)] = L'\0';
  852. //
  853. // Open the node for this logfile and extract the information
  854. // required by SetupDataStruct, and then call it.
  855. //
  856. RtlInitUnicodeString(&SubKeyName, SubKeyString);
  857. InitializeObjectAttributes(&ObjectAttributes,
  858. &SubKeyName,
  859. OBJ_CASE_INSENSITIVE,
  860. hEventLogNode,
  861. NULL);
  862. Status = NtOpenKey(&hLogFile,
  863. KEY_READ | KEY_SET_VALUE,
  864. &ObjectAttributes);
  865. if (!NT_SUCCESS(Status))
  866. {
  867. //
  868. // Unclear how this could happen since I just enum'ed
  869. // it, but if I can't open it, I just pretend like it
  870. // wasn't there to begin with.
  871. //
  872. ELF_LOG1(TRACE,
  873. "ElfSetUpConfigDataStructs: Unable to open key for %ws log\n",
  874. SubKeyName);
  875. ElfpFreeBuffer(SubKeyString);
  876. Status = STATUS_SUCCESS; // so we don't terminate the loop
  877. continue;
  878. }
  879. //
  880. // Get the information from the registry. Note that we have to
  881. // initialize the "log full" popup policy before doing so since
  882. // ReadRegistryInfo will compare the value found in the registry
  883. // (if there is one) to the current value.
  884. //
  885. LogFileInfo.logpLogPopup = IS_WORKSTATION() ? LOGPOPUP_NEVER_SHOW :
  886. LOGPOPUP_CLEARED;
  887. Status = ReadRegistryInfo(hLogFile,
  888. &SubKeyName,
  889. &LogFileInfo);
  890. if (NT_SUCCESS(Status))
  891. {
  892. //
  893. // Now set up the actual data structures. Failures are
  894. // dealt with in the routine. Note that the check for
  895. // the security log (i.e., for LOGPOPUP_NEVER_SHOW) is
  896. // made in SetUpDataStruct
  897. //
  898. SetUpDataStruct(LogFileInfo.LogFileName,
  899. LogFileInfo.MaxFileSize,
  900. LogFileInfo.Retention,
  901. &SubKeyName,
  902. hLogFile,
  903. ElfNormalLog,
  904. LogFileInfo.logpLogPopup,
  905. LogFileInfo.dwAutoBackup);
  906. NtClose(hLogFile);
  907. }
  908. else
  909. {
  910. ELF_LOG1(ERROR,
  911. "ElfSetUpConfigdataStructs: ReadRegistryInfo failed %#x\n",
  912. Status);
  913. }
  914. }
  915. }
  916. } // if (hEventLogNode)
  917. else
  918. {
  919. logpLogPopup = IS_WORKSTATION() ? LOGPOPUP_NEVER_SHOW :
  920. LOGPOPUP_CLEARED;
  921. Status = STATUS_SUCCESS;
  922. }
  923. //
  924. // If we just ran out of keys, that's OK (unless there weren't any at all)
  925. //
  926. if (Status == STATUS_NO_MORE_ENTRIES && Index != 1)
  927. {
  928. Status = STATUS_SUCCESS;
  929. }
  930. if (NT_SUCCESS(Status))
  931. {
  932. //
  933. // Make sure we created the Application log file, since it is the
  934. // default.
  935. if (!ElfDefaultLogModule)
  936. {
  937. ELF_LOG0(ERROR,
  938. "ElfSetUpConfigDatastructs: No Application module -- creating default\n");
  939. Status = CreateDefaultDataStruct(
  940. ELF_APPLICATION_DEFAULT_LOG_FILE,
  941. ELF_DEFAULT_MODULE_NAME, logpLogPopup);
  942. if (!NT_SUCCESS(Status))
  943. {
  944. ELF_LOG0(ERROR,
  945. "ElfSetUpConfigDatastructs: Could not create the application log -- exiting\n");
  946. return STATUS_EVENTLOG_CANT_START;
  947. }
  948. }
  949. // Make sure we created the Security log file.
  950. if (NULL == FindLogFileByModName(ELF_SECURITY_MODULE_NAME))
  951. {
  952. ELF_LOG0(ERROR,
  953. "ElfSetUpConfigDatastructs: No Security module -- creating default\n");
  954. Status = CreateDefaultDataStruct(
  955. ELF_SECURITY_DEFAULT_LOG_FILE,
  956. ELF_SECURITY_MODULE_NAME, logpLogPopup);
  957. if (!NT_SUCCESS(Status))
  958. {
  959. ELF_LOG0(ERROR,
  960. "ElfSetUpConfigDatastructs: Could not create the security log -- exiting\n");
  961. return STATUS_EVENTLOG_CANT_START;
  962. }
  963. }
  964. // Make sure we created the System log file.
  965. if (NULL == FindLogFileByModName(ELF_SYSTEM_MODULE_NAME))
  966. {
  967. ELF_LOG0(ERROR,
  968. "ElfSetUpConfigDatastructs: No System module -- creating default\n");
  969. Status = CreateDefaultDataStruct(
  970. ELF_SYSTEM_DEFAULT_LOG_FILE,
  971. ELF_SYSTEM_MODULE_NAME, logpLogPopup);
  972. if (!NT_SUCCESS(Status))
  973. {
  974. // not good, but carry on anyway
  975. ELF_LOG0(ERROR,
  976. "ElfSetUpConfigDatastructs: Could not create the system log\n");
  977. }
  978. }
  979. //
  980. // Now get the Module for the Eventlog service to use. GetModuleStruc
  981. // always succeeds, returning the default log if the requested one
  982. // isn't configured.
  983. //
  984. RtlInitUnicodeString(&EventlogModuleName, L"eventlog");
  985. ElfModule = GetModuleStruc(&EventlogModuleName);
  986. RtlInitUnicodeString(&EventlogSecModuleName, L"SECURITY");
  987. ElfSecModule = GetModuleStruc(&EventlogSecModuleName);
  988. }
  989. return Status;
  990. }
  991. VOID
  992. ElfWriteNoonEvent(
  993. TIMESTAMPEVENT EventType,
  994. ULONG ulTimeStampInterval
  995. )
  996. /*++
  997. Routine Description:
  998. This routine writes a Noon/Start/Stop event to the event log. The NoonEvent contains the system
  999. Uptime, TimeStampInterval, TimeZone. information.
  1000. The NoonEvent PData contains system version information, such as: OSVersion, OSBuildType,
  1001. HotFixes, System Manufacturer, System Model, System Type, BIOS Version, BIOS Date,
  1002. ProcessorNumber, PhysicalMemory Size, LangID and FQDN
  1003. Arguments:
  1004. EventType - type of the Event, could be start/stop/noonEvent
  1005. ulTimeStampInterval - interval of the time stamp
  1006. if interval equals 0, only the version information/PDATA
  1007. will not write to the event.
  1008. Return Value:
  1009. NONE
  1010. Note:
  1011. --*/
  1012. {
  1013. TIME_ZONE_INFORMATION timeZoneInfo;
  1014. #define NUM_OF_NOON_EVENT_STRINGS 7
  1015. LPWSTR NoonEventStrings[ NUM_OF_NOON_EVENT_STRINGS ];
  1016. LPWSTR UptimeString = NULL;
  1017. LPWSTR TimeStampString = NULL;
  1018. LPWSTR TimeZoneString = NULL;
  1019. WCHAR NullString[2];
  1020. HRESULT hr;
  1021. ULONG ulTemp = 0;
  1022. //
  1023. // As defined in the spec:
  1024. // the first 4 string will be empty strings.
  1025. // 5th string will be Uptime.
  1026. // 6th string will be TimeStampInterval in seconds.
  1027. // 7th string will be TimeZone information
  1028. //
  1029. *NullString = 0;
  1030. for ( ulTemp = 0; ulTemp < NUM_OF_NOON_EVENT_STRINGS; ulTemp++ )
  1031. NoonEventStrings[ ulTemp ] = NullString;
  1032. UptimeString = (LPWSTR)ElfpAllocateBuffer( NUM_OF_CHAR_IN_ULONG * sizeof(WCHAR) );
  1033. TimeStampString = (LPWSTR)ElfpAllocateBuffer( NUM_OF_CHAR_IN_ULONG * sizeof(WCHAR) );
  1034. TimeZoneString = (LPWSTR)ElfpAllocateBuffer( sizeof( TIME_ZONE_INFORMATION ) );
  1035. if ( !UptimeString || !TimeStampString || !TimeZoneString )
  1036. {
  1037. goto cleanup;
  1038. }
  1039. //
  1040. // Time Zone
  1041. //
  1042. if ( TIME_ZONE_ID_INVALID != GetTimeZoneInformation( &timeZoneInfo ) )
  1043. {
  1044. hr = StringCchPrintfW(TimeZoneString, sizeof(TIME_ZONE_INFORMATION)/sizeof(WCHAR),
  1045. L"%d %s",
  1046. timeZoneInfo.Bias,
  1047. timeZoneInfo.StandardName );
  1048. NoonEventStrings[ 6 ] = TimeZoneString;
  1049. }
  1050. //
  1051. // Get system uptime.
  1052. //
  1053. hr = StringCchPrintfW(UptimeString, NUM_OF_CHAR_IN_ULONG,
  1054. L"%d", GetNoonEventSystemUptime());
  1055. NoonEventStrings[ 4 ] = UptimeString;
  1056. hr = StringCchPrintfW(TimeStampString, NUM_OF_CHAR_IN_ULONG,
  1057. L"%d", ulTimeStampInterval);
  1058. NoonEventStrings[ 5 ] = TimeStampString;
  1059. ElfpCreateElfEvent(
  1060. EventType,
  1061. EVENTLOG_INFORMATION_TYPE,
  1062. 0, // EventCategory
  1063. NUM_OF_NOON_EVENT_STRINGS, // NumberOfStrings
  1064. NoonEventStrings, // Strings
  1065. ( (ulTimeStampInterval == 0 )? NULL: g_NoonEventInfo.pData), // Version Info
  1066. ( (ulTimeStampInterval == 0 )? 0 : g_NoonEventInfo.dwNumOfWChar * sizeof(WCHAR)), // Datalength
  1067. 0, // flags
  1068. FALSE); // Security file
  1069. cleanup:
  1070. ElfpFreeBuffer( UptimeString );
  1071. ElfpFreeBuffer( TimeStampString );
  1072. ElfpFreeBuffer( TimeZoneString );
  1073. #undef NUM_OF_NOON_EVENT_STRINGS
  1074. return;
  1075. }
  1076. VOID
  1077. ElfWriteTimeStamp(
  1078. TIMESTAMPEVENT EventType,
  1079. BOOLEAN CheckPreviousStamp
  1080. )
  1081. /*++
  1082. Routine Description:
  1083. This routine writes a time stamp in the form of a systemtime structure
  1084. to the registry which is then used to extract reliability data.
  1085. Arguments:
  1086. EventType - Indicates what type of event we are logging
  1087. CheckPreviousStamp - Whether we should check for the existance of a previous
  1088. time stamp which indicates a prior system crash.
  1089. Return Value:
  1090. NONE
  1091. Note:
  1092. --*/
  1093. {
  1094. #define NUM_OF_EVENT_STRINGS 7
  1095. SYSTEMTIME stCurrentUTCTime;
  1096. SYSTEMTIME stPreviousUTCTime;
  1097. SYSTEMTIME stPreviousLocalTime;
  1098. ULONG ulUptime = 0;
  1099. DWORD dwDirtyFlag = 1;
  1100. HKEY hKey;
  1101. LONG rc;
  1102. DWORD ValueSize;
  1103. ULONG Interval = DEFAULT_INTERVAL;
  1104. ULONG wchars;
  1105. LPWSTR DateTimeBuffer[NUM_OF_EVENT_STRINGS];
  1106. WCHAR NullString[ 1 ];
  1107. rc = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  1108. REGSTR_PATH_RELIABILITY,
  1109. 0,
  1110. NULL,
  1111. REG_OPTION_NON_VOLATILE,
  1112. KEY_ALL_ACCESS,
  1113. NULL,
  1114. &hKey,
  1115. NULL);
  1116. if (rc != ERROR_SUCCESS)
  1117. {
  1118. return;
  1119. }
  1120. if (EventType == EVENT_NormalShutdown)
  1121. {
  1122. //
  1123. // Delete the time stamp registry value, this is how we indicate a clean shutdown
  1124. //
  1125. RegDeleteValue(hKey, REGSTR_VAL_LASTALIVESTAMP);
  1126. RegFlushKey(hKey);
  1127. RegCloseKey(hKey);
  1128. return;
  1129. }
  1130. //
  1131. // Get the current UTC time
  1132. //
  1133. GetSystemTime(&stCurrentUTCTime);
  1134. if (CheckPreviousStamp)
  1135. {
  1136. ValueSize = sizeof(SYSTEMTIME);
  1137. rc = RegQueryValueEx(hKey,
  1138. REGSTR_VAL_LASTALIVESTAMP,
  1139. 0,
  1140. NULL,
  1141. (PUCHAR) &stPreviousUTCTime,
  1142. &ValueSize);
  1143. //
  1144. // If we can successfully read a systemtime structure it indicates
  1145. // that the previous shutdown was abnormal, i.e. we didn't execute
  1146. // or normal shutdown cleanup code.
  1147. //
  1148. //
  1149. // Format the time and date of the crash time stamp
  1150. // appropriately for the locale and log a #6008 event
  1151. //
  1152. if ((rc == ERROR_SUCCESS) && (ValueSize == sizeof(SYSTEMTIME)))
  1153. {
  1154. SYSTEMTIME lpData[2]; // Data for the event
  1155. WCHAR TimeStampString[ NUM_OF_CHAR_IN_ULONG ];
  1156. ULONG ulIndex = 0;
  1157. //
  1158. // init the evnet strings.
  1159. //
  1160. *NullString = 0;
  1161. for ( ulIndex = 0; ulIndex < NUM_OF_EVENT_STRINGS; ulIndex ++ )
  1162. DateTimeBuffer[ ulIndex ] = NullString;
  1163. //
  1164. // now let's get the previous uptime.
  1165. //
  1166. ValueSize = sizeof(ULONG);
  1167. if (!RegQueryValueEx(hKey,
  1168. REGSTR_VAL_LASTALIVEUPTIME,
  1169. 0,
  1170. NULL,
  1171. (PUCHAR)&ulUptime,
  1172. &ValueSize ) )
  1173. {
  1174. StringCchPrintfW(TimeStampString, NUM_OF_CHAR_IN_ULONG,
  1175. L"%d", ulUptime);
  1176. DateTimeBuffer[ 4 ] = TimeStampString;
  1177. }
  1178. if (!SystemTimeToTzSpecificLocalTime(NULL,
  1179. &stPreviousUTCTime,
  1180. &stPreviousLocalTime))
  1181. {
  1182. //
  1183. // Couldn't convert to the active time zone -- use UTC
  1184. //
  1185. stPreviousLocalTime = stPreviousUTCTime;
  1186. }
  1187. //
  1188. // Write the local time and the UTC time for the "last alive"
  1189. // timestamp since NT4SP5 shipped with only the local time
  1190. // as the event data. This allows tools that work on NT4SP5
  1191. // to continue working on NT5.
  1192. //
  1193. lpData[0] = stPreviousLocalTime;
  1194. lpData[1] = stPreviousUTCTime;
  1195. wchars = GetTimeFormat(LOCALE_SYSTEM_DEFAULT,
  1196. 0,
  1197. &stPreviousLocalTime,
  1198. NULL,
  1199. NULL,
  1200. 0);
  1201. DateTimeBuffer[0] = ElfpAllocateBuffer(wchars * sizeof(WCHAR));
  1202. if (DateTimeBuffer[0])
  1203. {
  1204. GetTimeFormat(LOCALE_SYSTEM_DEFAULT,
  1205. 0,
  1206. &stPreviousLocalTime,
  1207. NULL,
  1208. DateTimeBuffer[0],
  1209. wchars);
  1210. wchars = GetDateFormat(LOCALE_SYSTEM_DEFAULT,
  1211. 0,
  1212. &stPreviousLocalTime,
  1213. NULL,
  1214. NULL,
  1215. 0);
  1216. DateTimeBuffer[1] = ElfpAllocateBuffer(wchars * sizeof(WCHAR));
  1217. if (DateTimeBuffer[1])
  1218. {
  1219. GetDateFormat(LOCALE_SYSTEM_DEFAULT,
  1220. 0,
  1221. &stPreviousLocalTime,
  1222. NULL,
  1223. DateTimeBuffer[1],
  1224. wchars);
  1225. ElfpCreateElfEvent(
  1226. EVENT_EventlogAbnormalShutdown,
  1227. EVENTLOG_ERROR_TYPE,
  1228. 0, // EventCategory
  1229. NUM_OF_EVENT_STRINGS, // NumberOfStrings
  1230. DateTimeBuffer, // Strings
  1231. lpData, // "Last alive" times
  1232. 2 * sizeof(SYSTEMTIME), // Datalength
  1233. 0, // flags
  1234. FALSE); // for security file
  1235. ElfpFreeBuffer(DateTimeBuffer[1]);
  1236. RegSetValueEx(hKey,
  1237. L"DirtyShutDown",
  1238. 0,
  1239. REG_DWORD,
  1240. (PUCHAR) &dwDirtyFlag,
  1241. sizeof(DWORD));
  1242. }
  1243. ElfpFreeBuffer(DateTimeBuffer[0]);
  1244. }
  1245. }
  1246. }
  1247. //
  1248. // Set the current time stamp
  1249. //
  1250. RegSetValueEx(hKey,
  1251. REGSTR_VAL_LASTALIVESTAMP,
  1252. 0,
  1253. REG_BINARY,
  1254. (PUCHAR) &stCurrentUTCTime,
  1255. sizeof(SYSTEMTIME));
  1256. //
  1257. // Set the current UpTime
  1258. //
  1259. ulUptime = GetNoonEventSystemUptime();
  1260. RegSetValueEx(hKey,
  1261. REGSTR_VAL_LASTALIVEUPTIME,
  1262. 0,
  1263. REG_DWORD,
  1264. (PUCHAR)&ulUptime,
  1265. sizeof(ULONG));
  1266. // Following flush is commented out to avoid a deadlock for VolSnap 702130
  1267. //RegFlushKey (hKey);
  1268. RegCloseKey (hKey);
  1269. #undef NUM_OF_EVENT_STRINGS
  1270. }
  1271. VOID
  1272. ElfWriteProductInfoEvent (
  1273. VOID
  1274. )
  1275. /*++
  1276. Routine Description:
  1277. This function writes an event #6009 which includes the OS version, build #,
  1278. service pack level, MP/UP, and Free/Checked.
  1279. Arguments:
  1280. NONE
  1281. Return Value:
  1282. NONE
  1283. Note:
  1284. --*/
  1285. {
  1286. #define NUM_INFO_VALUES 4 //EVENT_EventLogProductInfo requires 4 parameters
  1287. DWORD dwNumStrChr = 0;
  1288. NTSTATUS Status = STATUS_SUCCESS;
  1289. HKEY hKey = NULL;
  1290. ULONG ValueSize = 0;
  1291. LPWSTR NullString = L"";
  1292. LPWSTR StringBuffers[NUM_INFO_VALUES] = {NULL, NULL, NULL, NULL};
  1293. OSVERSIONINFOEX OsVersion;
  1294. WCHAR wszTemp[NUM_OF_CHAR_IN_ULONG];
  1295. UINT i;
  1296. OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1297. if( !GetVersionEx( (LPOSVERSIONINFO)&OsVersion ) )
  1298. {
  1299. return;
  1300. }
  1301. //Allocate storage
  1302. //Buffer 0 holds the version number in the format of 5.xx.
  1303. dwNumStrChr = 2*NUM_OF_CHAR_IN_ULONG + 2;
  1304. StringBuffers[0] = ElfpAllocateBuffer( dwNumStrChr * sizeof(WCHAR) );
  1305. //Buffer 1 holds the build number
  1306. StringBuffers[1] = ElfpAllocateBuffer( (NUM_OF_CHAR_IN_ULONG) * sizeof(WCHAR) );
  1307. //Buffer 2 holds the service pack
  1308. StringBuffers[2] = ElfpAllocateBuffer( sizeof(OsVersion.szCSDVersion) );
  1309. if( StringBuffers[0] == NULL ||
  1310. StringBuffers[1] == NULL ||
  1311. StringBuffers[2] == NULL )
  1312. {
  1313. goto ErrorExit;
  1314. }
  1315. //
  1316. //Add major version
  1317. //
  1318. _ltow (
  1319. OsVersion.dwMajorVersion,
  1320. wszTemp,
  1321. 10
  1322. );
  1323. StringCchCopyW(StringBuffers[0], dwNumStrChr, wszTemp);
  1324. StringCchCatW(StringBuffers[0], dwNumStrChr, L"." );
  1325. //
  1326. //Add minor version
  1327. //
  1328. _ltow (
  1329. OsVersion.dwMinorVersion,
  1330. wszTemp,
  1331. 10
  1332. );
  1333. if( OsVersion.dwMinorVersion < 10 )
  1334. {
  1335. StringCchCatW(StringBuffers[0], dwNumStrChr, L"0" );
  1336. }
  1337. StringCchCatW(StringBuffers[0], dwNumStrChr, wszTemp );
  1338. StringCchCatW(StringBuffers[0], dwNumStrChr, L"." );
  1339. //
  1340. //Get build number
  1341. //
  1342. _ltow (
  1343. OsVersion.dwBuildNumber,
  1344. wszTemp,
  1345. 10
  1346. );
  1347. StringCchCopyW( StringBuffers[1], NUM_OF_CHAR_IN_ULONG, wszTemp );
  1348. //Get service pack info
  1349. StringCchCopyW( StringBuffers[2], sizeof(OsVersion.szCSDVersion)/sizeof(WCHAR),
  1350. OsVersion.szCSDVersion );
  1351. //
  1352. // Get OS type (uniprocessor or multiprocessor chk or free)
  1353. // Open HKLM\Software\Microsoft\Windows NT\CurrentVersion
  1354. //
  1355. if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1356. REGSTR_PATH_NT_CURRENTVERSION,
  1357. 0,
  1358. KEY_ALL_ACCESS,
  1359. &hKey)
  1360. != ERROR_SUCCESS)
  1361. {
  1362. goto ErrorExit;
  1363. }
  1364. //
  1365. // For each of the registry values, query for the string size, allocate storage,
  1366. // and query the actual value
  1367. //
  1368. if ((RegQueryValueEx (hKey,
  1369. REGSTR_VAL_CURRENT_TYPE,
  1370. 0,
  1371. NULL,
  1372. NULL,
  1373. &ValueSize)
  1374. == ERROR_SUCCESS)
  1375. &&
  1376. ValueSize != 0)
  1377. {
  1378. StringBuffers[3] = ElfpAllocateBuffer(ValueSize);
  1379. if (StringBuffers[3] != NULL)
  1380. {
  1381. RegQueryValueEx(hKey,
  1382. REGSTR_VAL_CURRENT_TYPE,
  1383. 0,
  1384. NULL,
  1385. (PUCHAR) StringBuffers[3],
  1386. &ValueSize);
  1387. ValueSize = 0;
  1388. }
  1389. }
  1390. else
  1391. {
  1392. StringBuffers[3] = NullString;
  1393. }
  1394. ElfpCreateElfEvent(
  1395. EVENT_EventLogProductInfo,
  1396. EVENTLOG_INFORMATION_TYPE,
  1397. 0, // EventCategory
  1398. NUM_INFO_VALUES, // NumberOfStrings
  1399. StringBuffers, // Strings
  1400. NULL, // EventData
  1401. 0, // Datalength
  1402. 0, // flags
  1403. FALSE); // for security file
  1404. ErrorExit:
  1405. for (i = 0; i < NUM_INFO_VALUES; i++)
  1406. {
  1407. if (StringBuffers[i] != NULL && StringBuffers[i] != NullString)
  1408. {
  1409. ElfpFreeBuffer(StringBuffers[i]);
  1410. }
  1411. }
  1412. if( hKey != NULL )
  1413. {
  1414. RegCloseKey (hKey);
  1415. }
  1416. #undef NUM_INFO_VALUES
  1417. }
  1418. VOID
  1419. TimeStampProc(
  1420. PVOID Interval,
  1421. BOOLEAN fWaitStatus
  1422. )
  1423. {
  1424. NTSTATUS ntStatus;
  1425. HANDLE hWaitHandle;
  1426. ULONG ValueSize;
  1427. HKEY hKey;
  1428. ULONG NewInterval;
  1429. ULONG rc;
  1430. //
  1431. // Deregister the wait (note that we must do this even
  1432. // if the WT_EXECUTEONLYONCE flag is set)
  1433. //
  1434. ntStatus = RtlDeregisterWait(g_hTimestampWorkitem);
  1435. if (!NT_SUCCESS(ntStatus))
  1436. {
  1437. ELF_LOG1(ERROR,
  1438. "TimeStampProc: RtlDeregister wait failed %#x\n",
  1439. ntStatus);
  1440. }
  1441. if (fWaitStatus == FALSE)
  1442. {
  1443. //
  1444. // The event log service is stopping
  1445. //
  1446. return;
  1447. }
  1448. //
  1449. // Note: NewInterval is specified in seconds
  1450. //
  1451. NewInterval = (ULONG)((ULONG_PTR)Interval);
  1452. //
  1453. // The event timed out -- write a timestamp
  1454. //
  1455. ElfWriteTimeStamp (EVENT_AbNormalShutdown, FALSE);
  1456. //
  1457. // recheck the time stamp interval value
  1458. //
  1459. NewInterval = GetNoonEventTimeStamp();
  1460. if ( NewInterval != 0 )
  1461. {
  1462. //
  1463. // Reregister the wait
  1464. //
  1465. ntStatus = RtlRegisterWait(&g_hTimestampWorkitem,
  1466. g_hTimestampEvent,
  1467. TimeStampProc, // Callback
  1468. (PVOID) UlongToPtr(NewInterval), // Context
  1469. NewInterval * 1000, // Timeout, in ms
  1470. WT_EXECUTEONLYONCE);
  1471. }
  1472. if (!NT_SUCCESS(ntStatus) || NewInterval == 0 )
  1473. {
  1474. InterlockedExchange(&g_TimeStampEnabled, TIME_STAMP_DISABLED);
  1475. ELF_LOG1(ERROR,
  1476. "TimeStampProc: RtlRegisterWait failed %#x.\n",
  1477. ntStatus);
  1478. }
  1479. }
  1480. VOID
  1481. NoonEventProc(
  1482. PVOID pData,
  1483. BOOLEAN fWaitStatus
  1484. )
  1485. {
  1486. NTSTATUS ntStatus;
  1487. HANDLE hWaitHandle;
  1488. ULONG NewInterval;
  1489. ULONG TimeStampInterval;
  1490. //
  1491. // Deregister the wait (note that we must do this even
  1492. // if the WT_EXECUTEONLYONCE flag is set)
  1493. //
  1494. ntStatus = RtlDeregisterWait(g_hNoonEventWorkitem);
  1495. if (!NT_SUCCESS(ntStatus))
  1496. {
  1497. ELF_LOG1(ERROR,
  1498. "NoonEventProc: RtlDeregister wait failed %#x\n",
  1499. ntStatus);
  1500. }
  1501. if (fWaitStatus == FALSE)
  1502. {
  1503. //
  1504. // The event log service is stopping
  1505. //
  1506. return;
  1507. }
  1508. //
  1509. // Note: NewInterval is specified in SECONDS
  1510. //
  1511. NewInterval = GetNextNoonEventDelay();
  1512. //
  1513. // The event timed out -- write a timestamp
  1514. //
  1515. TimeStampInterval = GetNoonEventTimeStamp();
  1516. //
  1517. // Note: as we noticed RtlRegisterWait could timeout before timeout value
  1518. // we specified, so we will only create an event when the NewInterval
  1519. // value is greater than a certain value. (We don't want two events
  1520. // shown up in a short time period. (filter out any early timeouts,
  1521. // if next noon is within 12 hour range, we will not write the noon
  1522. // event.)
  1523. // Remove this if checking when RtlRegisterWait timeout is fixed.
  1524. //
  1525. //
  1526. if ( NewInterval > 60 * 60 * 12 )
  1527. {
  1528. ElfWriteNoonEvent (EVENT_EventlogUptime, TimeStampInterval );
  1529. }
  1530. else
  1531. {
  1532. ELF_LOG1(ERROR,
  1533. "NoonEventProc: invoked earlier, next noon %d seconds\n",
  1534. NewInterval );
  1535. }
  1536. //
  1537. // If timeStamp proc is turned off and TimeStampInterval is > 0.
  1538. // let's turn on the timeStampProc
  1539. //
  1540. if ( TimeStampInterval > 0 && g_TimeStampEnabled != TIME_STAMP_ENABLED )
  1541. {
  1542. if ( InterlockedCompareExchange( &g_TimeStampEnabled,
  1543. TIME_STAMP_ENABLED,
  1544. TIME_STAMP_DISABLED )
  1545. == TIME_STAMP_DISABLED )
  1546. {
  1547. ntStatus = RtlRegisterWait(&g_hTimestampWorkitem,
  1548. g_hTimestampEvent,
  1549. TimeStampProc, // Callback
  1550. (PVOID) UlongToPtr(TimeStampInterval), // Context
  1551. TimeStampInterval * 1000, // Timeout, in ms
  1552. WT_EXECUTEONLYONCE);
  1553. if (!NT_SUCCESS(ntStatus))
  1554. {
  1555. ELF_LOG1(ERROR,
  1556. "TimeStampProc: Rtl-RegisterWait failed %#x\n",
  1557. ntStatus);
  1558. InterlockedExchange( &g_TimeStampEnabled, TIME_STAMP_DISABLED );
  1559. }
  1560. }
  1561. }
  1562. //
  1563. // Reregister the wait
  1564. //
  1565. ntStatus = RtlRegisterWait(&g_hNoonEventWorkitem,
  1566. g_hTimestampEvent,
  1567. NoonEventProc, // Callback
  1568. (PVOID) NULL, // Context
  1569. NewInterval * 1000, // Timeout, in ms
  1570. WT_EXECUTEONLYONCE);
  1571. if (!NT_SUCCESS(ntStatus))
  1572. {
  1573. ELF_LOG1(ERROR,
  1574. "NoonEventProc: RtlRegisterWait failed %#x\n",
  1575. ntStatus);
  1576. }
  1577. }
  1578. DWORD NoonEventGetOsVersionInfo(
  1579. Noon_Event_Data* pNoonEvent
  1580. )
  1581. /*++
  1582. Routine Description:
  1583. This routine gather the OS related information.
  1584. Arguments:
  1585. pNoonEvent - point to the noon event data. (PDATA - version info)
  1586. Return Value:
  1587. if failed, return non zero error code.
  1588. Note:
  1589. --*/
  1590. {
  1591. LPCWSTR OsInfoKey = L"Software\\Microsoft\\Windows NT\\CurrentVersion";
  1592. LPCWSTR ProductName = L"ProductName";
  1593. LPCWSTR CurrentType = L"CurrentType";
  1594. LPCWSTR InstallDate = L"InstallDate";
  1595. LPCWSTR BuildLab = L"BuildLab";
  1596. DWORD cbData = 0;
  1597. HKEY hOsKey;
  1598. DWORD dwError = ERROR_SUCCESS;
  1599. DWORD dwType = 0;
  1600. OSVERSIONINFOEX osVersionInfoEx = {0};
  1601. osVersionInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  1602. if ( GetVersionEx( (LPOSVERSIONINFOW) &(osVersionInfoEx) ) )
  1603. {
  1604. //
  1605. // OsVersion: 5.1.3580 Build 3580
  1606. //
  1607. StringCchPrintfW(pNoonEvent->szOSVersion,
  1608. MAX_OS_INFO_LENGTH + 128,
  1609. L"%d.%d.%d Build %d %s",
  1610. osVersionInfoEx.dwMajorVersion,
  1611. osVersionInfoEx.dwMinorVersion,
  1612. osVersionInfoEx.dwBuildNumber,
  1613. osVersionInfoEx.dwBuildNumber,
  1614. (*(osVersionInfoEx.szCSDVersion))? osVersionInfoEx.szCSDVersion:TEXT(" ")
  1615. );
  1616. pNoonEvent->szOSVersion[ NUM_OF_CHAR(pNoonEvent->szOSVersion) - 1 ] = 0;
  1617. }
  1618. else
  1619. {
  1620. pNoonEvent->szOSVersion[0] = 0;
  1621. }
  1622. if ( !RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1623. OsInfoKey,
  1624. 0,
  1625. KEY_READ,
  1626. &hOsKey ) )
  1627. {
  1628. //
  1629. // OSName: Microsoft Windows XP
  1630. //
  1631. cbData = sizeof( pNoonEvent->szOSName);
  1632. if ( RegQueryValueEx( hOsKey, ProductName, NULL, &dwType, (LPBYTE)pNoonEvent->szOSName, &cbData) ||
  1633. dwType != REG_SZ )
  1634. {
  1635. pNoonEvent->szOSName[0] = 0;
  1636. }
  1637. //
  1638. // OsBuildType: Uniprocessor Free
  1639. //
  1640. cbData = sizeof( pNoonEvent->szOSBuildType );
  1641. if ( RegQueryValueEx( hOsKey, CurrentType, NULL, &dwType, (LPBYTE)pNoonEvent->szOSBuildType, &cbData) ||
  1642. dwType != REG_SZ )
  1643. {
  1644. pNoonEvent->szOSBuildType[0] = 0;
  1645. }
  1646. //
  1647. // Original Install Date: ULONG
  1648. //
  1649. cbData = sizeof( ULONG );
  1650. if ( RegQueryValueEx( hOsKey, InstallDate, NULL, NULL, (LPBYTE)(&pNoonEvent->ulOriginalInstallDate), &cbData) )
  1651. {
  1652. pNoonEvent->ulOriginalInstallDate = 0;
  1653. }
  1654. //
  1655. // BuildString: 2600.xpclient.010817-1148
  1656. //
  1657. cbData = sizeof( pNoonEvent->szOSBuildString );
  1658. if ( RegQueryValueEx( hOsKey, BuildLab, NULL, &dwType, (LPBYTE)pNoonEvent->szOSBuildString, &cbData) ||
  1659. dwType != REG_SZ )
  1660. {
  1661. pNoonEvent->szOSBuildString[0] = 0;
  1662. }
  1663. RegCloseKey( hOsKey );
  1664. }
  1665. else
  1666. {
  1667. //
  1668. // RegOpenKey failed.
  1669. //
  1670. pNoonEvent->szOSName[0] = 0;
  1671. pNoonEvent->szOSBuildType[0] = 0;
  1672. pNoonEvent->ulOriginalInstallDate = 0;
  1673. pNoonEvent->szOSBuildString[0] = 0;
  1674. }
  1675. pNoonEvent->ulSystemLangID = (ULONG)GetSystemDefaultLangID();
  1676. return dwError;
  1677. }
  1678. DWORD NoonEventGetHardwareInfo(
  1679. Noon_Event_Data* pNoonEvent
  1680. )
  1681. /*++
  1682. Routine Description:
  1683. This routine gather information about hardware such as: Manufacture, Model, Physical Memory,
  1684. Processor Number...
  1685. Arguments:
  1686. pNoonEvent - point to the noon event data. (PDATA - version info)
  1687. Return Value:
  1688. if failed, return non zero error code.
  1689. Note:
  1690. pNoonEvent->szBiosVersion free by caller
  1691. --*/
  1692. {
  1693. DWORD dwError = ERROR_SUCCESS;
  1694. LPCWSTR OemInfoKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\WindowsUpdate\\OemInfo";
  1695. LPCWSTR WbemOem = L"WbemOem";
  1696. LPCWSTR WbemProduct = L"WbemProduct";
  1697. HKEY hOemKey;
  1698. DWORD cbData;
  1699. DWORD dwLength = 0;
  1700. DWORD dwType = 0;
  1701. SYSTEM_INFO sysInfo;
  1702. MEMORYSTATUSEX memoryStatus = {0};
  1703. //
  1704. // Dns Fully Qualified. If the host is a node of cluster, the node's name
  1705. // will be displayed.
  1706. //
  1707. dwLength = NUM_OF_CHAR( pNoonEvent->szFQDN );
  1708. if ( !GetComputerNameEx( ComputerNamePhysicalDnsFullyQualified,
  1709. pNoonEvent->szFQDN,
  1710. &dwLength ) )
  1711. {
  1712. ELF_LOG1(ERROR, "GetComputerNameEx failed, error: %u\n", GetLastError());
  1713. *(pNoonEvent->szFQDN) = 0;
  1714. }
  1715. GetSystemInfo( &sysInfo );
  1716. pNoonEvent->ulProcessorNum = sysInfo.dwNumberOfProcessors;
  1717. pNoonEvent->ulSystemType = sysInfo.wProcessorArchitecture;
  1718. if ( !RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  1719. OemInfoKey,
  1720. 0,
  1721. KEY_READ,
  1722. &hOemKey ) )
  1723. {
  1724. //
  1725. // Manufacture:
  1726. //
  1727. cbData = sizeof( pNoonEvent->szSystemManufacturer );
  1728. if ( RegQueryValueEx( hOemKey, WbemOem, NULL, &dwType, (LPBYTE)pNoonEvent->szSystemManufacturer, &cbData) ||
  1729. dwType != REG_SZ )
  1730. {
  1731. pNoonEvent->szSystemManufacturer[0] = 0;
  1732. }
  1733. //
  1734. // Model
  1735. //
  1736. cbData = sizeof( pNoonEvent->szSystemModel );
  1737. if ( RegQueryValueEx( hOemKey, WbemProduct, NULL, &dwType, (LPBYTE)pNoonEvent->szSystemModel, &cbData) ||
  1738. dwType != REG_SZ )
  1739. {
  1740. pNoonEvent->szSystemModel[ 0 ] = 0;
  1741. }
  1742. RegCloseKey( hOemKey );
  1743. }
  1744. else
  1745. {
  1746. pNoonEvent->szSystemManufacturer[0] = 0;
  1747. pNoonEvent->szSystemModel[ 0 ] = 0;
  1748. }
  1749. memoryStatus.dwLength = sizeof(MEMORYSTATUSEX);
  1750. if ( GlobalMemoryStatusEx( &memoryStatus ) )
  1751. {
  1752. pNoonEvent->ulPhysicalMemory = (ULONG)(memoryStatus.ullTotalPhys / (1024*1024));
  1753. if ( memoryStatus.ullTotalPhys % (1024*1024) != 0 )
  1754. pNoonEvent->ulPhysicalMemory ++;
  1755. }
  1756. else
  1757. {
  1758. pNoonEvent->ulPhysicalMemory = 0;
  1759. }
  1760. return dwError;
  1761. }
  1762. VOID BuildNoonEventPData()
  1763. /*++
  1764. Routine Description:
  1765. build up the Noon Event Version Information. (PDATA for the event).
  1766. Arguments:
  1767. N/A
  1768. Return Value:
  1769. N/A
  1770. Note:
  1771. --*/
  1772. {
  1773. Noon_Event_Data NoonEventData;
  1774. DWORD dwLength = MAX_PATH;
  1775. DWORD dwTemp = 0;
  1776. RtlZeroMemory( &NoonEventData, sizeof(Noon_Event_Data));
  1777. #define NOON_EVENT_VERSION L"1.1"
  1778. StringCchCopyW( NoonEventData.szVersionId, VERSION_ID_SIZE, NOON_EVENT_VERSION);
  1779. #undef NOON_EVENT_VERSION
  1780. //
  1781. // Boot Mode: 0 Normal boot
  1782. // 1 Fail-safe boot
  1783. // 2 Fail-safe with network boot
  1784. //
  1785. NoonEventData.lBootMode = GetSystemMetrics( SM_CLEANBOOT );
  1786. //
  1787. // OS Name, OS Version, OS Build Type, Build Lab String, and
  1788. // Original Install Date
  1789. //
  1790. NoonEventGetOsVersionInfo( &NoonEventData );
  1791. //
  1792. // Hardware Information
  1793. //
  1794. NoonEventGetHardwareInfo( &NoonEventData );
  1795. //
  1796. // The data will be packed as a MULIT_SZ string. (number will be converted to
  1797. // string as well.)
  1798. // sizeof(NoonEventData): counts all the static buffer size.
  1799. // two dynamic buffer : szBiosVerion + szHotFixes
  1800. // Total Number Fields
  1801. // NULL terminate after each field.
  1802. //
  1803. dwLength = sizeof(NoonEventData)
  1804. + NUM_OF_CHAR_IN_ULONG * TOTAL_NUM_IN_NOON_EVENT
  1805. + TOTAL_FIELD_IN_NOON_EVENT ;
  1806. g_NoonEventInfo.pData = (LPWSTR)GlobalAlloc(GPTR, sizeof(WCHAR) * dwLength);
  1807. if ( g_NoonEventInfo.pData )
  1808. {
  1809. StringCchPrintfW( g_NoonEventInfo.pData,
  1810. dwLength,
  1811. L"%s\r%d\r%s\r%s\r%s\r%s\r%x\r%s\r%s\r%d\r%d\r%d\r%x\r%s\r\r",
  1812. NoonEventData.szVersionId,
  1813. NoonEventData.lBootMode,
  1814. (*NoonEventData.szOSName)? NoonEventData.szOSName :UNKNOWN_STRING,
  1815. (*NoonEventData.szOSVersion)? NoonEventData.szOSVersion : UNKNOWN_STRING,
  1816. (*NoonEventData.szOSBuildType)? NoonEventData.szOSBuildType : UNKNOWN_STRING,
  1817. (*NoonEventData.szOSBuildString)? NoonEventData.szOSBuildString : UNKNOWN_STRING,
  1818. NoonEventData.ulOriginalInstallDate,
  1819. (*NoonEventData.szSystemManufacturer)? NoonEventData.szSystemManufacturer : UNKNOWN_STRING,
  1820. (*NoonEventData.szSystemModel)? NoonEventData.szSystemModel : UNKNOWN_STRING,
  1821. NoonEventData.ulSystemType,
  1822. NoonEventData.ulProcessorNum,
  1823. NoonEventData.ulPhysicalMemory,
  1824. NoonEventData.ulSystemLangID,
  1825. (*NoonEventData.szFQDN)? NoonEventData.szFQDN : UNKNOWN_STRING
  1826. );
  1827. for ( dwTemp = 0; dwTemp < dwLength - 1; dwTemp ++ )
  1828. {
  1829. if ( g_NoonEventInfo.pData[ dwTemp ] == L'\r' )
  1830. {
  1831. g_NoonEventInfo.pData[ dwTemp ] = 0;
  1832. if ( g_NoonEventInfo.pData[ dwTemp + 1 ] == L'\r' )
  1833. {
  1834. g_NoonEventInfo.pData[ ++ dwTemp ] = 0;
  1835. g_NoonEventInfo.dwNumOfWChar = (dwTemp + 1);
  1836. break;
  1837. }
  1838. }
  1839. }
  1840. }
  1841. else
  1842. {
  1843. ELF_LOG0(ERROR, "BuildNoonEventPData failed to allocate PDATA.\n");
  1844. g_NoonEventInfo.dwNumOfWChar = 0;
  1845. }
  1846. return;
  1847. }
  1848. NTSTATUS EnsureComputerName(
  1849. )
  1850. /*++
  1851. Routine Description:
  1852. This routine ensures that the computer name.
  1853. Arguments:
  1854. Return Value:
  1855. status value, STATUS_SUCCESS if all is well.
  1856. --*/
  1857. {
  1858. NTSTATUS Status;
  1859. UNICODE_STRING ValueName;
  1860. ULONG ulActualSize;
  1861. WCHAR wComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1862. DWORD dwComputerNameLen = MAX_COMPUTERNAME_LENGTH + 1;
  1863. DWORD dwLen;
  1864. BOOL bRet;
  1865. BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
  1866. PKEY_VALUE_PARTIAL_INFORMATION ValueBuffer =
  1867. (PKEY_VALUE_PARTIAL_INFORMATION) Buffer;
  1868. RtlInitUnicodeString(&ValueName, VALUE_COMPUTERNAME);
  1869. // Determine if there is a String under the eventlog key that
  1870. // contains the current name.
  1871. Status = NtQueryValueKey(hEventLogNode,
  1872. &ValueName,
  1873. KeyValuePartialInformation,
  1874. ValueBuffer,
  1875. ELF_MAX_REG_KEY_INFO_SIZE,
  1876. &ulActualSize);
  1877. if (NT_SUCCESS(Status))
  1878. {
  1879. if(ValueBuffer->DataLength != 0)
  1880. return STATUS_SUCCESS; // all is well, there is already a string
  1881. }
  1882. // Get the computer name and write it
  1883. bRet = GetComputerName(wComputerName, &dwComputerNameLen);
  1884. if(bRet == FALSE)
  1885. {
  1886. ELF_LOG1(ERROR,
  1887. "EnsureComputerName: GetComputerName failed %#x\n",
  1888. GetLastError());
  1889. return STATUS_UNSUCCESSFUL;
  1890. }
  1891. // calc size in byte including null
  1892. dwLen = sizeof(WCHAR) * (dwComputerNameLen + 1);
  1893. Status = NtSetValueKey(hEventLogNode,
  1894. &ValueName,
  1895. 0,
  1896. REG_SZ,
  1897. wComputerName,
  1898. dwLen);
  1899. if (!NT_SUCCESS(Status))
  1900. ELF_LOG1(ERROR,
  1901. "EnsureComputerName: NtSetValueKey failed %#x\n",
  1902. Status);
  1903. return Status;
  1904. }
  1905. VOID
  1906. SvcEntry_Eventlog(
  1907. DWORD argc,
  1908. LPWSTR argv[],
  1909. PSVCS_GLOBAL_DATA SvcsGlobalData,
  1910. HANDLE SvcRefHandle
  1911. )
  1912. /*++
  1913. Routine Description:
  1914. This is the main routine for the Event Logging Service.
  1915. Arguments:
  1916. Command-line arguments.
  1917. Return Value:
  1918. NONE
  1919. --*/
  1920. {
  1921. NTSTATUS Status;
  1922. OBJECT_ATTRIBUTES ObjectAttributes;
  1923. UNICODE_STRING RootRegistryNode;
  1924. UNICODE_STRING ComputerNameRegistryNode;
  1925. ULONG Win32Error = NO_ERROR;
  1926. ELF_REQUEST_RECORD FlushRequest;
  1927. BYTE Buffer[ELF_MAX_REG_KEY_INFO_SIZE];
  1928. PKEY_VALUE_FULL_INFORMATION ValueBuffer = (PKEY_VALUE_FULL_INFORMATION) Buffer;
  1929. SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
  1930. HKEY hKey;
  1931. ULONG ValueSize = sizeof(ULONG);
  1932. #if DBG
  1933. UNICODE_STRING ValueName;
  1934. ULONG ulActualSize;
  1935. #endif // DBG
  1936. g_lNumSecurityWriters = 0;
  1937. //
  1938. // Set up the object that describes the root node for the eventlog service
  1939. //
  1940. RtlInitUnicodeString(&RootRegistryNode, REG_EVENTLOG_NODE_PATH);
  1941. InitializeObjectAttributes(&ObjectAttributes,
  1942. &RootRegistryNode,
  1943. OBJ_CASE_INSENSITIVE,
  1944. NULL,
  1945. NULL);
  1946. //
  1947. // If this fails, we'll just use the defaults
  1948. //
  1949. Status = NtOpenKey(&hEventLogNode, KEY_READ | KEY_NOTIFY | KEY_SET_VALUE, &ObjectAttributes);
  1950. if (NT_SUCCESS(Status))
  1951. {
  1952. Status = EnsureComputerName();
  1953. if (!NT_SUCCESS(Status))
  1954. {
  1955. //
  1956. // Not much we can do here as we don't even have a
  1957. // SERVICE_STATUS_HANDLE at this point.
  1958. //
  1959. return;
  1960. }
  1961. }
  1962. RtlInitUnicodeString(&ComputerNameRegistryNode, REG_COMPUTERNAME_NODE_PATH);
  1963. InitializeObjectAttributes(&ObjectAttributes,
  1964. &ComputerNameRegistryNode,
  1965. OBJ_CASE_INSENSITIVE,
  1966. NULL,
  1967. NULL);
  1968. Status = NtOpenKey(&hComputerNameNode, KEY_READ | KEY_NOTIFY, &ObjectAttributes);
  1969. if (!NT_SUCCESS(Status))
  1970. {
  1971. ELF_LOG1(ERROR,
  1972. "SvcEntry_Eventlog: NtOpenKey for ComputerName failed %#x -- exiting\n",
  1973. Status);
  1974. //
  1975. // Not much we can do here as we don't even have a
  1976. // SERVICE_STATUS_HANDLE at this point.
  1977. //
  1978. return;
  1979. }
  1980. ///////////////////////////////////////////////////////
  1981. #if DBG
  1982. //
  1983. // See if there's a debug value
  1984. //
  1985. RtlInitUnicodeString(&ValueName, VALUE_DEBUG);
  1986. Status = NtQueryValueKey(hEventLogNode,
  1987. &ValueName,
  1988. KeyValuePartialInformation,
  1989. ValueBuffer,
  1990. ELF_MAX_REG_KEY_INFO_SIZE,
  1991. &ulActualSize);
  1992. if (NT_SUCCESS(Status))
  1993. {
  1994. if (((PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer)->Type == REG_DWORD)
  1995. {
  1996. ElfDebugLevel = *(LPDWORD) (((PKEY_VALUE_PARTIAL_INFORMATION) ValueBuffer)->Data);
  1997. }
  1998. }
  1999. ELF_LOG1(TRACE,
  2000. "SvcEntry_Eventlog: ElfDebugLevel = %#x\n",
  2001. ElfDebugLevel);
  2002. #endif // DBG
  2003. UNREFERENCED_PARAMETER(argc);
  2004. UNREFERENCED_PARAMETER(argv);
  2005. ElfGlobalSvcRefHandle = SvcRefHandle;
  2006. ElfGlobalData = SvcsGlobalData;
  2007. //
  2008. // Initialize the list heads for the modules and log files.
  2009. //
  2010. InitializeListHead(&LogFilesHead);
  2011. InitializeListHead(&LogModuleHead);
  2012. InitializeListHead(&QueuedEventListHead);
  2013. InitializeListHead(&QueuedMessageListHead);
  2014. //
  2015. // Initialize to 0 so that we can clean up before exiting
  2016. //
  2017. EventFlags = 0;
  2018. //
  2019. // Create the Eventlog's private heap if possible. This must be
  2020. // done before any calls to ElfpAllocateBuffer are made.
  2021. //
  2022. ElfpCreateHeap();
  2023. //
  2024. // Initialize the status data.
  2025. //
  2026. Status = ElfpInitStatus();
  2027. if (!NT_SUCCESS(Status))
  2028. {
  2029. ELF_LOG1(ERROR,
  2030. "SvcEntry_Eventlog: ElfpInitStatus failed %#x -- exiting\n",
  2031. Status);
  2032. //
  2033. // Not much we can do here as we don't even have a
  2034. // SERVICE_STATUS_HANDLE at this point.
  2035. //
  2036. return;
  2037. }
  2038. //
  2039. // Set up control handler
  2040. //
  2041. if ((ElfServiceStatusHandle = RegisterServiceCtrlHandler(
  2042. EVENTLOG_SVC_NAMEW,
  2043. ElfControlResponse)) == 0)
  2044. {
  2045. Win32Error = GetLastError();
  2046. //
  2047. // If we got an error, we need to set status to uninstalled, and end the
  2048. // thread.
  2049. //
  2050. ELF_LOG1(ERROR,
  2051. "SvcEntry_Eventlog: RegisterServiceCtrlHandler failed %#x\n",
  2052. Win32Error);
  2053. goto cleanupandexit;
  2054. }
  2055. //
  2056. // Notify the Service Controller for the first time that we are alive
  2057. // and are in a start pending state
  2058. //
  2059. // *** UPDATE STATUS ***
  2060. ElfStatusUpdate(STARTING);
  2061. //
  2062. // Get the localized title for message box popups.
  2063. //
  2064. ElfInitMessageBoxTitle();
  2065. //
  2066. // Initialize a critical section for use when adding or removing
  2067. // LogFiles or LogModules. This must be done before we process any
  2068. // file information.
  2069. //
  2070. Status = ElfpInitCriticalSection(&LogFileCritSec);
  2071. if (!NT_SUCCESS(Status))
  2072. {
  2073. ELF_LOG1(ERROR,
  2074. "SvcEntry_Eventlog: Unable to create LogFileCritSec %#x\n",
  2075. Status);
  2076. goto cleanupandexit;
  2077. }
  2078. EventFlags |= ELF_INIT_LOGFILE_CRIT_SEC;
  2079. Status = ElfpInitCriticalSection(&LogModuleCritSec);
  2080. if (!NT_SUCCESS(Status))
  2081. {
  2082. ELF_LOG1(ERROR,
  2083. "SvcEntry_Eventlog: Unable to create LogModuleCritSec %#x\n",
  2084. Status);
  2085. goto cleanupandexit;
  2086. }
  2087. EventFlags |= ELF_INIT_LOGMODULE_CRIT_SEC;
  2088. Status = ElfpInitCriticalSection(&QueuedEventCritSec);
  2089. if (!NT_SUCCESS(Status))
  2090. {
  2091. ELF_LOG1(ERROR,
  2092. "SvcEntry_Eventlog: Unable to create QueuedEventCritSec %#x\n",
  2093. Status);
  2094. goto cleanupandexit;
  2095. }
  2096. EventFlags |= ELF_INIT_QUEUED_EVENT_CRIT_SEC;
  2097. Status = ElfpInitCriticalSection(&QueuedMessageCritSec);
  2098. if (!NT_SUCCESS(Status))
  2099. {
  2100. ELF_LOG1(ERROR,
  2101. "SvcEntry_Eventlog: Unable to create QueuedMessageCritSec %#x\n",
  2102. Status);
  2103. goto cleanupandexit;
  2104. }
  2105. EventFlags |= ELF_INIT_QUEUED_MESSAGE_CRIT_SEC;
  2106. //
  2107. // Set up the data structures for the Logfiles and Modules.
  2108. //
  2109. Status = ElfSetUpConfigDataStructs();
  2110. if (!NT_SUCCESS(Status))
  2111. {
  2112. ELF_LOG1(ERROR,
  2113. "SvcEntry_Eventlog: ElfSetUpConfigDataStructs failed %#x\n",
  2114. Status);
  2115. goto cleanupandexit;
  2116. }
  2117. //
  2118. // Tell service controller that we are making progress
  2119. //
  2120. ElfStatusUpdate(STARTING);
  2121. //
  2122. // Initialize a critical section for use when adding or removing
  2123. // context handles (LogHandles).
  2124. //
  2125. Status = ElfpInitCriticalSection(&LogHandleCritSec);
  2126. if (!NT_SUCCESS(Status))
  2127. {
  2128. ELF_LOG1(ERROR,
  2129. "SvcEntry_Eventlog: Unable to create LogHandleCritSec %#x\n",
  2130. Status);
  2131. goto cleanupandexit;
  2132. }
  2133. EventFlags |= ELF_INIT_LOGHANDLE_CRIT_SEC;
  2134. //
  2135. // Initialize the context handle (log handle) list.
  2136. //
  2137. InitializeListHead( &LogHandleListHead );
  2138. //
  2139. // Initialize the Global Resource.
  2140. //
  2141. Status = ElfpInitResource(&GlobalElfResource);
  2142. if (!NT_SUCCESS(Status))
  2143. {
  2144. ELF_LOG1(ERROR,
  2145. "SvcEntry_Eventlog: Unable to create GlobalElfResource %#x\n",
  2146. Status);
  2147. goto cleanupandexit;
  2148. }
  2149. EventFlags |= ELF_INIT_GLOBAL_RESOURCE;
  2150. //
  2151. //Initialize a CritSec for clustering support
  2152. //
  2153. Status = ElfpInitCriticalSection(&gClPropCritSec);
  2154. if (!NT_SUCCESS(Status))
  2155. {
  2156. ELF_LOG1(ERROR,
  2157. "SvcEntry_Eventlog: Unable to create gClPropCritSec %#x\n",
  2158. Status);
  2159. goto cleanupandexit;
  2160. }
  2161. EventFlags |= ELF_INIT_CLUS_CRIT_SEC;
  2162. //
  2163. // Tell service controller that we are making progress
  2164. //
  2165. ElfStatusUpdate(STARTING);
  2166. // Create a thread for watching the LPC port.
  2167. //
  2168. if (!StartLPCThread())
  2169. {
  2170. ELF_LOG0(ERROR,
  2171. "SvcEntry_Eventlog: StartLPCThread failed\n");
  2172. Status = STATUS_UNSUCCESSFUL;
  2173. goto cleanupandexit;
  2174. }
  2175. EventFlags |= ELF_STARTED_LPC_THREAD;
  2176. //
  2177. // Tell service controller of that we are making progress
  2178. //
  2179. ElfStatusUpdate(STARTING);
  2180. //
  2181. // Create a thread for watching for changes in the registry.
  2182. //
  2183. if (!ElfStartRegistryMonitor())
  2184. {
  2185. ELF_LOG0(ERROR,
  2186. "SvcEntry_Eventlog: ElfStartRegistryMonitor failed\n");
  2187. Status = STATUS_UNSUCCESSFUL;
  2188. goto cleanupandexit;
  2189. }
  2190. EventFlags |= ELF_STARTED_REGISTRY_MONITOR;
  2191. //
  2192. // Setup NoonEvent PData
  2193. //
  2194. BuildNoonEventPData();
  2195. //
  2196. // if this is setup, then dont do the periodic timestamp writting
  2197. // Setup has the feature where the last write is ignored and so
  2198. // the code acted as if a dirty shutdown happened.
  2199. //
  2200. if(!SvcsGlobalData->fSetupInProgress)
  2201. {
  2202. //
  2203. // < Not in Setup >
  2204. // Read from the registry to determine the time stamp
  2205. // interval, default to 5 minutes
  2206. //
  2207. g_PreviousInterval = GetNoonEventTimeStamp();
  2208. }
  2209. else
  2210. {
  2211. g_PreviousInterval = 0;
  2212. }
  2213. //
  2214. // Tell service controller of that we are making progress
  2215. //
  2216. ElfStatusUpdate(STARTING);
  2217. //
  2218. // Write out an event that says we started
  2219. //
  2220. ElfWriteNoonEvent(EVENT_EventlogStarted,
  2221. g_PreviousInterval );
  2222. //
  2223. // Write a boot event with version info
  2224. //
  2225. ElfWriteProductInfoEvent();
  2226. // Write a computer name change event if that is applicable
  2227. ElfCheckForComputerNameChange();
  2228. //
  2229. // If this is setup, then dont do the periodic timestamp writting
  2230. // Setup has the feature where the last write is ignored and so
  2231. // the code acted as if a dirty shutdown happened.
  2232. //
  2233. if(SvcsGlobalData->fSetupInProgress)
  2234. {
  2235. ElfWriteTimeStamp(EVENT_NormalShutdown,
  2236. FALSE); // clears out the time stamp.
  2237. }
  2238. if (g_PreviousInterval != 0)
  2239. {
  2240. //
  2241. // Write out the first timer based abnormal shutdown time stamp
  2242. //
  2243. ElfWriteTimeStamp (EVENT_AbNormalShutdown, TRUE);
  2244. }
  2245. //
  2246. // Write out any events that were queued up during initialization
  2247. //
  2248. FlushRequest.Command = ELF_COMMAND_WRITE_QUEUED;
  2249. ElfPerformRequest(&FlushRequest);
  2250. //
  2251. // Tell service controller that we are making progress
  2252. //
  2253. ElfStatusUpdate(STARTING);
  2254. //
  2255. // Finish setting up the RPC server
  2256. //
  2257. // NOTE: Now all RPC servers in services.exe share the same pipe name.
  2258. // However, in order to support communication with version 1.0 of WinNt,
  2259. // it is necessary for the Client Pipe name to remain the same as
  2260. // it was in version 1.0. Mapping to the new name is performed in
  2261. // the Named Pipe File System code.
  2262. //
  2263. Status = ElfGlobalData->StartRpcServer(
  2264. ElfGlobalData->SvcsRpcPipeName,
  2265. eventlog_ServerIfHandle);
  2266. if (!NT_SUCCESS(Status))
  2267. {
  2268. ELF_LOG1(ERROR,
  2269. "SvcEntry_Eventlog: StartRpcServer failed %#x\n",
  2270. Status);
  2271. goto cleanupandexit;
  2272. }
  2273. //
  2274. // Tell service controller that we are making progress
  2275. //
  2276. ElfStatusUpdate(RUNNING);
  2277. EventFlags |= ELF_STARTED_RPC_SERVER;
  2278. if (GetElState() == RUNNING)
  2279. {
  2280. //
  2281. // Create a thread to periodically write
  2282. // a time stamp to the registry.
  2283. //
  2284. g_hTimestampEvent = CreateEvent (NULL, TRUE, FALSE, NULL);
  2285. if (g_hTimestampEvent != NULL)
  2286. {
  2287. if ( g_PreviousInterval != 0 )
  2288. {
  2289. InterlockedExchange( &g_TimeStampEnabled, TIME_STAMP_ENABLED );
  2290. Status = RtlRegisterWait(&g_hTimestampWorkitem,
  2291. g_hTimestampEvent,
  2292. TimeStampProc, // Callback
  2293. (PVOID) UlongToPtr(g_PreviousInterval), // Context
  2294. 0, // Timeout
  2295. WT_EXECUTEONLYONCE);
  2296. if (!NT_SUCCESS(Status))
  2297. {
  2298. ELF_LOG1(ERROR,
  2299. "SvcEntry_Eventlog: RtlRegisterWait failed %#x\n",
  2300. Status);
  2301. InterlockedExchange( &g_TimeStampEnabled, TIME_STAMP_DISABLED );
  2302. }
  2303. }
  2304. if(!SvcsGlobalData->fSetupInProgress)
  2305. {
  2306. //
  2307. // start the NoonEvent Proc if it is not in a setup
  2308. //
  2309. Status = RtlRegisterWait(&g_hNoonEventWorkitem,
  2310. g_hTimestampEvent,
  2311. NoonEventProc, // Callback
  2312. (PVOID) NULL, // Context
  2313. GetNextNoonEventDelay() * 1000, // Timeout
  2314. WT_EXECUTEONLYONCE);
  2315. if (!NT_SUCCESS(Status))
  2316. {
  2317. ELF_LOG1(ERROR,
  2318. "SvcEntry_Eventlog: RtlRegisterWait failed %#x\n",
  2319. Status);
  2320. }
  2321. }
  2322. }
  2323. else
  2324. {
  2325. ELF_LOG1(ERROR,
  2326. "SvcEntry_Eventlog: CreateEvent for timestamp failed %d\n",
  2327. GetLastError());
  2328. }
  2329. ELF_LOG0(TRACE,
  2330. "SvcEntry_Eventlog: Service running -- main thread returning\n");
  2331. return;
  2332. }
  2333. cleanupandexit:
  2334. //
  2335. // Come here if there is cleanup necessary.
  2336. //
  2337. ELF_LOG0(ERROR,
  2338. "SvcEntry_Eventlog: Exiting on error\n");
  2339. if (Win32Error == NO_ERROR)
  2340. {
  2341. Win32Error = RtlNtStatusToDosError(Status);
  2342. }
  2343. ElfBeginForcedShutdown(PENDING, Win32Error, Status);
  2344. //
  2345. // If the registry monitor has been initialized, then
  2346. // let it do the shutdown cleanup. All we need to do
  2347. // here is wake it up.
  2348. // Otherwise, this thread will do the cleanup.
  2349. //
  2350. if (EventFlags & ELF_STARTED_REGISTRY_MONITOR)
  2351. {
  2352. StopRegistryMonitor();
  2353. }
  2354. else
  2355. {
  2356. ElfpCleanUp(EventFlags);
  2357. }
  2358. return;
  2359. }
  2360. VOID
  2361. ElfInitMessageBoxTitle(
  2362. VOID
  2363. )
  2364. /*++
  2365. Routine Description:
  2366. Obtains the title text for the message box used to display messages.
  2367. If the title is successfully obtained from the message file, then
  2368. that title is pointed to by GlobalAllocatedMsgTitle and
  2369. GlobalMessageBoxTitle. If unsuccessful, then GlobalMessageBoxTitle
  2370. left pointing to the DefaultMessageBoxTitle.
  2371. NOTE: If successful, a buffer is allocated by this function. The
  2372. pointer stored in GlobalAllocatedMsgTitle and it should be freed when
  2373. done with this buffer.
  2374. Arguments:
  2375. Return Value:
  2376. none
  2377. --*/
  2378. {
  2379. LPVOID hModule;
  2380. DWORD msgSize;
  2381. //
  2382. // This function should be called only once during initialization. Note
  2383. // that it needs to be called before the Eventlog's RPC server is started
  2384. // or else it's possible for the log to fill up, which will generate a
  2385. // "log full" popup with no title (since GlobalMessageBoxTitle is NULL).
  2386. //
  2387. ASSERT(GlobalMessageBoxTitle == NULL);
  2388. hModule = LoadLibraryEx(L"netevent.dll",
  2389. NULL,
  2390. LOAD_LIBRARY_AS_DATAFILE);
  2391. if ( hModule == NULL)
  2392. {
  2393. ELF_LOG1(ERROR,
  2394. "ElfInitMessageBoxTitle: LoadLibrary of netevent.dll failed %d\n",
  2395. GetLastError());
  2396. return;
  2397. }
  2398. msgSize = FormatMessageW(
  2399. FORMAT_MESSAGE_FROM_HMODULE | // dwFlags
  2400. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  2401. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  2402. hModule,
  2403. TITLE_EventlogMessageBox, // MessageId
  2404. 0, // dwLanguageId
  2405. (LPWSTR) &GlobalMessageBoxTitle, // lpBuffer
  2406. 0, // nSize
  2407. NULL);
  2408. if (msgSize == 0)
  2409. {
  2410. ELF_LOG2(ERROR,
  2411. "ElfInitMessageBoxTitle: FormatMessage failed %d -- using %ws\n",
  2412. GetLastError(),
  2413. ELF_DEFAULT_MESSAGE_BOX_TITLE);
  2414. GlobalMessageBoxTitle = ELF_DEFAULT_MESSAGE_BOX_TITLE;
  2415. bGlobalMessageBoxTitleNeedFree = FALSE;
  2416. }
  2417. else
  2418. bGlobalMessageBoxTitleNeedFree = TRUE;
  2419. FreeLibrary(hModule);
  2420. return;
  2421. }
  2422. #ifdef EXIT_PROCESS
  2423. //
  2424. // This code is compiled into the Eventlog to track down a DLL that's loaded
  2425. // into services.exe and calls ExitProcess. Since this DLL should never be
  2426. // unloaded, we break into the debugger on DLL_PROCESS_DETACH. To use this,
  2427. // the following need to be added to the sources file:
  2428. //
  2429. // DLLENTRY= DllInit
  2430. //
  2431. // -DEXIT_PROCESS (to the C_DEFINES line)
  2432. //
  2433. BOOL
  2434. DllInit(
  2435. IN HINSTANCE hDll,
  2436. IN DWORD dwReason,
  2437. IN PCONTEXT pContext OPTIONAL
  2438. )
  2439. {
  2440. switch (dwReason) {
  2441. case DLL_PROCESS_ATTACH:
  2442. //
  2443. // No notification of THREAD_ATTACH and THREAD_DETACH
  2444. //
  2445. DisableThreadLibraryCalls(hDll);
  2446. break;
  2447. case DLL_PROCESS_DETACH:
  2448. //
  2449. // This should NEVER happen -- it means services.exe
  2450. // is exiting via an ExitProcess call
  2451. //
  2452. DebugBreak();
  2453. break;
  2454. }
  2455. return TRUE;
  2456. }
  2457. #endif // EXIT_PROCESS