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.

4572 lines
151 KiB

  1. /*++
  2. Copyright (c) 1990-1994 Microsoft Corporation
  3. Module Name:
  4. operate.c
  5. Abstract:
  6. This file contains all the routines to perform operations on the
  7. log files. They are called by the thread that performs requests.
  8. Author:
  9. Rajen Shah (rajens) 16-Jul-1991
  10. Revision History:
  11. 04-Apr-1995 MarkBl
  12. Resets the file archive attribute on log write. The backup caller
  13. clears it.
  14. 29-Aug-1994 Danl
  15. We no longer grow log files in place. Therefore, the ExtendSize
  16. function will allocate a block that is as large as the old size plus
  17. the size of the new block that must be added. If this allocation
  18. succeeds, then it will free up the old block. If a failure occurs,
  19. we continue to use the old block as if we have already grown as much
  20. as we can.
  21. 22-Jul-1994 Danl
  22. ValidFilePos: Changed test for pEndRecordLen > PhysicalEOF
  23. so that it uses >=. In the case where pEndRecordLen == PhysicalEOF,
  24. we want to wrap to find the last DWORD at the beginning of the File
  25. (after the header).
  26. 08-Jul-1994 Danl
  27. PerformWriteRequest: Fixed overwrite logic so that in the case where
  28. a log is set up for always-overwrite, that we never go down the branch
  29. that indicates the log was full. Previously, it would go down that
  30. branch if the current time was less than the log time (ie. someone
  31. set the clock back).
  32. 18-Apr-2001 a-jyotig
  33. IsPositionWithinRange function changed to take 2 additional parameters
  34. EOF and Base Address (BOF) and check if the position is between EOF
  35. and BOF
  36. --*/
  37. /****
  38. @doc EXTERNAL INTERFACES EVTLOG
  39. ****/
  40. //
  41. // INCLUDES
  42. //
  43. #include <eventp.h>
  44. #include <alertmsg.h> // ALERT_ELF manifests
  45. #include "elfmsg.h"
  46. #include <strsafe.h>
  47. #define OVERWRITE_AS_NEEDED 0x00000000
  48. #define NEVER_OVERWRITE 0xffffffff
  49. //
  50. // Prototypes
  51. //
  52. VOID PerformClearRequest(PELF_REQUEST_RECORD Request);
  53. BOOL
  54. IsPositionWithinRange(
  55. PVOID Position,
  56. PVOID BeginningRecord,
  57. PVOID EndingRecord,
  58. PVOID PhysEOF,
  59. PVOID BaseAddress
  60. );
  61. VOID
  62. ElfExtendFile (
  63. PLOGFILE pLogFile,
  64. ULONG SpaceNeeded,
  65. PULONG SpaceAvail
  66. )
  67. /*++
  68. Routine Description:
  69. This routine takes an open log file and extends the file and underlying
  70. section and view if possible. If it can't be grown, it caps the file
  71. at this size by setting the ConfigMaxFileSize to the Actual. It also
  72. updates the SpaceAvail parm which is used in PerformWriteRequest (the
  73. caller).
  74. Arguments:
  75. pLogFile - pointer to a LOGFILE structure for the open logfile
  76. ExtendAmount - How much bigger to make the file/section/view
  77. SpaceAvail - Update this with how much space was added to the section
  78. Return Value:
  79. None - If we can't extend the file, we just cap it at this size for the
  80. duration of this boot. We'll try again the next time the eventlog
  81. is closed and reopened.
  82. Note:
  83. ExtendAmount should always be granular to 64K.
  84. --*/
  85. {
  86. LARGE_INTEGER NewSize;
  87. NTSTATUS Status;
  88. PVOID BaseAddress;
  89. SIZE_T Size;
  90. IO_STATUS_BLOCK IoStatusBlock;
  91. //
  92. // Calculate how much to grow the file then extend the section by
  93. // that amount. Do this in 64K chunks.
  94. //
  95. SpaceNeeded = ((SpaceNeeded - *SpaceAvail) & 0xFFFF0000) + 0x10000;
  96. if (SpaceNeeded > (pLogFile->ConfigMaxFileSize - pLogFile->ActualMaxFileSize))
  97. {
  98. //
  99. // We can't grow it by the full amount we need. Grow
  100. // it to the max size and let file wrap take over.
  101. // If there isn't any room to grow, then return;
  102. //
  103. SpaceNeeded = pLogFile->ConfigMaxFileSize - pLogFile->ActualMaxFileSize;
  104. if (SpaceNeeded == 0)
  105. {
  106. return;
  107. }
  108. }
  109. NewSize = RtlConvertUlongToLargeInteger(pLogFile->ActualMaxFileSize + SpaceNeeded);
  110. //
  111. // Update the file size information, extend the section, and map the
  112. // new section
  113. //
  114. Status = NtSetInformationFile(pLogFile->FileHandle,
  115. &IoStatusBlock,
  116. &NewSize,
  117. sizeof(NewSize),
  118. FileEndOfFileInformation);
  119. if (!NT_SUCCESS(Status))
  120. {
  121. ELF_LOG2(ERROR,
  122. "ElfExtendFile: NtSetInformationFile for %ws log failed %#x\n",
  123. pLogFile->LogModuleName->Buffer,
  124. Status);
  125. goto ErrorExit;
  126. }
  127. Status = NtExtendSection(pLogFile->SectionHandle, &NewSize);
  128. if (!NT_SUCCESS(Status))
  129. {
  130. ELF_LOG2(ERROR,
  131. "ElfExtendFile: NtExtendSection for %ws log failed %#x\n",
  132. pLogFile->LogModuleName->Buffer,
  133. Status);
  134. goto ErrorExit;
  135. }
  136. //
  137. // Now that the section is extended, we need to map the new section.
  138. //
  139. //
  140. // Map a view of the entire section (with the extension).
  141. // Allow the allocator to tell us where it is located, and
  142. // what the size is.
  143. //
  144. BaseAddress = NULL;
  145. Size = 0;
  146. Status = NtMapViewOfSection(pLogFile->SectionHandle,
  147. NtCurrentProcess(),
  148. &BaseAddress,
  149. 0,
  150. 0,
  151. NULL,
  152. &Size,
  153. ViewUnmap,
  154. 0,
  155. PAGE_READWRITE);
  156. if (!NT_SUCCESS(Status))
  157. {
  158. //
  159. // If this fails, just exit, and we will continue with the
  160. // view that we have.
  161. //
  162. ELF_LOG2(ERROR,
  163. "ElfExtendFile: NtMapViewOfSection for %ws log failed %#x\n",
  164. pLogFile->LogModuleName->Buffer,
  165. Status);
  166. goto ErrorExit;
  167. }
  168. //
  169. // Unmap the old section.
  170. //
  171. Status = NtUnmapViewOfSection(NtCurrentProcess(),
  172. pLogFile->BaseAddress);
  173. if (!NT_SUCCESS(Status))
  174. {
  175. ELF_LOG2(ERROR,
  176. "ElfExtendFile: NtUnmapeViewOfSection for %ws log failed %#x\n",
  177. pLogFile->LogModuleName->Buffer,
  178. Status);
  179. }
  180. pLogFile->BaseAddress = BaseAddress;
  181. //
  182. // We managed to extend the file, update the actual size
  183. // and space available and press on.
  184. //
  185. if (pLogFile->Flags & ELF_LOGFILE_HEADER_WRAP)
  186. {
  187. //
  188. // Since we're wrapped, we want to move the "unwrapped" portion (i.e.,
  189. // everything from the first record to the end of the old file) down to
  190. // be at the bottom of the new file
  191. //
  192. // The call below moves memory as follows:
  193. //
  194. // 1. Destination -- PhysicalEOF - the size of the region
  195. // 2. Source -- Address of the start of the first record
  196. // 3. Size -- Num. bytes in the old file -
  197. // offset of the first record
  198. //
  199. //
  200. // Note that at this point, we have the following relevant variables
  201. //
  202. // BaseAddress -- The base address of the mapped section
  203. // Size -- The size of the enlarged section
  204. // pLogFile->ViewSize -- The size of the old section
  205. // pLogfile->BeginRecord -- The offset of the first log record
  206. //
  207. //
  208. // Calculate the number of bytes to move
  209. //
  210. DWORD dwWrapSize = (DWORD)(pLogFile->ViewSize - pLogFile->BeginRecord);
  211. ELF_LOG1(FILES,
  212. "ElfExtendFile: %ws is wrapped\n",
  213. pLogFile->LogModuleName->Buffer);
  214. RtlMoveMemory((LPBYTE)BaseAddress + Size - dwWrapSize,
  215. (LPBYTE)BaseAddress + pLogFile->BeginRecord,
  216. dwWrapSize);
  217. //
  218. // We've moved the BeginRecord -- update the offset
  219. //
  220. pLogFile->BeginRecord = (ULONG)(Size - dwWrapSize);
  221. }
  222. pLogFile->ViewSize = (ULONG)Size;
  223. pLogFile->ActualMaxFileSize += SpaceNeeded;
  224. *SpaceAvail += SpaceNeeded;
  225. //
  226. // Now flush this to disk to commit it
  227. //
  228. BaseAddress = pLogFile->BaseAddress;
  229. Size = FILEHEADERBUFSIZE;
  230. Status = NtFlushVirtualMemory(NtCurrentProcess(),
  231. &BaseAddress,
  232. &Size,
  233. &IoStatusBlock);
  234. if (!NT_SUCCESS(Status))
  235. {
  236. ELF_LOG2(ERROR,
  237. "ElfExtendFile: NtFlushVirtualMemory for %ws log failed %#x\n",
  238. pLogFile->LogModuleName->Buffer,
  239. Status);
  240. }
  241. return;
  242. ErrorExit:
  243. //
  244. // Couldn't extend the section for some reason. Just wrap the file now.
  245. // Cap the file at this size, so we don't try and extend the section on
  246. // every write. The next time the eventlog service is started up it
  247. // will revert to the configured max again.
  248. //
  249. //
  250. // BUGBUG: Generate an Alert here
  251. //
  252. ELF_LOG1(ERROR,
  253. "ElfExtendFile: Couldn't extend %ws log\n",
  254. pLogFile->LogModuleName->Buffer);
  255. pLogFile->ConfigMaxFileSize = pLogFile->ActualMaxFileSize;
  256. return;
  257. }
  258. NTSTATUS
  259. CopyUnicodeToAnsiRecord (
  260. OUT PVOID Dest OPTIONAL,
  261. IN PVOID Src,
  262. OUT PVOID *NewBufPos OPTIONAL,
  263. OUT PULONG RecordSize
  264. )
  265. /*++
  266. Routine Description:
  267. This routine reads from the event log specified in the request packet.
  268. This routine uses memory mapped I/O to access the log file. This makes
  269. it much easier to move around the file.
  270. Arguments:
  271. Dest - Points to destination buffer. If NULL, calculate and return
  272. the record length without copying the record.
  273. Src - Points to the UNICODE record.
  274. NewBufPos - Gets offset in Dest buffer after record just transferred.
  275. If Dest is NULL, this is ignored.
  276. RecordSize - Gets size of this (ANSI) record.
  277. Return Value:
  278. STATUS_SUCCESS if no errors occur. Specific NTSTATUS error otherwise.
  279. Note:
  280. --*/
  281. {
  282. ANSI_STRING StringA;
  283. UNICODE_STRING StringU;
  284. PEVENTLOGRECORD SrcRecord, DestRecord;
  285. PWSTR pStringU;
  286. PVOID TempPtr;
  287. ULONG PadSize, i;
  288. ULONG zero = 0;
  289. WCHAR *SrcStrings, *DestStrings;
  290. ULONG RecordLength, *pLength;
  291. ULONG ulTempLength;
  292. NTSTATUS Status = STATUS_SUCCESS;
  293. DestRecord = (PEVENTLOGRECORD)Dest;
  294. SrcRecord = (PEVENTLOGRECORD)Src;
  295. if (DestRecord != NULL)
  296. {
  297. DestRecord->TimeGenerated = SrcRecord->TimeGenerated;
  298. DestRecord->Reserved = SrcRecord->Reserved;
  299. DestRecord->RecordNumber = SrcRecord->RecordNumber;
  300. DestRecord->TimeWritten = SrcRecord->TimeWritten;
  301. DestRecord->EventID = SrcRecord->EventID;
  302. DestRecord->EventType = SrcRecord->EventType;
  303. DestRecord->EventCategory = SrcRecord->EventCategory;
  304. DestRecord->NumStrings = SrcRecord->NumStrings;
  305. DestRecord->UserSidLength = SrcRecord->UserSidLength;
  306. DestRecord->DataLength = SrcRecord->DataLength;
  307. }
  308. //
  309. // Convert and copy over modulename
  310. //
  311. pStringU = (PWSTR)((ULONG_PTR)SrcRecord + sizeof(EVENTLOGRECORD));
  312. RtlInitUnicodeString(&StringU, pStringU);
  313. if (DestRecord != NULL)
  314. {
  315. Status = RtlUnicodeStringToAnsiString(&StringA,
  316. &StringU,
  317. TRUE);
  318. ulTempLength = StringA.MaximumLength;
  319. }
  320. else
  321. {
  322. ulTempLength = RtlUnicodeStringToAnsiSize(&StringU);
  323. }
  324. if (NT_SUCCESS(Status))
  325. {
  326. TempPtr = (PVOID)((ULONG_PTR)DestRecord + sizeof(EVENTLOGRECORD));
  327. if (DestRecord != NULL)
  328. {
  329. RtlMoveMemory ( TempPtr, StringA.Buffer, ulTempLength );
  330. RtlFreeAnsiString(&StringA);
  331. }
  332. TempPtr = (PVOID)((ULONG_PTR) TempPtr + ulTempLength);
  333. //
  334. // Convert and copy over computername
  335. //
  336. // TempPtr points to location in the destination for the computername
  337. //
  338. pStringU = (PWSTR)((ULONG_PTR)pStringU + StringU.MaximumLength);
  339. RtlInitUnicodeString ( &StringU, pStringU );
  340. if (DestRecord != NULL)
  341. {
  342. Status = RtlUnicodeStringToAnsiString (
  343. &StringA,
  344. &StringU,
  345. TRUE
  346. );
  347. ulTempLength = StringA.MaximumLength;
  348. }
  349. else
  350. {
  351. ulTempLength = RtlUnicodeStringToAnsiSize(&StringU);
  352. }
  353. if (NT_SUCCESS(Status))
  354. {
  355. if (DestRecord != NULL)
  356. {
  357. RtlMoveMemory ( TempPtr, StringA.Buffer, ulTempLength );
  358. RtlFreeAnsiString(&StringA);
  359. }
  360. TempPtr = (PVOID)((ULONG_PTR) TempPtr + ulTempLength);
  361. }
  362. }
  363. if (NT_SUCCESS(Status))
  364. {
  365. // TempPtr points to location after computername - i.e. UserSid.
  366. // Before we write out the UserSid, we ensure that we pad the
  367. // bytes so that the UserSid starts on a DWORD boundary.
  368. //
  369. PadSize = sizeof(ULONG)
  370. - (ULONG)(((ULONG_PTR)TempPtr-(ULONG_PTR)DestRecord) % sizeof(ULONG));
  371. if (DestRecord != NULL)
  372. {
  373. RtlMoveMemory (TempPtr, &zero, PadSize);
  374. TempPtr = (PVOID)((ULONG_PTR)TempPtr + PadSize);
  375. //
  376. // Copy over the UserSid.
  377. //
  378. RtlMoveMemory(TempPtr,
  379. (PVOID)((ULONG_PTR)SrcRecord + SrcRecord->UserSidOffset),
  380. SrcRecord->UserSidLength);
  381. DestRecord->UserSidOffset = (ULONG)((ULONG_PTR)TempPtr - (ULONG_PTR)DestRecord);
  382. }
  383. else
  384. {
  385. TempPtr = (PVOID)((ULONG_PTR)TempPtr + PadSize);
  386. }
  387. //
  388. // Copy over the Strings
  389. //
  390. TempPtr = (PVOID)((ULONG_PTR)TempPtr + SrcRecord->UserSidLength);
  391. SrcStrings = (WCHAR *)((ULONG_PTR)SrcRecord + (ULONG)SrcRecord->StringOffset);
  392. DestStrings = (WCHAR *)TempPtr;
  393. for (i=0; i < SrcRecord->NumStrings; i++)
  394. {
  395. RtlInitUnicodeString (&StringU, SrcStrings);
  396. if (DestRecord != NULL)
  397. {
  398. Status = RtlUnicodeStringToAnsiString(&StringA,
  399. &StringU,
  400. TRUE);
  401. ulTempLength = StringA.MaximumLength;
  402. }
  403. else
  404. {
  405. ulTempLength = RtlUnicodeStringToAnsiSize(&StringU);
  406. }
  407. if (!NT_SUCCESS(Status))
  408. {
  409. //
  410. // Bail out
  411. //
  412. return Status;
  413. }
  414. if (DestRecord != NULL)
  415. {
  416. RtlMoveMemory(DestStrings,
  417. StringA.Buffer,
  418. ulTempLength);
  419. RtlFreeAnsiString (&StringA);
  420. }
  421. DestStrings = (WCHAR*)((ULONG_PTR)DestStrings + (ULONG)ulTempLength);
  422. SrcStrings = (WCHAR*)((ULONG_PTR)SrcStrings + (ULONG)StringU.MaximumLength);
  423. }
  424. //
  425. // DestStrings points to the point after the last string copied.
  426. //
  427. if (DestRecord != NULL)
  428. {
  429. DestRecord->StringOffset = (ULONG)((ULONG_PTR)TempPtr - (ULONG_PTR)DestRecord);
  430. TempPtr = (PVOID)DestStrings;
  431. //
  432. // Copy over the binary Data
  433. //
  434. DestRecord->DataOffset = (ULONG)((ULONG_PTR)TempPtr - (ULONG_PTR)DestRecord);
  435. RtlMoveMemory(TempPtr,
  436. (PVOID)((ULONG_PTR)SrcRecord + SrcRecord->DataOffset),
  437. SrcRecord->DataLength);
  438. }
  439. else
  440. {
  441. TempPtr = (PVOID)DestStrings;
  442. }
  443. //
  444. // Now do the pad bytes.
  445. //
  446. TempPtr = (PVOID) ((ULONG_PTR) TempPtr + SrcRecord->DataLength);
  447. PadSize = sizeof(ULONG)
  448. - (ULONG) (((ULONG_PTR) TempPtr - (ULONG_PTR) DestRecord) % sizeof(ULONG));
  449. RecordLength = (ULONG) ((ULONG_PTR) TempPtr
  450. + PadSize
  451. + sizeof(ULONG)
  452. - (ULONG_PTR)DestRecord);
  453. if (DestRecord != NULL)
  454. {
  455. RtlMoveMemory (TempPtr, &zero, PadSize);
  456. pLength = (PULONG)((ULONG_PTR)TempPtr + PadSize);
  457. *pLength = RecordLength;
  458. DestRecord->Length = RecordLength;
  459. ASSERT(((ULONG_PTR) DestRecord + RecordLength) ==
  460. ((ULONG_PTR) pLength + sizeof(ULONG)));
  461. *NewBufPos = (PVOID) ((ULONG_PTR) DestRecord + RecordLength);
  462. }
  463. *RecordSize = RecordLength;
  464. }
  465. return Status;
  466. } // CopyUnicodeToAnsiRecord
  467. BOOL
  468. ValidFilePos (
  469. PVOID Position,
  470. PVOID BeginningRecord,
  471. PVOID EndingRecord,
  472. PVOID PhysicalEOF,
  473. PVOID BaseAddress,
  474. BOOL fCheckBeginEndRange
  475. )
  476. /*++
  477. Routine Description:
  478. This routine determines whether we are pointing to a valid beginning
  479. of an event record in the event log. It does this by validating
  480. the signature then comparing the length at the beginning of the record to
  481. the length at the end, both of which have to be at least the size of the
  482. fixed length portion of an eventlog record.
  483. Arguments:
  484. Position - Pointer to be verified.
  485. BeginningRecord - Pointer to the beginning record in the file.
  486. EndingRecord - Pointer to the byte after the ending record in the file.
  487. PhysicalEOF - Pointer the physical end of the log.
  488. BaseAddress - Pointer to the physical beginning of the log.
  489. Return Value:
  490. TRUE if this position is valid.
  491. Note:
  492. There is a possibility of error if a record just happens to have the
  493. ULONG at the current position the same as the value that number of
  494. bytes further on in the record. However, this is a very slim chance
  495. as it must have a valid log signature as well.
  496. --*/
  497. {
  498. PULONG pEndRecordLength;
  499. BOOL fValid = TRUE;
  500. PEVENTLOGRECORD pEventRecord;
  501. try
  502. {
  503. pEventRecord = (PEVENTLOGRECORD)Position;
  504. //
  505. // Verify that the pointer is within the range of BEGINNING->END
  506. //
  507. if ( fCheckBeginEndRange )
  508. {
  509. fValid = IsPositionWithinRange(Position,
  510. BeginningRecord,
  511. EndingRecord,
  512. PhysicalEOF,
  513. BaseAddress);
  514. }
  515. //
  516. // If the offset looks OK, then examine the lengths at the beginning
  517. // and end of the current record. If they don't match, then the position
  518. // is invalid.
  519. //
  520. if (fValid)
  521. {
  522. //
  523. // Make sure the length is a multiple number of DWORDS
  524. //
  525. if (pEventRecord->Length & 3)
  526. {
  527. fValid = FALSE;
  528. }
  529. else
  530. {
  531. pEndRecordLength = (PULONG) ((PBYTE) Position + pEventRecord->Length) - 1;
  532. //
  533. // If the file is wrapped, adjust the pointer to reflect the
  534. // portion of the record that is wrapped starting after the
  535. // header
  536. //
  537. if ((PVOID) pEndRecordLength >= PhysicalEOF)
  538. {
  539. pEndRecordLength = (PULONG) ((PBYTE) BaseAddress +
  540. ((PBYTE) pEndRecordLength - (PBYTE) PhysicalEOF) +
  541. FILEHEADERBUFSIZE);
  542. }
  543. // Do a sanity check on this pointer before dereferencing. DAVJ
  544. if ((PVOID) pEndRecordLength > PhysicalEOF)
  545. {
  546. return FALSE;
  547. }
  548. if (pEventRecord->Length == *pEndRecordLength
  549. &&
  550. pEventRecord->Length == ELFEOFRECORDSIZE)
  551. {
  552. ULONG Size;
  553. Size = min(ELFEOFUNIQUEPART,
  554. (ULONG) ((PBYTE) PhysicalEOF - (PBYTE) pEventRecord));
  555. if (RtlCompareMemory(pEventRecord,
  556. &EOFRecord,
  557. Size) == Size)
  558. {
  559. Size = ELFEOFUNIQUEPART - Size;
  560. //
  561. // If Size is non-zero, then the unique portion of
  562. // the EOF record is wrapped across the end of file.
  563. // Continue comparison at file beginning for the
  564. // remainder of the record.
  565. //
  566. if ( Size )
  567. {
  568. PBYTE pRemainder = (PBYTE) &EOFRecord + ELFEOFUNIQUEPART - Size;
  569. fValid = (RtlCompareMemory((PBYTE) BaseAddress + FILEHEADERBUFSIZE,
  570. pRemainder,
  571. Size) == Size);
  572. }
  573. }
  574. else
  575. {
  576. fValid = FALSE;
  577. }
  578. }
  579. else if ((pEventRecord->Length < sizeof(EVENTLOGRECORD))
  580. ||
  581. (pEventRecord->Reserved != ELF_LOG_FILE_SIGNATURE)
  582. ||
  583. (pEventRecord->Length != *pEndRecordLength))
  584. {
  585. fValid = FALSE;
  586. }
  587. }
  588. }
  589. }
  590. except (EXCEPTION_EXECUTE_HANDLER)
  591. {
  592. ELF_LOG2(ERROR,
  593. "ValidFilePos: Exception %#x caught validating file position %p\n",
  594. GetExceptionCode(),
  595. BeginningRecord);
  596. fValid = FALSE;
  597. }
  598. return fValid;
  599. }
  600. BOOL
  601. IsPositionWithinRange(
  602. PVOID Position,
  603. PVOID BeginningRecord,
  604. PVOID EndingRecord,
  605. PVOID PhysEOF,
  606. PVOID BaseAddress
  607. )
  608. {
  609. //
  610. // Verify that the pointer is within the range of [Beginning, End]
  611. //
  612. //This check was introduced to make sure that the position does not
  613. //cross the file boundaries. Refer to Bug #370063. If required, one
  614. //can change this check to make sure that the position lies between
  615. //PhyStart i.e. BaseAddress + FILEHEADERBUFSIZE
  616. if((Position < BaseAddress) || (Position > PhysEOF))
  617. return FALSE;
  618. else if (EndingRecord > BeginningRecord)
  619. {
  620. return ((Position >= BeginningRecord) && (Position <= EndingRecord));
  621. }
  622. else if (EndingRecord < BeginningRecord)
  623. {
  624. return ((Position >= BeginningRecord) || (Position <= EndingRecord));
  625. }
  626. //
  627. // If BeginningRecord and EndingRecord are equal, it means that the only
  628. // record in the log file is the EOF record. In that case, return FALSE
  629. // as Position isn't pointing to a valid (i.e., non-EOF) record.
  630. //
  631. return FALSE;
  632. }
  633. PVOID
  634. FindStartOfNextRecord (
  635. PVOID Position,
  636. PVOID BeginningRecord,
  637. PVOID EndingRecord,
  638. PVOID PhysicalStart,
  639. PVOID PhysicalEOF,
  640. PVOID BaseAddress
  641. )
  642. /*++
  643. Routine Description:
  644. This routine starts at Position, and finds the beginning of the next
  645. valid record, wrapping around the physical end of the file if necessary.
  646. Arguments:
  647. Position - Pointer at which to start the search.
  648. BeginningRecord - Pointer to the beginning record in the file.
  649. EndingRecord - Pointer to the byte after the ending record in the file.
  650. PhysicalStart - Pointer to the start of log information (after header)
  651. PhysicalEOF - Pointer to the physical end of the log.
  652. BaseAddress - Pointer to the physical beginning of the log.
  653. Return Value:
  654. A pointer to the start of the next valid record, NULL if there is no
  655. valid record.
  656. Note:
  657. There is a possibility of error if a record just happens to have the
  658. ULONG at the current position the same as the value that number of
  659. bytes further on in the record. However, this is a very slim chance
  660. as it must have a valid log signature as well.
  661. --*/
  662. {
  663. PULONG ptr;
  664. PULONG EndOfBlock;
  665. PULONG EndOfFile;
  666. PVOID pRecord;
  667. ULONG Size;
  668. BOOL StillLooking = TRUE;
  669. //
  670. // Search for a ULONG which matches a record signature
  671. //
  672. ptr = (PULONG) Position;
  673. EndOfBlock = EndOfFile = (PULONG) PhysicalEOF - 1;
  674. while (StillLooking)
  675. {
  676. //
  677. // Check to see if it is the EOF record
  678. //
  679. if (*ptr == ELFEOFRECORDSIZE)
  680. {
  681. //
  682. // Only scan up to the end of the file. Just compare up the
  683. // constant information
  684. //
  685. //
  686. // BUGBUG: If (End - pEvent) is less than ELFEOFUNIQUEPART,
  687. // we never validate what should be the remainder of
  688. // the EOF record at the start of the logfile
  689. //
  690. Size = min(ELFEOFUNIQUEPART,
  691. (ULONG) ((PBYTE) PhysicalEOF - (PBYTE) ptr));
  692. pRecord = CONTAINING_RECORD(ptr,
  693. ELF_EOF_RECORD,
  694. RecordSizeBeginning);
  695. if (RtlCompareMemory(pRecord,
  696. &EOFRecord,
  697. Size) == Size)
  698. {
  699. ELF_LOG1(FILES,
  700. "FindStartOfNextRecord: Found EOF record at %p\n",
  701. pRecord);
  702. //
  703. // This is the EOF record, back up to the last record
  704. //
  705. (PBYTE) pRecord -= *((PULONG) pRecord - 1);
  706. if (pRecord < PhysicalStart)
  707. {
  708. pRecord = (PBYTE) PhysicalEOF -
  709. ((PBYTE)PhysicalStart - (PBYTE)pRecord);
  710. }
  711. }
  712. if (ValidFilePos(pRecord,
  713. BeginningRecord,
  714. EndingRecord,
  715. PhysicalEOF,
  716. BaseAddress,
  717. TRUE))
  718. {
  719. ELF_LOG1(FILES,
  720. "FindStartOfNextRecord: Valid record at %p preceding EOF record\n",
  721. pRecord);
  722. return pRecord;
  723. }
  724. }
  725. //
  726. // Check to see if it is an event record
  727. //
  728. if (*ptr == ELF_LOG_FILE_SIGNATURE)
  729. {
  730. //
  731. // This is a signature, see if the containing record is valid
  732. //
  733. pRecord = CONTAINING_RECORD(ptr,
  734. EVENTLOGRECORD,
  735. Reserved);
  736. if (ValidFilePos(pRecord,
  737. BeginningRecord,
  738. EndingRecord,
  739. PhysicalEOF,
  740. BaseAddress,
  741. TRUE))
  742. {
  743. ELF_LOG1(FILES,
  744. "FindStartOfNextRecord: Valid record found at %p\n",
  745. pRecord);
  746. return pRecord;
  747. }
  748. }
  749. //
  750. // Bump to the next byte and see if we're done.
  751. //
  752. ptr++;
  753. if (ptr >= EndOfBlock)
  754. {
  755. //
  756. // Need the second test on this condition in case Position
  757. // happens to equal PhysicalEOF - 1 (EndOfBlock initial value);
  758. // without this, this loop would terminate prematurely.
  759. //
  760. if ((EndOfBlock == (PULONG) Position)
  761. &&
  762. ((PULONG) Position != EndOfFile))
  763. {
  764. //
  765. // This was the top half, so we're done
  766. //
  767. StillLooking = FALSE;
  768. ELF_LOG0(FILES,
  769. "FindStartOfNextRecord: Unsuccessfully searched "
  770. "top half of file\n");
  771. }
  772. else
  773. {
  774. //
  775. // This was the bottom half, let's look in the top half
  776. //
  777. EndOfBlock = (PULONG) Position;
  778. ptr = (PULONG) PhysicalStart;
  779. ELF_LOG0(FILES,
  780. "FindStartOfNextRecord: Unsuccessfully searched "
  781. "bottom half of file -- searching top half\n");
  782. }
  783. }
  784. }
  785. //
  786. // Didn't find a valid record
  787. //
  788. return NULL;
  789. }
  790. PVOID
  791. NextRecordPosition (
  792. ULONG ReadFlags,
  793. PVOID CurrPosition,
  794. ULONG CurrRecordLength,
  795. PVOID BeginRecord,
  796. PVOID EndRecord,
  797. PVOID PhysicalEOF,
  798. PVOID PhysStart
  799. )
  800. /*++
  801. Routine Description:
  802. This routine seeks to the beginning of the next record to be read
  803. depending on the flags in the request packet.
  804. Arguments:
  805. ReadFlags - Read forwards or backwards
  806. CurrPosition - Pointer to the current position.
  807. CurrRecordLength - Length of the record at the last position read.
  808. BeginRecord - Logical first record
  809. EndRecord - Logical last record (EOF record)
  810. PhysEOF - End of file
  811. PhysStart - Start of file pointer (following file header).
  812. Return Value:
  813. New position or NULL if invalid record.
  814. Note:
  815. --*/
  816. {
  817. PVOID NewPosition;
  818. ULONG Length;
  819. PDWORD FillDword;
  820. if (ReadFlags & EVENTLOG_FORWARDS_READ)
  821. {
  822. //
  823. // If we're pointing at the EOF record, just set the position to
  824. // the first record
  825. //
  826. if (CurrRecordLength == ELFEOFRECORDSIZE)
  827. {
  828. ELF_LOG1(FILES,
  829. "NextRecordPosition: Pointing to EOF record -- returning "
  830. "address of first record (%p)\n",
  831. BeginRecord);
  832. return BeginRecord;
  833. }
  834. NewPosition = (PVOID) ((ULONG_PTR) CurrPosition + CurrRecordLength);
  835. //
  836. // Take care of wrapping.
  837. //
  838. if (NewPosition >= PhysicalEOF)
  839. {
  840. NewPosition = (PBYTE)PhysStart
  841. + ((PBYTE) NewPosition - (PBYTE) PhysicalEOF);
  842. }
  843. //
  844. // If this is a ELF_SKIP_DWORD, skip to the top of the file
  845. //
  846. if (*(PDWORD) NewPosition == ELF_SKIP_DWORD)
  847. {
  848. NewPosition = PhysStart;
  849. }
  850. }
  851. else
  852. {
  853. //
  854. // Reading backwards.
  855. //
  856. ASSERT (ReadFlags & EVENTLOG_BACKWARDS_READ);
  857. if (CurrPosition == BeginRecord)
  858. {
  859. //
  860. // This is the "end of file" if we're reading backwards.
  861. //
  862. ELF_LOG1(FILES,
  863. "NextRecordPosition: Reading backwards and pointing to first "
  864. "record -- returning address of last record (%p)\n",
  865. EndRecord);
  866. return EndRecord;
  867. }
  868. else if (CurrPosition == PhysStart)
  869. {
  870. //
  871. // Flip to the bottom of the file, but skip and ELF_SKIP_DWORDs
  872. //
  873. FillDword = (PDWORD) PhysicalEOF; // last dword
  874. FillDword--;
  875. while (*FillDword == ELF_SKIP_DWORD)
  876. {
  877. FillDword--;
  878. }
  879. CurrPosition = (PVOID) (FillDword + 1);
  880. }
  881. Length = *((PULONG) CurrPosition - 1);
  882. if (Length < ELFEOFRECORDSIZE)
  883. {
  884. //
  885. // Bogus length, must be invalid record
  886. //
  887. ELF_LOG1(FILES,
  888. "NextRecordPosition: Invalid record length (%d) encountered\n",
  889. Length);
  890. return NULL;
  891. }
  892. NewPosition = (PBYTE) CurrPosition - Length;
  893. //
  894. // Take care of wrapping
  895. //
  896. if (NewPosition < PhysStart)
  897. {
  898. NewPosition = (PBYTE) PhysicalEOF
  899. - ((PBYTE) PhysStart - (PBYTE) NewPosition);
  900. }
  901. }
  902. return NewPosition;
  903. }
  904. NTSTATUS
  905. SeekToStartingRecord (
  906. PELF_REQUEST_RECORD Request,
  907. PVOID *ReadPosition,
  908. PVOID BeginRecord,
  909. PVOID EndRecord,
  910. PVOID PhysEOF,
  911. PVOID PhysStart
  912. )
  913. /*++
  914. Routine Description:
  915. This routine seeks to the correct position as indicated in the
  916. request packet.
  917. Arguments:
  918. Pointer to the request packet.
  919. Pointer to a pointer where the final position after the seek is returned.
  920. Return Value:
  921. NTSTATUS and new position in file.
  922. Note:
  923. This routine ensures that it is possible to seek to the position
  924. specified in the request packet. If not, then an error is returned
  925. which indicates that the file probably changed between the two
  926. READ operations, or else the record offset specified is beyond the
  927. end of the file.
  928. --*/
  929. {
  930. PVOID Position;
  931. ULONG RecordLen;
  932. ULONG NumRecordsToSeek;
  933. ULONG BytesPerRecord;
  934. ULONG NumberOfRecords;
  935. ULONG NumberOfBytes;
  936. ULONG ReadFlags;
  937. //
  938. // If the beginning and the end are the same, then there are no
  939. // entries in this file.
  940. //
  941. if (BeginRecord == EndRecord)
  942. {
  943. ELF_LOG1(FILES,
  944. "SeekToStartingRecord: %ws log is empty\n",
  945. Request->Module->ModuleName);
  946. return STATUS_END_OF_FILE;
  947. }
  948. //
  949. // Find the last position (or the "beginning" if this is the first READ
  950. // call for this handle).
  951. //
  952. if (Request->Pkt.ReadPkt->ReadFlags & EVENTLOG_SEQUENTIAL_READ)
  953. {
  954. if (Request->Pkt.ReadPkt->ReadFlags & EVENTLOG_FORWARDS_READ)
  955. {
  956. //
  957. // If this is the first READ operation, LastSeekPosition will
  958. // be zero. In that case, we set the position to the first
  959. // record (in terms of time) in the file.
  960. //
  961. if (Request->Pkt.ReadPkt->LastSeekPos == 0)
  962. {
  963. ELF_LOG1(FILES,
  964. "SeekToStartingRecord: First read (forwards) of %ws log\n",
  965. Request->Module->ModuleName);
  966. Position = BeginRecord;
  967. }
  968. else
  969. {
  970. Position = (PBYTE) Request->LogFile->BaseAddress
  971. + Request->Pkt.ReadPkt->LastSeekPos;
  972. //
  973. // If we're changing the direction we're reading, skip
  974. // forward one record. This is because we're pointing at
  975. // the "next" record based on the last read direction
  976. //
  977. if (!(Request->Pkt.ReadPkt->Flags & ELF_LAST_READ_FORWARD))
  978. {
  979. Position = NextRecordPosition(Request->Pkt.ReadPkt->ReadFlags,
  980. Position,
  981. ((PEVENTLOGRECORD) Position)->Length,
  982. BeginRecord,
  983. EndRecord,
  984. PhysEOF,
  985. PhysStart);
  986. }
  987. else
  988. {
  989. //
  990. // This *really* cheesy check exists to handle the case
  991. // where Position could be on an ELF_SKIP_DWORD pad
  992. // dword at end of the file.
  993. //
  994. // NB: Must be prepared to handle an exception since
  995. // a somewhat unknown pointer is dereferenced.
  996. //
  997. NTSTATUS Status = STATUS_SUCCESS;
  998. try
  999. {
  1000. if (IsPositionWithinRange(Position,
  1001. BeginRecord,
  1002. EndRecord,
  1003. PhysEOF,
  1004. Request->LogFile->BaseAddress))
  1005. {
  1006. //
  1007. // If this is an ELF_SKIP_DWORD, skip to the
  1008. // top of the file.
  1009. //
  1010. if (*(PDWORD) Position == ELF_SKIP_DWORD)
  1011. {
  1012. ELF_LOG1(FILES,
  1013. "SeekToStartingRecord: Next forward read position "
  1014. "in %ws log is on an ELF_SKIP_DWORD\n",
  1015. Request->Module->ModuleName);
  1016. Position = PhysStart;
  1017. }
  1018. }
  1019. else
  1020. {
  1021. //
  1022. // More likely the caller's handle was invalid
  1023. // if the position was not within range.
  1024. //
  1025. ELF_LOG1(ERROR,
  1026. "SeekToStartingRecord: Next forward read position "
  1027. "in %ws log is out of range -- log is corrupt\n",
  1028. Request->Module->ModuleName);
  1029. Status = STATUS_INVALID_HANDLE;
  1030. }
  1031. }
  1032. except (EXCEPTION_EXECUTE_HANDLER)
  1033. {
  1034. ELF_LOG2(ERROR,
  1035. "SeekToStartingRecord: Caught exception %#x looking for "
  1036. "next forward read position in %ws log\n",
  1037. GetExceptionCode(),
  1038. Request->Module->ModuleName);
  1039. Status = STATUS_EVENTLOG_FILE_CORRUPT;
  1040. }
  1041. if (!NT_SUCCESS(Status))
  1042. {
  1043. *ReadPosition = NULL;
  1044. return Status;
  1045. }
  1046. }
  1047. }
  1048. }
  1049. else
  1050. {
  1051. //
  1052. // READ backwards
  1053. //
  1054. // If this is the first READ operation, LastSeekPosition will
  1055. // be zero. In that case, we set the position to the last
  1056. // record (in terms of time) in the file.
  1057. //
  1058. if (Request->Pkt.ReadPkt->LastSeekPos == 0)
  1059. {
  1060. ELF_LOG1(FILES,
  1061. "SeekToStartingRecord: First read (backwards) of %ws log\n",
  1062. Request->Module->ModuleName);
  1063. Position = EndRecord;
  1064. //
  1065. // Subtract the length of the last record from the current
  1066. // position to get to the beginning of the record.
  1067. //
  1068. // If that moves beyond the physical beginning of the file,
  1069. // then we need to wrap around to the physical end of the file.
  1070. //
  1071. Position = (PBYTE) Position - *((PULONG) Position - 1);
  1072. if (Position < PhysStart)
  1073. {
  1074. Position = (PBYTE) PhysEOF - ((PBYTE) PhysStart - (PBYTE) Position);
  1075. }
  1076. }
  1077. else
  1078. {
  1079. Position = (PBYTE) Request->LogFile->BaseAddress
  1080. + Request->Pkt.ReadPkt->LastSeekPos;
  1081. //
  1082. // If we're changing the direction we're reading, skip
  1083. // forward one record. This is because we're pointing at
  1084. // the "next" record based on the last read direction
  1085. //
  1086. if (Request->Pkt.ReadPkt->Flags & ELF_LAST_READ_FORWARD)
  1087. {
  1088. Position = NextRecordPosition(Request->Pkt.ReadPkt->ReadFlags,
  1089. Position,
  1090. 0, // not used if reading backwards
  1091. BeginRecord,
  1092. EndRecord,
  1093. PhysEOF,
  1094. PhysStart);
  1095. }
  1096. }
  1097. }
  1098. }
  1099. else if (Request->Pkt.ReadPkt->ReadFlags & EVENTLOG_SEEK_READ)
  1100. {
  1101. //
  1102. // Make sure the record number passed in is valid
  1103. //
  1104. if (Request->Pkt.ReadPkt->RecordNumber < Request->LogFile->OldestRecordNumber
  1105. ||
  1106. Request->Pkt.ReadPkt->RecordNumber >= Request->LogFile->CurrentRecordNumber)
  1107. {
  1108. ELF_LOG1(ERROR,
  1109. "SeekToStartingRecord: Invalid record number %d\n",
  1110. Request->Pkt.ReadPkt->RecordNumber);
  1111. return STATUS_INVALID_PARAMETER;
  1112. }
  1113. //
  1114. // We're seeking to an absolute record number, so use the following
  1115. // algorithm:
  1116. //
  1117. // 1. Calculate the average number of bytes per record
  1118. //
  1119. // 2. Based on this number seek to where the record should start
  1120. //
  1121. // 3. Find the start of the next record in the file
  1122. //
  1123. // 4. Walk (forwards or backwards) from there to the right record
  1124. //
  1125. //
  1126. // 1. Calculate the average number of bytes per record
  1127. //
  1128. NumberOfRecords = Request->LogFile->CurrentRecordNumber
  1129. - Request->LogFile->OldestRecordNumber;
  1130. NumberOfBytes = Request->LogFile->Flags & ELF_LOGFILE_HEADER_WRAP ?
  1131. Request->LogFile->ActualMaxFileSize :
  1132. Request->LogFile->EndRecord;
  1133. NumberOfBytes -= FILEHEADERBUFSIZE;
  1134. BytesPerRecord = NumberOfBytes / NumberOfRecords;
  1135. //
  1136. // 2. Calcuate the first guess as to what the offset of the desired
  1137. // record should be
  1138. //
  1139. Position = (PBYTE) Request->LogFile->BaseAddress
  1140. + Request->LogFile->BeginRecord
  1141. + BytesPerRecord
  1142. * (Request->Pkt.ReadPkt->RecordNumber
  1143. - Request->LogFile->OldestRecordNumber);
  1144. //
  1145. // Align the position to a ULONG bountry.
  1146. //
  1147. Position = (PVOID) (((ULONG_PTR) Position + sizeof(ULONG) - 1) & ~(sizeof(ULONG) - 1));
  1148. //
  1149. // Take care of file wrap
  1150. //
  1151. if (Position >= PhysEOF)
  1152. {
  1153. Position = (PBYTE)PhysStart +
  1154. ((PBYTE) Position - (PBYTE) PhysEOF);
  1155. if (Position >= PhysEOF)
  1156. {
  1157. //
  1158. // It's possible, in an obscure error case, that Position
  1159. // may still be beyond the EOF. Adjust, if so.
  1160. //
  1161. Position = BeginRecord;
  1162. }
  1163. }
  1164. //
  1165. // Bug fix:
  1166. //
  1167. // 57017 - Event Log Causes Services.Exe to Access Violate therefore
  1168. // Hanging the Server
  1169. //
  1170. // The calculation above can easily put Position out of range of
  1171. // the begin/end file markers. This is not good. Adjust Position,
  1172. // if necessary.
  1173. //
  1174. if (BeginRecord < EndRecord && Position >= EndRecord)
  1175. {
  1176. Position = BeginRecord;
  1177. }
  1178. else if (BeginRecord > EndRecord && Position >= EndRecord && Position < BeginRecord)
  1179. {
  1180. Position = BeginRecord;
  1181. }
  1182. else
  1183. {
  1184. // Do nothing.
  1185. }
  1186. //
  1187. // 3. Get to the start of the next record after Position
  1188. //
  1189. Position = FindStartOfNextRecord(Position,
  1190. BeginRecord,
  1191. EndRecord,
  1192. PhysStart,
  1193. PhysEOF,
  1194. Request->LogFile->BaseAddress);
  1195. //
  1196. // 4. Walk (forwards or backwards) from Position to the right record
  1197. //
  1198. if (Position)
  1199. {
  1200. if (Request->Pkt.ReadPkt->RecordNumber >
  1201. ((PEVENTLOGRECORD) Position)->RecordNumber)
  1202. {
  1203. NumRecordsToSeek = Request->Pkt.ReadPkt->RecordNumber
  1204. - ((PEVENTLOGRECORD) Position)->RecordNumber;
  1205. ReadFlags = EVENTLOG_FORWARDS_READ;
  1206. ELF_LOG2(FILES,
  1207. "SeekToStartingRecord: Walking forward %d records from record %d\n",
  1208. NumRecordsToSeek,
  1209. ((PEVENTLOGRECORD) Position)->RecordNumber);
  1210. }
  1211. else
  1212. {
  1213. NumRecordsToSeek = ((PEVENTLOGRECORD) Position)->RecordNumber
  1214. - Request->Pkt.ReadPkt->RecordNumber;
  1215. ReadFlags = EVENTLOG_BACKWARDS_READ;
  1216. ELF_LOG2(FILES,
  1217. "SeekToStartingRecord: Walking backward %d records from record %d\n",
  1218. NumRecordsToSeek,
  1219. ((PEVENTLOGRECORD) Position)->RecordNumber);
  1220. }
  1221. }
  1222. while (Position != NULL && NumRecordsToSeek--)
  1223. {
  1224. RecordLen = ((PEVENTLOGRECORD) Position)->Length;
  1225. Position = NextRecordPosition(ReadFlags,
  1226. Position,
  1227. RecordLen,
  1228. BeginRecord,
  1229. EndRecord,
  1230. PhysEOF,
  1231. PhysStart);
  1232. }
  1233. }
  1234. else
  1235. {
  1236. //
  1237. // Flags didn't specify a sequential or seek read
  1238. //
  1239. return STATUS_INVALID_PARAMETER;
  1240. }
  1241. *ReadPosition = Position; // This is the new seek position
  1242. if (!Position)
  1243. {
  1244. //
  1245. // The record was invalid
  1246. //
  1247. ELF_LOG1(ERROR,
  1248. "SeekToStartingRecord: Position is NULL -- %ws log is corrupt\n",
  1249. Request->Module->ModuleName);
  1250. return STATUS_EVENTLOG_FILE_CORRUPT;
  1251. }
  1252. return STATUS_SUCCESS;
  1253. }
  1254. VOID
  1255. CopyRecordToBuffer(
  1256. IN PBYTE pReadPosition,
  1257. IN OUT PBYTE *ppBufferPosition,
  1258. IN ULONG ulRecordSize,
  1259. IN PBYTE pPhysicalEOF,
  1260. IN PBYTE pPhysStart
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. This routine copies the EVENTLOGRECORD at pReadPosition into
  1265. *ppBufferPosition
  1266. Return Value:
  1267. None.
  1268. --*/
  1269. {
  1270. ULONG ulBytesToMove; // Number of bytes to copy
  1271. ASSERT(ppBufferPosition != NULL);
  1272. //
  1273. // If the number of bytes to the end of the file is less than the
  1274. // size of the record, then part of the record has wrapped to the
  1275. // beginning of the file - transfer the bytes piece-meal.
  1276. //
  1277. // Otherwise, transfer the whole record.
  1278. //
  1279. ulBytesToMove = min(ulRecordSize,
  1280. (ULONG) (pPhysicalEOF - pReadPosition));
  1281. if (ulBytesToMove < ulRecordSize)
  1282. {
  1283. //
  1284. // We need to copy the bytes up to the end of the file,
  1285. // and then wrap around and copy the remaining bytes of
  1286. // this record.
  1287. //
  1288. RtlMoveMemory(*ppBufferPosition, pReadPosition, ulBytesToMove);
  1289. //
  1290. // Advance user buffer pointer, move read position to the
  1291. // beginning of the file (past the file header), and
  1292. // update bytes remaining to be moved for this record.
  1293. //
  1294. *ppBufferPosition += ulBytesToMove;
  1295. pReadPosition = pPhysStart;
  1296. ulBytesToMove = ulRecordSize - ulBytesToMove; // Remaining bytes
  1297. }
  1298. //
  1299. // Move the remaining bytes of the record OR the full record.
  1300. //
  1301. RtlMoveMemory(*ppBufferPosition, pReadPosition, ulBytesToMove);
  1302. //
  1303. // Update to new read positions
  1304. //
  1305. *ppBufferPosition += ulBytesToMove;
  1306. }
  1307. NTSTATUS
  1308. ReadFromLog(
  1309. PELF_REQUEST_RECORD Request
  1310. )
  1311. /*++
  1312. Routine Description:
  1313. This routine reads from the event log specified in the request packet.
  1314. This routine uses memory mapped I/O to access the log file. This makes
  1315. it much easier to move around the file.
  1316. Arguments:
  1317. Pointer to the request packet.
  1318. Return Value:
  1319. NTSTATUS.
  1320. Note:
  1321. --*/
  1322. {
  1323. NTSTATUS Status;
  1324. PVOID ReadPosition; // Current read position in file
  1325. PVOID BufferPosition; // Current position in user's buffer
  1326. ULONG TotalBytesRead; // Total Bytes transferred
  1327. ULONG TotalRecordsRead; // Total records transferred
  1328. ULONG BytesInBuffer; // Bytes remaining in buffer
  1329. ULONG RecordSize; // Size of event record
  1330. PVOID PhysicalEOF; // Physical end of file
  1331. PVOID PhysStart; // Physical start of file (after file hdr)
  1332. PVOID BeginRecord; // Points to first record
  1333. PVOID EndRecord; // Points to byte after last record
  1334. PVOID TempBuf = NULL, TempBufferPosition;
  1335. ULONG RecordBytesTransferred;
  1336. PEVENTLOGRECORD pEvent;
  1337. //
  1338. // Initialize variables.
  1339. //
  1340. BytesInBuffer = Request->Pkt.ReadPkt->BufferSize;
  1341. BufferPosition = Request->Pkt.ReadPkt->Buffer;
  1342. TotalBytesRead = 0;
  1343. TotalRecordsRead = 0;
  1344. PhysicalEOF = (LPBYTE) Request->LogFile->BaseAddress
  1345. + Request->LogFile->ViewSize;
  1346. PhysStart = (LPBYTE) Request->LogFile->BaseAddress
  1347. + FILEHEADERBUFSIZE;
  1348. BeginRecord = (LPBYTE) Request->LogFile->BaseAddress
  1349. + Request->LogFile->BeginRecord; // Start at first record
  1350. EndRecord = (LPBYTE) Request->LogFile->BaseAddress
  1351. + Request->LogFile->EndRecord; // Byte after end of last record
  1352. //
  1353. // "Seek" to the starting record depending on either the last seek
  1354. // position, or the starting record offset passed in.
  1355. //
  1356. Status = SeekToStartingRecord(Request,
  1357. &ReadPosition,
  1358. BeginRecord,
  1359. EndRecord,
  1360. PhysicalEOF,
  1361. PhysStart);
  1362. if (NT_SUCCESS(Status))
  1363. {
  1364. //
  1365. // Make sure the record is valid
  1366. //
  1367. if (!ValidFilePos(ReadPosition,
  1368. BeginRecord,
  1369. EndRecord,
  1370. PhysicalEOF,
  1371. Request->LogFile->BaseAddress,
  1372. TRUE))
  1373. {
  1374. ELF_LOG1(ERROR,
  1375. "ReadFromLog: Next record (%p) is not valid -- log is corrupt\n",
  1376. ReadPosition);
  1377. Request->Pkt.ReadPkt->BytesRead = 0;
  1378. Request->Pkt.ReadPkt->RecordsRead = 0;
  1379. return STATUS_INVALID_HANDLE;
  1380. }
  1381. // make sure that if we asked for a specific record, that we got it
  1382. if ((Request->Pkt.ReadPkt->ReadFlags & EVENTLOG_SEEK_READ) &&
  1383. (Request->Pkt.ReadPkt->ReadFlags & EVENTLOG_BACKWARDS_READ))
  1384. {
  1385. pEvent = (PEVENTLOGRECORD)ReadPosition;
  1386. if(pEvent->Length == ELFEOFRECORDSIZE ||
  1387. pEvent->RecordNumber != Request->Pkt.ReadPkt->RecordNumber)
  1388. {
  1389. Request->Pkt.ReadPkt->BytesRead = 0;
  1390. Request->Pkt.ReadPkt->RecordsRead = 0;
  1391. return STATUS_EVENTLOG_FILE_CORRUPT;
  1392. }
  1393. }
  1394. RecordSize = RecordBytesTransferred = *(PULONG) ReadPosition;
  1395. if ((Request->Pkt.ReadPkt->Flags & ELF_IREAD_ANSI)
  1396. &&
  1397. (RecordSize != ELFEOFRECORDSIZE))
  1398. {
  1399. //
  1400. //
  1401. // If we were called by an ANSI API, then we need to read the
  1402. // next record into a temporary buffer, process the data in
  1403. // that record and copy it over to the real buffer as ANSI
  1404. // strings (rather than UNICODE).
  1405. //
  1406. // We need to do this here since we won't be able to
  1407. // appropriately size a record that wraps for an ANSI
  1408. // call otherwise (we'll AV trying to read it past
  1409. // the end of the log).
  1410. //
  1411. TempBuf = ElfpAllocateBuffer(RecordSize);
  1412. if (TempBuf == NULL)
  1413. {
  1414. ELF_LOG0(ERROR,
  1415. "ReadFromLog: Unable to allocate memory for "
  1416. "Ansi record (1st call)\n");
  1417. return STATUS_NO_MEMORY;
  1418. }
  1419. TempBufferPosition = BufferPosition; // Save this away
  1420. BufferPosition = TempBuf; // Read into TempBuf
  1421. CopyRecordToBuffer((PBYTE) ReadPosition,
  1422. (PBYTE *) &BufferPosition,
  1423. RecordSize,
  1424. (PBYTE) PhysicalEOF,
  1425. (PBYTE) PhysStart);
  1426. //
  1427. // Call CopyUnicodeToAnsiRecord with a NULL destination
  1428. // location in order to get the size of the Ansi record
  1429. //
  1430. Status = CopyUnicodeToAnsiRecord(NULL,
  1431. TempBuf,
  1432. NULL,
  1433. &RecordBytesTransferred);
  1434. if (!NT_SUCCESS(Status))
  1435. {
  1436. ELF_LOG1(ERROR,
  1437. "ReadFromLog: CopyUnicodeToAnsiRecord failed %#x (1st call)\n",
  1438. Status);
  1439. ElfpFreeBuffer(TempBuf);
  1440. return Status;
  1441. }
  1442. }
  1443. //
  1444. // While there are records to be read, and more space in the buffer,
  1445. // keep on reading records into the buffer.
  1446. //
  1447. while((RecordBytesTransferred <= BytesInBuffer)
  1448. &&
  1449. (RecordSize != ELFEOFRECORDSIZE))
  1450. {
  1451. //
  1452. // If we were called by an ANSI API, then we need to take the
  1453. // record read into TempBuf and transfer it over to the user's
  1454. // buffer while converting any UNICODE strings to ANSI.
  1455. //
  1456. if (Request->Pkt.ReadPkt->Flags & ELF_IREAD_ANSI)
  1457. {
  1458. Status = CopyUnicodeToAnsiRecord(TempBufferPosition,
  1459. TempBuf,
  1460. &BufferPosition,
  1461. &RecordBytesTransferred);
  1462. //
  1463. // RecordBytesTransferred contains the bytes actually
  1464. // copied into the user's buffer.
  1465. //
  1466. // BufferPosition points to the point in the user's buffer
  1467. // just after this record.
  1468. //
  1469. ElfpFreeBuffer(TempBuf);
  1470. TempBuf = NULL;
  1471. if (!NT_SUCCESS(Status))
  1472. {
  1473. ELF_LOG1(ERROR,
  1474. "ReadFromLog: CopyUnicodeToAnsiRecord failed %x "
  1475. "(2nd call)\n",
  1476. Status);
  1477. //
  1478. // Stop reading
  1479. //
  1480. break;
  1481. }
  1482. }
  1483. else
  1484. {
  1485. //
  1486. // Unicode call -- simply copy the record into the buffer
  1487. //
  1488. CopyRecordToBuffer((PBYTE) ReadPosition,
  1489. (PBYTE *) &BufferPosition,
  1490. RecordSize,
  1491. (PBYTE) PhysicalEOF,
  1492. (PBYTE) PhysStart);
  1493. }
  1494. //
  1495. // Update the byte and record counts
  1496. //
  1497. TotalRecordsRead++;
  1498. TotalBytesRead += RecordBytesTransferred;
  1499. BytesInBuffer -= RecordBytesTransferred;
  1500. ReadPosition = NextRecordPosition(Request->Pkt.ReadPkt->ReadFlags,
  1501. ReadPosition,
  1502. RecordSize,
  1503. BeginRecord,
  1504. EndRecord,
  1505. PhysicalEOF,
  1506. PhysStart);
  1507. //
  1508. // Make sure the record is valid
  1509. //
  1510. if (ReadPosition == NULL
  1511. ||
  1512. !ValidFilePos(ReadPosition,
  1513. BeginRecord,
  1514. EndRecord,
  1515. PhysicalEOF,
  1516. Request->LogFile->BaseAddress,
  1517. TRUE))
  1518. {
  1519. ELF_LOG0(ERROR,
  1520. "ReadFromLog: Next record is invalid -- log is corrupt\n");
  1521. return STATUS_EVENTLOG_FILE_CORRUPT;
  1522. }
  1523. RecordSize = RecordBytesTransferred = *(PULONG) ReadPosition;
  1524. if ((Request->Pkt.ReadPkt->Flags & ELF_IREAD_ANSI)
  1525. &&
  1526. (RecordSize != ELFEOFRECORDSIZE))
  1527. {
  1528. TempBuf = ElfpAllocateBuffer(RecordSize);
  1529. if (TempBuf == NULL)
  1530. {
  1531. ELF_LOG0(ERROR,
  1532. "ReadFromLog: Unable to allocate memory for "
  1533. "Ansi record (2nd call)\n");
  1534. return STATUS_NO_MEMORY;
  1535. }
  1536. TempBufferPosition = BufferPosition; // Save this away
  1537. BufferPosition = TempBuf; // Read into TempBuf
  1538. CopyRecordToBuffer((PBYTE) ReadPosition,
  1539. (PBYTE *) &BufferPosition,
  1540. RecordSize,
  1541. (PBYTE) PhysicalEOF,
  1542. (PBYTE) PhysStart);
  1543. //
  1544. // Call CopyUnicodeToAnsiRecord with a NULL destination
  1545. // location in order to get the size of the Ansi record
  1546. //
  1547. Status = CopyUnicodeToAnsiRecord(NULL,
  1548. TempBuf,
  1549. NULL,
  1550. &RecordBytesTransferred);
  1551. if (!NT_SUCCESS(Status))
  1552. {
  1553. ELF_LOG1(ERROR,
  1554. "ReadFromLog: CopyUnicodeToAnsiRecord failed %#x "
  1555. "(1st call)\n",
  1556. Status);
  1557. ElfpFreeBuffer(TempBuf);
  1558. return Status;
  1559. }
  1560. }
  1561. } // while
  1562. ElfpFreeBuffer(TempBuf);
  1563. TempBuf = NULL;
  1564. //
  1565. // If we got to the end and did not read in any records, return
  1566. // an error indicating that the user's buffer is too small if
  1567. // we're not at the EOF record, or end of file if we are.
  1568. //
  1569. if (TotalRecordsRead == 0)
  1570. {
  1571. if (RecordSize == ELFEOFRECORDSIZE)
  1572. {
  1573. ELF_LOG0(FILES,
  1574. "ReadFromLog: No records read -- pointing at EOF record\n");
  1575. Status = STATUS_END_OF_FILE;
  1576. }
  1577. else
  1578. {
  1579. //
  1580. // We didn't read any records, and we're not at EOF, so
  1581. // the buffer was too small
  1582. //
  1583. ELF_LOG1(ERROR,
  1584. "ReadFromLog: No records read -- buffer was too small "
  1585. "(%d bytes needed)\n",
  1586. RecordBytesTransferred);
  1587. Status = STATUS_BUFFER_TOO_SMALL;
  1588. Request->Pkt.ReadPkt->MinimumBytesNeeded = RecordBytesTransferred;
  1589. }
  1590. }
  1591. //
  1592. // Update the current file position.
  1593. //
  1594. Request->Pkt.ReadPkt->LastSeekPos =
  1595. (ULONG) ((ULONG_PTR) ReadPosition
  1596. - (ULONG_PTR) Request->LogFile->BaseAddress);
  1597. Request->Pkt.ReadPkt->LastSeekRecord += TotalRecordsRead;
  1598. ELF_LOG1(FILES,
  1599. "ReadFromLog: %d records successfully read\n",
  1600. TotalRecordsRead);
  1601. }
  1602. else
  1603. {
  1604. ELF_LOG1(ERROR,
  1605. "ReadFromLog: SeekToStartingRecord failed %#x\n",
  1606. Status);
  1607. }
  1608. //
  1609. // Set the bytes read in the request packet for return to client.
  1610. //
  1611. Request->Pkt.ReadPkt->BytesRead = TotalBytesRead;
  1612. Request->Pkt.ReadPkt->RecordsRead = TotalRecordsRead;
  1613. return Status;
  1614. }
  1615. VOID
  1616. PerformReadRequest(
  1617. PELF_REQUEST_RECORD Request
  1618. )
  1619. /*++
  1620. Routine Description:
  1621. This routine performs the READ request.
  1622. It first grabs the log file structure resource and then proceeds
  1623. to read from the file. If the resource is not available, it will
  1624. block until it is.
  1625. This routine impersonates the client in order to ensure that the correct
  1626. access control is uesd. If the client does not have permission to read
  1627. the file, the operation will fail.
  1628. Arguments:
  1629. Pointer to the request packet.
  1630. Return Value:
  1631. NONE
  1632. Note:
  1633. --*/
  1634. {
  1635. //
  1636. // Get shared access to the log file. This will allow multiple
  1637. // readers to get to the file together.
  1638. //
  1639. RtlAcquireResourceShared(&Request->Module->LogFile->Resource,
  1640. TRUE); // Wait until available
  1641. //
  1642. // Try to read from the log. Note that a corrupt log is the
  1643. // most likely cause of an exception (garbage pointers, etc).
  1644. // The eventlog corruption error is a bit all-inclusive, but
  1645. // necessary, since log state is pretty much indeterminable
  1646. // in this situation.
  1647. //
  1648. try
  1649. {
  1650. Request->Status = ReadFromLog(Request);
  1651. }
  1652. except (EXCEPTION_EXECUTE_HANDLER)
  1653. {
  1654. ELF_LOG2(ERROR,
  1655. "PerformReadRequest: Caught exception %#x reading %ws log\n",
  1656. GetExceptionCode(),
  1657. Request->Module->ModuleName);
  1658. Request->Status = STATUS_EVENTLOG_FILE_CORRUPT;
  1659. }
  1660. //
  1661. // Release the resource
  1662. //
  1663. RtlReleaseResource(&Request->Module->LogFile->Resource);
  1664. }
  1665. //
  1666. // BUGBUG: These are only used in WriteToLog and they're not modified.
  1667. // Probably cleaner to make them #define'd constants.
  1668. //
  1669. WCHAR wszAltDosDevices[] = L"\\DosDevices\\";
  1670. WCHAR wszDosDevices[] = L"\\??\\";
  1671. #define DOSDEVICES_LEN ((sizeof(wszDosDevices) / sizeof(WCHAR)) - 1)
  1672. #define ALTDOSDEVICES_LEN ((sizeof(wszAltDosDevices) / sizeof(WCHAR)) - 1)
  1673. VOID
  1674. WriteToLog(
  1675. PLOGFILE pLogFile,
  1676. PVOID Buffer,
  1677. ULONG BufSize,
  1678. PULONG Destination,
  1679. ULONG PhysEOF,
  1680. ULONG PhysStart
  1681. )
  1682. /*++
  1683. Routine Description:
  1684. This routine writes the record into the log file, allowing for wrapping
  1685. around the end of the file.
  1686. It assumes that the caller has serialized access to the file, and has
  1687. ensured that there is enough space in the file for the record.
  1688. Arguments:
  1689. Buffer - Pointer to the buffer containing the event record.
  1690. BufSize - Size of the record to be written.
  1691. Destination - Pointer to the destination - which is in the log file.
  1692. PhysEOF - Physical end of file.
  1693. PhysStart - Physical beginning of file (past the file header).
  1694. Return Value:
  1695. NONE.
  1696. Note:
  1697. --*/
  1698. {
  1699. ULONG BytesToCopy;
  1700. SIZE_T FlushSize;
  1701. ULONG NewDestination;
  1702. NTSTATUS Status;
  1703. PVOID BaseAddress;
  1704. LPWSTR pwszLogFileName;
  1705. LARGE_INTEGER ByteOffset;
  1706. IO_STATUS_BLOCK IoStatusBlock;
  1707. BytesToCopy = min(PhysEOF - *Destination, BufSize);
  1708. ByteOffset = RtlConvertUlongToLargeInteger(*Destination);
  1709. //
  1710. // BUGBUG: If this call fails, we shouldn't set *Destination to
  1711. // NewDestination below. The same is true if the second
  1712. // NtWriteFile call fails.
  1713. //
  1714. Status = NtWriteFile(pLogFile->FileHandle, // Filehandle
  1715. NULL, // Event
  1716. NULL, // APC routine
  1717. NULL, // APC context
  1718. &IoStatusBlock, // IO_STATUS_BLOCK
  1719. Buffer, // Buffer
  1720. BytesToCopy, // Length
  1721. &ByteOffset, // Byteoffset
  1722. NULL); // Key
  1723. if (!NT_SUCCESS(Status))
  1724. {
  1725. ELF_LOG1(ERROR,
  1726. "WriteToLog: NtWriteFile (1st call) failed %#x\n",
  1727. Status);
  1728. }
  1729. NewDestination = *Destination + BytesToCopy;
  1730. if (BytesToCopy != BufSize)
  1731. {
  1732. //
  1733. // Wrap around to the beginning of the file and copy the
  1734. // rest of the data.
  1735. //
  1736. Buffer = (PBYTE) Buffer + BytesToCopy;
  1737. BytesToCopy = BufSize - BytesToCopy;
  1738. ByteOffset = RtlConvertUlongToLargeInteger(PhysStart);
  1739. Status = NtWriteFile(pLogFile->FileHandle, // Filehandle
  1740. NULL, // Event
  1741. NULL, // APC routine
  1742. NULL, // APC context
  1743. &IoStatusBlock, // IO_STATUS_BLOCK
  1744. Buffer, // Buffer
  1745. BytesToCopy, // Length
  1746. &ByteOffset, // Byteoffset
  1747. NULL); // Key
  1748. if (!NT_SUCCESS(Status))
  1749. {
  1750. ELF_LOG1(ERROR,
  1751. "WriteToLog: NtWriteFile (2nd call) failed %#x\n",
  1752. Status);
  1753. }
  1754. NewDestination = PhysStart + BytesToCopy;
  1755. //
  1756. // Set "wrap" bit in log file structure
  1757. //
  1758. pLogFile->Flags |= ELF_LOGFILE_HEADER_WRAP;
  1759. //
  1760. // Now flush this to disk to commit it
  1761. //
  1762. BaseAddress = pLogFile->BaseAddress;
  1763. FlushSize = FILEHEADERBUFSIZE;
  1764. Status = NtFlushVirtualMemory(NtCurrentProcess(),
  1765. &BaseAddress,
  1766. &FlushSize,
  1767. &IoStatusBlock);
  1768. if (!NT_SUCCESS(Status))
  1769. {
  1770. ELF_LOG1(ERROR,
  1771. "WriteToLog: NtFlushVirtualMemory failed %#x\n",
  1772. Status);
  1773. }
  1774. }
  1775. *Destination = NewDestination; // Return new destination
  1776. //
  1777. // Providing all succeeded above, if not set, set the archive file
  1778. // attribute on this log.
  1779. //
  1780. if (NT_SUCCESS(Status)
  1781. &&
  1782. !(pLogFile->Flags & ELF_LOGFILE_ARCHIVE_SET))
  1783. {
  1784. //
  1785. // Advance past prefix string, '\??\' or '\DosDevices\'
  1786. //
  1787. if ((pLogFile->LogFileName->Length / 2) >= DOSDEVICES_LEN
  1788. &&
  1789. !_wcsnicmp(wszDosDevices, pLogFile->LogFileName->Buffer, DOSDEVICES_LEN))
  1790. {
  1791. pwszLogFileName = pLogFile->LogFileName->Buffer + DOSDEVICES_LEN;
  1792. }
  1793. else if ((pLogFile->LogFileName->Length / 2) >= ALTDOSDEVICES_LEN
  1794. &&
  1795. !_wcsnicmp(wszAltDosDevices, pLogFile->LogFileName->Buffer, ALTDOSDEVICES_LEN))
  1796. {
  1797. pwszLogFileName = pLogFile->LogFileName->Buffer + ALTDOSDEVICES_LEN;
  1798. }
  1799. else
  1800. {
  1801. pwszLogFileName = pLogFile->LogFileName->Buffer;
  1802. }
  1803. if (SetFileAttributes(pwszLogFileName, FILE_ATTRIBUTE_ARCHIVE))
  1804. {
  1805. pLogFile->Flags |= ELF_LOGFILE_ARCHIVE_SET;
  1806. }
  1807. else
  1808. {
  1809. ELF_LOG2(ERROR,
  1810. "WriteToLog: SetFileAttributes on file %ws failed %d\n",
  1811. pwszLogFileName,
  1812. GetLastError());
  1813. }
  1814. }
  1815. }
  1816. NTSTATUS
  1817. AutoBackupLogFile(PELF_REQUEST_RECORD Request, ULONG OverwrittenEOF)
  1818. /*++
  1819. Routine Description:
  1820. This routine makes a best attempt to backup the log file.
  1821. It will log an event in the SECURITY log file indicating
  1822. success or failure.
  1823. Arguments:
  1824. Pointer to the request packet.
  1825. Return Value:
  1826. NTSTATUS
  1827. Note:
  1828. --*/
  1829. {
  1830. UNICODE_STRING BackupFileNameU;
  1831. WCHAR BackupFileName[64]; // holds the "unique" part of the name (wsprintf)
  1832. PLOGFILE pLogFile; // For optimized access to structure
  1833. WCHAR BackupFileNamePrefix[] = L"Archive-";
  1834. WCHAR* EventMessage[3];
  1835. WCHAR Number[20]; // long enough to hold a DWORD represented as a string
  1836. SYSTEMTIME SystemTime;
  1837. ELF_REQUEST_RECORD ClearRequest;
  1838. CLEAR_PKT ClearPkt;
  1839. USHORT ClearStatus;
  1840. NTSTATUS Status;
  1841. ULONG WritePos; // Position to write record
  1842. pLogFile = Request->LogFile; // Set local variable
  1843. if (OverwrittenEOF)
  1844. {
  1845. //
  1846. // The EOF record was at the end of the physical file,
  1847. // and we overwrote it with ELF_SKIP_DWORDs, so we need
  1848. // to put it back since we're not going to be able to
  1849. // write a record. We also need to turn the wrap bit
  1850. // back off
  1851. //
  1852. pLogFile->Flags &= ~(ELF_LOGFILE_HEADER_WRAP);
  1853. pLogFile->EndRecord = OverwrittenEOF;
  1854. WritePos = OverwrittenEOF;
  1855. //
  1856. // Write out the EOF record
  1857. //
  1858. WriteToLog(pLogFile,
  1859. &EOFRecord,
  1860. ELFEOFRECORDSIZE,
  1861. &WritePos,
  1862. pLogFile->ActualMaxFileSize,
  1863. FILEHEADERBUFSIZE);
  1864. }
  1865. Status = FlushLogFile(pLogFile);
  1866. if (!NT_SUCCESS(Status))
  1867. return Status;
  1868. //
  1869. // Make BackupFileNameU unique.
  1870. // Allocate enough space for the current LogModuleName, a NULL character,
  1871. // and BackupFileName bytes.
  1872. // If AutoBackupPath is non-NULL, add space for that too.
  1873. //
  1874. // Rename file in place.
  1875. //
  1876. BackupFileNameU.Length = 0;
  1877. BackupFileNameU.MaximumLength = ((wcslen(pLogFile->LogModuleName->Buffer) +
  1878. wcslen(BackupFileNamePrefix) + 1 ) * sizeof(WCHAR)) +
  1879. sizeof(BackupFileName);
  1880. BackupFileNameU.Buffer = ElfpAllocateBuffer(BackupFileNameU.MaximumLength);
  1881. if (BackupFileNameU.Buffer == NULL)
  1882. {
  1883. ELF_LOG0(ERROR,
  1884. "AutoBackupLogFile: failed due to lack of memory\n");
  1885. return STATUS_NO_MEMORY;
  1886. }
  1887. StringCbCopy(BackupFileNameU.Buffer, BackupFileNameU.MaximumLength,
  1888. BackupFileNamePrefix);
  1889. StringCbCat(BackupFileNameU.Buffer, BackupFileNameU.MaximumLength,
  1890. pLogFile->LogModuleName->Buffer);
  1891. GetSystemTime(&SystemTime);
  1892. StringCchPrintfW(BackupFileName, 64, L"-%u-%02u-%02u-%02u-%02u-%02u-%03u.evt",
  1893. SystemTime.wYear,
  1894. SystemTime.wMonth,
  1895. SystemTime.wDay,
  1896. SystemTime.wHour,
  1897. SystemTime.wMinute,
  1898. SystemTime.wSecond,
  1899. SystemTime.wMilliseconds);
  1900. StringCbCat(BackupFileNameU.Buffer, BackupFileNameU.MaximumLength,BackupFileName);
  1901. BackupFileNameU.Length = wcslen(BackupFileNameU.Buffer) * sizeof(WCHAR);
  1902. //
  1903. // Fill in the request packet
  1904. //
  1905. ClearRequest.Pkt.ClearPkt = &ClearPkt;
  1906. ClearRequest.Flags = 0;
  1907. ClearRequest.Module = Request->Module;
  1908. ClearRequest.LogFile = Request->LogFile;
  1909. ClearRequest.Command = ELF_COMMAND_CLEAR;
  1910. ClearRequest.Status = STATUS_SUCCESS;
  1911. ClearRequest.Pkt.ClearPkt->BackupFileName = &BackupFileNameU;
  1912. PerformClearRequest(&ClearRequest);
  1913. //
  1914. // Generate an audit in the Security log.
  1915. //
  1916. StringCchPrintfW(Number, 20, L"0x%x", ClearRequest.Status);
  1917. EventMessage[0] = pLogFile->LogModuleName->Buffer;
  1918. EventMessage[1] = BackupFileNameU.Buffer;
  1919. EventMessage[2] = Number;
  1920. if (NT_SUCCESS(ClearRequest.Status))
  1921. {
  1922. ELF_LOG0(TRACE,
  1923. "AutoBackupLogFile: auto backup and clear worked\n");
  1924. ClearStatus = EVENTLOG_AUDIT_SUCCESS;
  1925. }
  1926. else
  1927. {
  1928. ELF_LOG1(ERROR,
  1929. "AutoBackupLogFile: failed calling clear/backup, error 0x%x\n",
  1930. ClearRequest.Status);
  1931. ClearStatus = EVENTLOG_AUDIT_FAILURE;
  1932. }
  1933. ElfpCreateElfEvent(
  1934. 0x20c, // todo, get the #def
  1935. ClearStatus,
  1936. 1, // EventCategory (SE_CATEGID_SYSTEM)
  1937. 3, // NumberOfStrings
  1938. EventMessage, // Strings
  1939. NULL, // Data
  1940. 0, // Datalength
  1941. 0, // Do not Overwrite if necc.
  1942. TRUE); // For the Security Log file
  1943. ElfpFreeBuffer(BackupFileNameU.Buffer);
  1944. return ClearRequest.Status;
  1945. }
  1946. VOID
  1947. PerformWriteRequest(
  1948. PELF_REQUEST_RECORD Request
  1949. )
  1950. /*++
  1951. Routine Description:
  1952. This routine writes the event log entry to the log file specified in
  1953. the request packet.
  1954. There is no need to impersonate the client since we want all clients
  1955. to have access to writing to the log file.
  1956. This routine does not use memory mapped I/O to access the log file. This
  1957. is so the changes can be immediately committed to disk if that was how
  1958. the log file was opened.
  1959. Arguments:
  1960. Pointer to the request packet.
  1961. Return Value:
  1962. NONE
  1963. Note:
  1964. --*/
  1965. {
  1966. NTSTATUS Status;
  1967. ULONG WritePos; // Position to write record
  1968. LARGE_INTEGER Time;
  1969. ULONG SpaceNeeded; // Record size + "buffer" size
  1970. ULONG CurrentTime = 0;
  1971. PEVENTLOGRECORD EventRecord;
  1972. ULONG RecordSize;
  1973. ULONG DeletedRecordOffset;
  1974. ULONG SpaceAvail;
  1975. ULONG EarliestTime;
  1976. PLOGFILE pLogFile; // For optimized access to structure
  1977. PELF_LOGFILE_HEADER pFileHeader;
  1978. PVOID BaseAddress;
  1979. IO_STATUS_BLOCK IoStatusBlock;
  1980. PEVENTLOGRECORD pEventLogRecord;
  1981. PDWORD FillDword;
  1982. ULONG OverwrittenEOF = 0;
  1983. BOOL bSecurity = FALSE;
  1984. BOOL fRetryWriteRequest = FALSE;
  1985. pLogFile = Request->LogFile; // Set local variable
  1986. // Set some basic BOOLs
  1987. if(!_wcsicmp(pLogFile->LogModuleName->Buffer, ELF_SECURITY_MODULE_NAME))
  1988. bSecurity = TRUE;
  1989. else
  1990. bSecurity = FALSE;
  1991. //This condition occurs under stress conditions
  1992. //and causes an AV further in this function
  1993. if(pLogFile->BaseAddress == NULL)
  1994. {
  1995. Request->Status = STATUS_INVALID_HANDLE;
  1996. return;
  1997. }
  1998. //
  1999. // Get exclusive access to the log file. This will ensure no one
  2000. // else is accessing the file.
  2001. //
  2002. RtlAcquireResourceExclusive(&pLogFile->Resource,
  2003. TRUE); // Wait until available
  2004. try
  2005. {
  2006. RetryWriteRequest:
  2007. //
  2008. // Put in the record number
  2009. //
  2010. pEventLogRecord = (PEVENTLOGRECORD) Request->Pkt.WritePkt->Buffer;
  2011. pEventLogRecord->RecordNumber = pLogFile->CurrentRecordNumber;
  2012. //
  2013. // Now, go to the end of the file and look for empty space.
  2014. //
  2015. // If there is enough space to write out the record, just
  2016. // write it out and update the pointers.
  2017. //
  2018. // If there isn't enough space, then we need to check if we can
  2019. // wrap around the file without overwriting any records that are
  2020. // within the time retention period.
  2021. // If we cannot find any room, then we have to return an error
  2022. // that the file is full (and alert the administrator).
  2023. //
  2024. RecordSize = Request->Pkt.WritePkt->Datasize;
  2025. SpaceNeeded = RecordSize + ELFEOFRECORDSIZE;
  2026. if (pLogFile->EndRecord > pLogFile->BeginRecord)
  2027. {
  2028. //
  2029. // The current write position is after the position of the first
  2030. // record, then we can write up to the end of the file without
  2031. // worrying about overwriting existing records.
  2032. //
  2033. SpaceAvail = pLogFile->ActualMaxFileSize
  2034. - (pLogFile->EndRecord - pLogFile->BeginRecord + FILEHEADERBUFSIZE);
  2035. }
  2036. else if (pLogFile->EndRecord == pLogFile->BeginRecord
  2037. &&
  2038. !(pLogFile->Flags & ELF_LOGFILE_HEADER_WRAP))
  2039. {
  2040. //
  2041. // If the write position is equal to the position of the first
  2042. // record, and we have't wrapped yet, then the file is "empty"
  2043. // and so we have room to the physical end of the file.
  2044. //
  2045. SpaceAvail = pLogFile->ActualMaxFileSize - FILEHEADERBUFSIZE;
  2046. }
  2047. else
  2048. {
  2049. //
  2050. // If our write position is before the position of the first record, then
  2051. // the file has wrapped and we need to deal with overwriting existing
  2052. // records in the file.
  2053. //
  2054. SpaceAvail = pLogFile->BeginRecord - pLogFile->EndRecord;
  2055. }
  2056. //
  2057. // We now have the number of bytes available to write the record
  2058. // WITHOUT overwriting any existing records stored in SpaceAvail.
  2059. // If that amount is not sufficient, then we need to create more space
  2060. // by "deleting" existing records that are older than the retention
  2061. // time that was configured for this file.
  2062. //
  2063. // We check the retention time against the time when the log was
  2064. // written since that is consistent at the server. We cannot use the
  2065. // client's time since that may vary if the clients are in different
  2066. // time zones.
  2067. //
  2068. NtQuerySystemTime(&Time);
  2069. RtlTimeToSecondsSince1970(&Time, &CurrentTime);
  2070. EarliestTime = CurrentTime - pLogFile->Retention;
  2071. Status = STATUS_SUCCESS; // Initialize for return to caller
  2072. //
  2073. // Check to see if the file hasn't reached its maximum allowable
  2074. // size yet, and also hasn't wrapped. If not, grow it by as much as
  2075. // needed, in 64K chunks.
  2076. //
  2077. if (pLogFile->ActualMaxFileSize < pLogFile->ConfigMaxFileSize
  2078. &&
  2079. SpaceNeeded > SpaceAvail)
  2080. {
  2081. //
  2082. // Extend it. This call cannot fail. If it can't extend it, it
  2083. // just caps it at the current size by changing
  2084. // pLogFile->ConfigMaxFileSize
  2085. //
  2086. ElfExtendFile(pLogFile,
  2087. SpaceNeeded,
  2088. &SpaceAvail);
  2089. }
  2090. //
  2091. // We don't want to split the fixed portion of a record across the
  2092. // physical end of the file, it makes it difficult when referencing
  2093. // these fields later (you have to check before you touch each one
  2094. // to make sure it's not after the physical EOF). So, if there's
  2095. // not enough room at the end of the file for the fixed portion,
  2096. // we fill it with a known byte pattern (ELF_SKIP_DWORD) that will
  2097. // be skipped if it's found at the start of a record (as long as
  2098. // it's less than the minimum record size, then we know it's not
  2099. // the start of a valid record).
  2100. //
  2101. if (pLogFile->ActualMaxFileSize - pLogFile->EndRecord < sizeof(EVENTLOGRECORD))
  2102. {
  2103. //
  2104. // Save the EndRecord pointer. In case we don't have the space
  2105. // to write another record, we'll need to rewrite the EOF where
  2106. // it was
  2107. //
  2108. OverwrittenEOF = pLogFile->EndRecord;
  2109. FillDword = (PDWORD) ((PBYTE) pLogFile->BaseAddress + pLogFile->EndRecord);
  2110. while (FillDword < (PDWORD) ((LPBYTE) pLogFile->BaseAddress +
  2111. pLogFile->ActualMaxFileSize))
  2112. {
  2113. *FillDword = ELF_SKIP_DWORD;
  2114. FillDword++;
  2115. }
  2116. pLogFile->EndRecord = FILEHEADERBUFSIZE;
  2117. SpaceAvail = pLogFile->BeginRecord - FILEHEADERBUFSIZE;
  2118. pLogFile->Flags |= ELF_LOGFILE_HEADER_WRAP;
  2119. }
  2120. EventRecord = (PEVENTLOGRECORD) ((PBYTE) pLogFile->BaseAddress
  2121. + pLogFile->BeginRecord);
  2122. while (SpaceNeeded > SpaceAvail)
  2123. {
  2124. //
  2125. // If this logfile can be overwrite-as-needed, or if it has
  2126. // an overwrite time limit and the time hasn't expired, then
  2127. // allow the new event to overwrite an older event.
  2128. //
  2129. if (pLogFile->Retention == OVERWRITE_AS_NEEDED
  2130. ||
  2131. (pLogFile->Retention != NEVER_OVERWRITE
  2132. &&
  2133. (EventRecord->TimeWritten < EarliestTime
  2134. ||
  2135. Request->Flags & ELF_FORCE_OVERWRITE)))
  2136. {
  2137. //
  2138. // OK to overwrite
  2139. //
  2140. ULONG NextRecord;
  2141. ULONG SearchStartPos;
  2142. BOOL fBeginningRecordWrap = FALSE;
  2143. BOOL fInvalidRecordLength = FALSE;
  2144. DeletedRecordOffset = pLogFile->BeginRecord;
  2145. pLogFile->BeginRecord += EventRecord->Length;
  2146. //
  2147. // Ensure BeginRecord offset is DWORD-aligned.
  2148. //
  2149. pLogFile->BeginRecord = (pLogFile->BeginRecord + sizeof(ULONG) - 1)
  2150. & ~(sizeof(ULONG) - 1);
  2151. //
  2152. // Check specifically for a record length value of zero.
  2153. // Zero is considered invalid.
  2154. //
  2155. if (EventRecord->Length == 0)
  2156. {
  2157. ELF_LOG2(ERROR,
  2158. "PerformWriteRequest: Zero-length record at "
  2159. "offset %d in %ws log\n",
  2160. DeletedRecordOffset,
  2161. pLogFile->LogModuleName->Buffer);
  2162. fInvalidRecordLength = TRUE;
  2163. }
  2164. if (pLogFile->BeginRecord >= pLogFile->ActualMaxFileSize)
  2165. {
  2166. ULONG BeginRecord;
  2167. //
  2168. // We're about to wrap around the end of the file. Adjust
  2169. // BeginRecord accordingly.
  2170. //
  2171. fBeginningRecordWrap = TRUE;
  2172. BeginRecord = FILEHEADERBUFSIZE
  2173. + (pLogFile->BeginRecord
  2174. - pLogFile->ActualMaxFileSize);
  2175. //
  2176. // If the record length was bogus (very large), it's possible
  2177. // the wrap-adjusted computed position is still beyond the
  2178. // end of file. In thise case, mark it as bogus.
  2179. //
  2180. if (BeginRecord >= pLogFile->ActualMaxFileSize)
  2181. {
  2182. ELF_LOG3(ERROR,
  2183. "PerformWriteRequest: Too-large record length (%#x) "
  2184. "at offset %d in %ws log\n",
  2185. EventRecord->Length,
  2186. DeletedRecordOffset,
  2187. pLogFile->LogModuleName->Buffer);
  2188. fInvalidRecordLength = TRUE;
  2189. }
  2190. else
  2191. {
  2192. pLogFile->BeginRecord = BeginRecord;
  2193. }
  2194. }
  2195. if (fInvalidRecordLength)
  2196. {
  2197. //
  2198. // If the record length is considered bogus, adjust
  2199. // BeginRecord to be just beyond the length and signature of
  2200. // the previous record to scan for the next valid record.
  2201. //
  2202. pLogFile->BeginRecord = DeletedRecordOffset
  2203. + (sizeof(ULONG) * 2);
  2204. }
  2205. //
  2206. // Ensure the record referenced is indeed a valid record and that
  2207. // we're not reading into a partially overwritten record. With a
  2208. // circular log, it's possible to partially overwrite existing
  2209. // entries with the EOF record and/or ELF_SKIP_DWORD values.
  2210. //
  2211. // Skip the record size to the record signature since the loop
  2212. // below will search for the next valid signature. Note that
  2213. // the increment of SpaceAvail is undone when we find a valid
  2214. // record below.
  2215. //
  2216. NextRecord = pLogFile->BeginRecord + sizeof(ULONG);
  2217. if (NextRecord < pLogFile->ActualMaxFileSize)
  2218. {
  2219. SpaceAvail += min(sizeof(ULONG),
  2220. pLogFile->ActualMaxFileSize - NextRecord);
  2221. }
  2222. //
  2223. // Seek to find a record signature.
  2224. //
  2225. SearchStartPos = pLogFile->BeginRecord;
  2226. for ( ;; )
  2227. {
  2228. PVOID Position;
  2229. for ( ;
  2230. NextRecord != SearchStartPos;
  2231. SpaceAvail += sizeof(ULONG), NextRecord += sizeof(ULONG))
  2232. {
  2233. if (NextRecord >= pLogFile->ActualMaxFileSize)
  2234. {
  2235. NextRecord = pLogFile->BeginRecord = FILEHEADERBUFSIZE;
  2236. }
  2237. if (*(PULONG) ((PBYTE) pLogFile->BaseAddress + NextRecord)
  2238. == ELF_LOG_FILE_SIGNATURE)
  2239. {
  2240. //
  2241. // Found the next valid record signature
  2242. //
  2243. break;
  2244. }
  2245. }
  2246. Position = (PULONG) ((PBYTE) pLogFile->BaseAddress + NextRecord);
  2247. if (*(PULONG) Position == ELF_LOG_FILE_SIGNATURE)
  2248. {
  2249. //
  2250. // This record is valid so far, perform a final, more
  2251. // rigorous check for record validity.
  2252. //
  2253. if (ValidFilePos(CONTAINING_RECORD(Position,
  2254. EVENTLOGRECORD,
  2255. Reserved),
  2256. NULL,
  2257. NULL,
  2258. (PBYTE) pLogFile->BaseAddress
  2259. + pLogFile->ViewSize,
  2260. pLogFile->BaseAddress,
  2261. FALSE))
  2262. {
  2263. //
  2264. // The record is valid. Adjust SpaceAvail to not
  2265. // include a sub-portion of this record in the
  2266. // available space computation.
  2267. //
  2268. SpaceAvail -= sizeof(ULONG);
  2269. pLogFile->BeginRecord = NextRecord - sizeof(ULONG);
  2270. break;
  2271. }
  2272. else
  2273. {
  2274. //
  2275. // Continue the search for the next valid record.
  2276. //
  2277. // NB : Not calling FixContextHandlesForRecord
  2278. // since we have not established a valid
  2279. // beginning record position yet. Not that
  2280. // it would do any good - this condition would
  2281. // be evaluated in cases of corrupt logs.
  2282. //
  2283. ELF_LOG2(FILES,
  2284. "PerformWriteRequest: Valid record signature with "
  2285. "invalid record found at offset %d of %ws log\n",
  2286. NextRecord,
  2287. pLogFile->LogModuleName->Buffer);
  2288. SpaceAvail += sizeof(ULONG);
  2289. NextRecord += sizeof(ULONG);
  2290. continue;
  2291. }
  2292. }
  2293. else
  2294. {
  2295. //
  2296. // Not a single valid record can be found. This is not
  2297. // good. Consider the log corrupted and bail the write.
  2298. //
  2299. ELF_LOG1(ERROR,
  2300. "PerformWriteRequest: No valid records found in %ws log\n",
  2301. pLogFile->LogModuleName->Buffer);
  2302. Status = STATUS_EVENTLOG_FILE_CORRUPT;
  2303. ASSERT(Status != STATUS_EVENTLOG_FILE_CORRUPT);
  2304. break;
  2305. }
  2306. }
  2307. if (Status == STATUS_EVENTLOG_FILE_CORRUPT)
  2308. {
  2309. break;
  2310. }
  2311. if (fBeginningRecordWrap)
  2312. {
  2313. //
  2314. // Check to see if the file has reached its maximum allowable
  2315. // size yet. If not, grow it by as much as needed in 64K
  2316. // chunks.
  2317. //
  2318. if (pLogFile->ActualMaxFileSize < pLogFile->ConfigMaxFileSize)
  2319. {
  2320. //
  2321. // Extend it. This call cannot fail. If it can't
  2322. // extend it, it just caps it at the current size by
  2323. // changing pLogFile->ConfigMaxFileSize.
  2324. //
  2325. ElfExtendFile(pLogFile,
  2326. SpaceNeeded,
  2327. &SpaceAvail);
  2328. //
  2329. // Since extending the file will cause it to be moved, we
  2330. // need to re-establish the address for the EventRecord.
  2331. //
  2332. EventRecord = (PEVENTLOGRECORD) ((PBYTE) pLogFile->BaseAddress
  2333. + DeletedRecordOffset);
  2334. }
  2335. }
  2336. //
  2337. // Make sure no handle points to the record that we're getting
  2338. // ready to overwrite, it one does, correct it to point to the
  2339. // new first record.
  2340. //
  2341. FixContextHandlesForRecord(DeletedRecordOffset,
  2342. pLogFile->BeginRecord);
  2343. if (!fInvalidRecordLength)
  2344. {
  2345. //
  2346. // Update SpaceAvail to include the deleted record's size.
  2347. // That is, if we have a high degree of confidence that
  2348. // it is valid.
  2349. //
  2350. SpaceAvail += EventRecord->Length;
  2351. }
  2352. //
  2353. // Bump to the next record, file wrap was handled above
  2354. //
  2355. //
  2356. // If these are ELF_SKIP_DWORDs, just move past them
  2357. //
  2358. FillDword = (PDWORD) ((PBYTE) pLogFile->BaseAddress
  2359. + pLogFile->BeginRecord);
  2360. if (*FillDword == ELF_SKIP_DWORD)
  2361. {
  2362. SpaceAvail += pLogFile->ActualMaxFileSize - pLogFile->BeginRecord;
  2363. pLogFile->BeginRecord = FILEHEADERBUFSIZE;
  2364. }
  2365. EventRecord = (PEVENTLOGRECORD) ((PBYTE) pLogFile->BaseAddress
  2366. + pLogFile->BeginRecord);
  2367. }
  2368. else
  2369. {
  2370. //
  2371. // CODEWORK: Split this out into a separate function
  2372. //
  2373. //
  2374. // All records within retention period
  2375. //
  2376. ELF_LOG1(ERROR,
  2377. "PerformWriteRequest: %ws log is full\n",
  2378. pLogFile->LogModuleName->Buffer);
  2379. //
  2380. // Do new behavior.
  2381. //
  2382. // Auto backup, clear the log, and log and event that says the file
  2383. // was backed up and try to log the current event one more time.
  2384. //
  2385. // If this cannot be done, we made our best attempt, so we will probably
  2386. // crash on audit fail, and not log the event (revert to old behavior).
  2387. //
  2388. if ((pLogFile->AutoBackupLogFiles != 0) && (fRetryWriteRequest == FALSE)) {
  2389. AutoBackupLogFile(Request, OverwrittenEOF);
  2390. fRetryWriteRequest = TRUE;
  2391. goto RetryWriteRequest;
  2392. }
  2393. //
  2394. // Hang an event on the queuedevent list for later writing
  2395. // if we haven't just written a log full event for this log.
  2396. // Don't put up the popup during setup as there's nothing
  2397. // the user can do about it until setup finishes.
  2398. //
  2399. if (pLogFile->logpLogPopup == LOGPOPUP_CLEARED
  2400. &&
  2401. !ElfGlobalData->fSetupInProgress && !bSecurity)
  2402. {
  2403. INT StringLen, id = -1;
  2404. LPTSTR lpModuleNameLoc = NULL;
  2405. HMODULE StringsResource;
  2406. //
  2407. // We should never be popping up or logging an event
  2408. // for the security log
  2409. //
  2410. ASSERT(_wcsicmp(pLogFile->LogModuleName->Buffer,
  2411. ELF_SECURITY_MODULE_NAME) != 0);
  2412. //
  2413. // Get the localized module name from message table
  2414. //
  2415. StringsResource = GetModuleHandle(L"EVENTLOG.DLL");
  2416. ASSERT(StringsResource != NULL);
  2417. if (_wcsicmp(pLogFile->LogModuleName->Buffer,
  2418. ELF_SYSTEM_MODULE_NAME) == 0)
  2419. {
  2420. id = ELF_MODULE_NAME_LOCALIZE_SYSTEM;
  2421. }
  2422. else if (_wcsicmp(pLogFile->LogModuleName->Buffer,
  2423. ELF_APPLICATION_MODULE_NAME) == 0)
  2424. {
  2425. id = ELF_MODULE_NAME_LOCALIZE_APPLICATION;
  2426. }
  2427. if (id != -1)
  2428. {
  2429. StringLen = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
  2430. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  2431. StringsResource,
  2432. id,
  2433. 0,
  2434. (LPTSTR) &lpModuleNameLoc,
  2435. 0,
  2436. NULL);
  2437. if ((StringLen > 1) && (lpModuleNameLoc != NULL))
  2438. {
  2439. //
  2440. // Get rid of cr/lf control code at the end
  2441. //
  2442. *(lpModuleNameLoc + StringLen - 2) = 0;
  2443. }
  2444. }
  2445. //
  2446. // Create the "log full" event -- use the name stored in the
  2447. // log's default module if it's not a well-known log type
  2448. //
  2449. ElfpCreateElfEvent(EVENT_LOG_FULL,
  2450. EVENTLOG_ERROR_TYPE,
  2451. 0, // EventCategory
  2452. 1, // NumberOfStrings
  2453. (lpModuleNameLoc != NULL) ?
  2454. &lpModuleNameLoc :
  2455. &Request->LogFile->LogModuleName->Buffer,
  2456. NULL, // Data
  2457. 0, // Datalength
  2458. ELF_FORCE_OVERWRITE,
  2459. FALSE); // Overwrite if necc.
  2460. ElfpCreateQueuedMessage(
  2461. ALERT_ELF_LogOverflow,
  2462. 1,
  2463. (lpModuleNameLoc != NULL) ?
  2464. &lpModuleNameLoc :
  2465. &Request->Module->LogFile->LogModuleName->Buffer);
  2466. LocalFree(lpModuleNameLoc);
  2467. //
  2468. // Don't post the popup again until either the machine is
  2469. // rebooted or the log is cleared
  2470. //
  2471. pLogFile->logpLogPopup = LOGPOPUP_ALREADY_SHOWN;
  2472. }
  2473. else if(bSecurity)
  2474. {
  2475. if(pLogFile->bFullAlertDone == FALSE)
  2476. ElfpCreateQueuedAlert(
  2477. ALERT_ELF_LogOverflow,
  2478. 1,
  2479. &Request->Module->LogFile->LogModuleName->Buffer);
  2480. pLogFile->bFullAlertDone = TRUE;
  2481. }
  2482. pLogFile->Flags |= ELF_LOGFILE_LOGFULL_WRITTEN;
  2483. if (OverwrittenEOF)
  2484. {
  2485. //
  2486. // The EOF record was at the end of the physical file,
  2487. // and we overwrote it with ELF_SKIP_DWORDs, so we need
  2488. // to put it back since we're not going to be able to
  2489. // write a record. We also need to turn the wrap bit
  2490. // back off
  2491. //
  2492. pLogFile->Flags &= ~(ELF_LOGFILE_HEADER_WRAP);
  2493. pLogFile->EndRecord = OverwrittenEOF;
  2494. WritePos = OverwrittenEOF;
  2495. //
  2496. // Write out the EOF record
  2497. //
  2498. WriteToLog(pLogFile,
  2499. &EOFRecord,
  2500. ELFEOFRECORDSIZE,
  2501. &WritePos,
  2502. pLogFile->ActualMaxFileSize,
  2503. FILEHEADERBUFSIZE);
  2504. }
  2505. Status = STATUS_LOG_FILE_FULL;
  2506. break; // Get out of while loop
  2507. }
  2508. }
  2509. if (NT_SUCCESS(Status))
  2510. {
  2511. //
  2512. // We have enough room to write the record and the EOF record.
  2513. //
  2514. //
  2515. // Update OldestRecordNumber to reflect the records that were
  2516. // overwritten amd increment the CurrentRecordNumber
  2517. //
  2518. // Make sure that the log isn't empty, if it is, the oldest
  2519. // record is 1
  2520. //
  2521. if (pLogFile->BeginRecord == pLogFile->EndRecord)
  2522. {
  2523. pLogFile->OldestRecordNumber = 1;
  2524. }
  2525. else
  2526. {
  2527. pLogFile->OldestRecordNumber = EventRecord->RecordNumber;
  2528. }
  2529. pLogFile->CurrentRecordNumber++;
  2530. //
  2531. // If the dirty bit is not set, then this is the first time that
  2532. // we have written to the file since we started. In that case,
  2533. // set the dirty bit in the file header as well so that we will
  2534. // know that the contents have changed.
  2535. //
  2536. if (!(pLogFile->Flags & ELF_LOGFILE_HEADER_DIRTY))
  2537. {
  2538. SIZE_T HeaderSize;
  2539. pLogFile->Flags |= ELF_LOGFILE_HEADER_DIRTY;
  2540. pFileHeader = (PELF_LOGFILE_HEADER) pLogFile->BaseAddress;
  2541. pFileHeader->Flags |= ELF_LOGFILE_HEADER_DIRTY;
  2542. //
  2543. // Now flush this to disk to commit it
  2544. //
  2545. BaseAddress = pLogFile->BaseAddress;
  2546. HeaderSize = FILEHEADERBUFSIZE;
  2547. Status = NtFlushVirtualMemory(NtCurrentProcess(),
  2548. &BaseAddress,
  2549. &HeaderSize,
  2550. &IoStatusBlock);
  2551. if (!NT_SUCCESS(Status))
  2552. {
  2553. ELF_LOG1(ERROR,
  2554. "PerformWriteRequest: NtFlushVirtualMemory to add dirty "
  2555. "flag to header failed %#x\n",
  2556. Status);
  2557. }
  2558. }
  2559. //
  2560. // Write the event to the log
  2561. //
  2562. WriteToLog(pLogFile,
  2563. Request->Pkt.WritePkt->Buffer,
  2564. RecordSize,
  2565. &(pLogFile->EndRecord),
  2566. pLogFile->ActualMaxFileSize,
  2567. FILEHEADERBUFSIZE);
  2568. //
  2569. // Use a separate variable for the position since we don't want
  2570. // it updated.
  2571. //
  2572. WritePos = pLogFile->EndRecord;
  2573. if (WritePos > pLogFile->ActualMaxFileSize)
  2574. {
  2575. WritePos -= pLogFile->ActualMaxFileSize - FILEHEADERBUFSIZE;
  2576. }
  2577. //
  2578. // Update the EOF record fields
  2579. //
  2580. EOFRecord.BeginRecord = pLogFile->BeginRecord;
  2581. EOFRecord.EndRecord = WritePos;
  2582. EOFRecord.CurrentRecordNumber = pLogFile->CurrentRecordNumber;
  2583. EOFRecord.OldestRecordNumber = pLogFile->OldestRecordNumber;
  2584. //
  2585. // Write out the EOF record
  2586. //
  2587. WriteToLog(pLogFile,
  2588. &EOFRecord,
  2589. ELFEOFRECORDSIZE,
  2590. &WritePos,
  2591. pLogFile->ActualMaxFileSize,
  2592. FILEHEADERBUFSIZE);
  2593. //
  2594. // If we had just written a logfull record, turn the bit off.
  2595. // Since we just wrote a record, technically it's not full anymore
  2596. //
  2597. if (!(Request->Flags & ELF_FORCE_OVERWRITE))
  2598. {
  2599. pLogFile->Flags &= ~(ELF_LOGFILE_LOGFULL_WRITTEN);
  2600. }
  2601. //
  2602. // See if there are any ElfChangeNotify callers to notify, and if
  2603. // there are, pulse their event
  2604. //
  2605. NotifyChange(pLogFile);
  2606. }
  2607. //
  2608. // Set status field in the request packet.
  2609. //
  2610. Request->Status = Status;
  2611. }
  2612. except (EXCEPTION_EXECUTE_HANDLER)
  2613. {
  2614. ELF_LOG2(ERROR,
  2615. "PerformWriteRequest: Caught exception %#x writing to %ws log\n",
  2616. GetExceptionCode(),
  2617. pLogFile->LogModuleName->Buffer);
  2618. Request->Status = STATUS_EVENTLOG_FILE_CORRUPT;
  2619. }
  2620. //
  2621. // Release the resource
  2622. //
  2623. RtlReleaseResource ( &pLogFile->Resource );
  2624. }
  2625. VOID
  2626. PerformClearRequest(
  2627. PELF_REQUEST_RECORD Request
  2628. )
  2629. /*++
  2630. Routine Description:
  2631. This routine will optionally back up the log file specified, and will
  2632. delete it.
  2633. Arguments:
  2634. Pointer to the request packet.
  2635. Return Value:
  2636. NONE
  2637. Note:
  2638. On the exit path, when we do some "cleanup" work, we discard the
  2639. status and instead return the status of the operation that is being
  2640. performed.
  2641. This is necessary since we wish to return any error condition that is
  2642. directly related to the clear operation. For other errors, we will
  2643. fail at a later stage.
  2644. --*/
  2645. {
  2646. NTSTATUS Status, IStatus;
  2647. PUNICODE_STRING FileName;
  2648. IO_STATUS_BLOCK IoStatusBlock;
  2649. PFILE_RENAME_INFORMATION NewName = NULL;
  2650. OBJECT_ATTRIBUTES ObjectAttributes;
  2651. HANDLE ClearHandle = NULL;
  2652. FILE_DISPOSITION_INFORMATION DeleteInfo = {TRUE};
  2653. ULONG FileRefCount;
  2654. BOOLEAN FileRenamed = FALSE;
  2655. //
  2656. // Get exclusive access to the log file. This will ensure no one
  2657. // else is accessing the file.
  2658. //
  2659. RtlAcquireResourceExclusive (&Request->Module->LogFile->Resource,
  2660. TRUE); // Wait until available
  2661. //
  2662. // We have exclusive access to the file.
  2663. //
  2664. // We force the file to be closed, and store away the ref count
  2665. // so that we can set it back when we reopen the file.
  2666. // This is a little *sleazy* but we have exclusive access to the
  2667. // logfile structure so we can play these games.
  2668. //
  2669. FileRefCount = Request->LogFile->RefCount; // Store this away
  2670. ElfpCloseLogFile(Request->LogFile, ELF_LOG_CLOSE_FORCE);
  2671. Request->LogFile->FileHandle = NULL; // For use later
  2672. //
  2673. // Open the file with delete access in order to rename it.
  2674. //
  2675. InitializeObjectAttributes(&ObjectAttributes,
  2676. Request->LogFile->LogFileName,
  2677. OBJ_CASE_INSENSITIVE,
  2678. NULL,
  2679. NULL);
  2680. Status = NtOpenFile(&ClearHandle,
  2681. GENERIC_READ | DELETE | SYNCHRONIZE,
  2682. &ObjectAttributes,
  2683. &IoStatusBlock,
  2684. FILE_SHARE_DELETE,
  2685. FILE_SYNCHRONOUS_IO_NONALERT);
  2686. if (NT_SUCCESS(Status))
  2687. {
  2688. //
  2689. // If the backup file name has been specified and is not NULL,
  2690. // then we move the current file to the new file. If that fails,
  2691. // then fail the whole operation.
  2692. //
  2693. if ((Request->Pkt.ClearPkt->BackupFileName != NULL)
  2694. &&
  2695. (Request->Pkt.ClearPkt->BackupFileName->Length != 0))
  2696. {
  2697. FileName = Request->Pkt.ClearPkt->BackupFileName;
  2698. //
  2699. // Set up the rename information structure with the new name
  2700. //
  2701. NewName = ElfpAllocateBuffer(FileName->Length
  2702. + sizeof(WCHAR) + sizeof(*NewName));
  2703. if (NewName)
  2704. {
  2705. RtlCopyMemory(NewName->FileName,
  2706. FileName->Buffer,
  2707. FileName->Length);
  2708. //
  2709. // Guarantee that it's NULL terminated
  2710. //
  2711. NewName->FileName[FileName->Length / sizeof(WCHAR)] = L'\0';
  2712. NewName->ReplaceIfExists = FALSE;
  2713. NewName->RootDirectory = NULL;
  2714. NewName->FileNameLength = FileName->Length;
  2715. Status = NtSetInformationFile(ClearHandle,
  2716. &IoStatusBlock,
  2717. NewName,
  2718. FileName->Length + sizeof(*NewName),
  2719. FileRenameInformation);
  2720. if (Status == STATUS_NOT_SAME_DEVICE)
  2721. {
  2722. //
  2723. // They want the backup file to be on a different
  2724. // device. We need to copy this one, and then delete
  2725. // it.
  2726. //
  2727. ELF_LOG2(FILES,
  2728. "PerformClearRequest: Attempting to copy log file %ws "
  2729. "to different device (%ws)\n",
  2730. Request->LogFile->LogFileName->Buffer,
  2731. NewName->FileName);
  2732. Status = ElfpCopyFile(ClearHandle, FileName);
  2733. if (NT_SUCCESS(Status))
  2734. {
  2735. ELF_LOG1(FILES,
  2736. "PerformClearRequest: Copy succeeded -- deleting %ws\n",
  2737. Request->LogFile->LogFileName->Buffer);
  2738. Status = NtSetInformationFile(ClearHandle,
  2739. &IoStatusBlock,
  2740. &DeleteInfo,
  2741. sizeof(DeleteInfo),
  2742. FileDispositionInformation);
  2743. if (!NT_SUCCESS (Status))
  2744. {
  2745. ELF_LOG2(ERROR,
  2746. "PerformClearRequest: Delete of %ws after "
  2747. "successful copy failed %#x\n",
  2748. Request->LogFile->LogFileName->Buffer,
  2749. Status);
  2750. }
  2751. }
  2752. }
  2753. else if (NT_SUCCESS (Status))
  2754. {
  2755. FileRenamed = TRUE;
  2756. }
  2757. if (!NT_SUCCESS(Status))
  2758. {
  2759. ELF_LOG2(ERROR,
  2760. "PerformClearRequest: Rename of %ws failed %#x\n",
  2761. Request->LogFile->LogFileName->Buffer,
  2762. Status);
  2763. }
  2764. }
  2765. else
  2766. {
  2767. ELF_LOG0(ERROR,
  2768. "PerformClearRequest: Unable to allocate memory for "
  2769. "FILE_RENAME_INFORMATION structure\n");
  2770. Status = STATUS_NO_MEMORY;
  2771. }
  2772. }
  2773. else
  2774. {
  2775. //
  2776. // No backup name was specified. Just delete the log file
  2777. // (i.e. "clear it"). We can just delete it since we know
  2778. // that the first time anything is written to a log file,
  2779. // if that file does not exist, it is created and a header
  2780. // is written to it. By deleting it here, we make it cleaner
  2781. // to manage log files, and avoid having zero-length files all
  2782. // over the disk.
  2783. //
  2784. ELF_LOG1(FILES,
  2785. "PerformClearRequest: No backup name specified -- deleting %ws\n",
  2786. Request->LogFile->LogFileName->Buffer);
  2787. Status = NtSetInformationFile(ClearHandle,
  2788. &IoStatusBlock,
  2789. &DeleteInfo,
  2790. sizeof(DeleteInfo),
  2791. FileDispositionInformation);
  2792. if (!NT_SUCCESS(Status))
  2793. {
  2794. ELF_LOG2(ERROR,
  2795. "PerformClearRequest: Delete of %ws failed %#x\n",
  2796. Request->LogFile->LogFileName->Buffer,
  2797. Status);
  2798. }
  2799. }
  2800. IStatus = NtClose(ClearHandle); // Discard status
  2801. ASSERT(NT_SUCCESS(IStatus));
  2802. }
  2803. else
  2804. {
  2805. //
  2806. // The open-for-delete failed.
  2807. //
  2808. ELF_LOG2(ERROR,
  2809. "PerformClearRequest: NtOpenFile of %ws for delete failed %#x\n",
  2810. Request->LogFile->LogFileName->Buffer,
  2811. Status);
  2812. }
  2813. //
  2814. // If the user reduced the size of the log file, pick up the new
  2815. // size as it couldn't be used until the log was cleared
  2816. //
  2817. if (NT_SUCCESS (Status))
  2818. {
  2819. if (Request->LogFile->NextClearMaxFileSize)
  2820. {
  2821. Request->LogFile->ConfigMaxFileSize = Request->LogFile->NextClearMaxFileSize;
  2822. }
  2823. //
  2824. // We need to recreate the file or if the file was just closed,
  2825. // then we reopen it.
  2826. //
  2827. IStatus = ElfOpenLogFile(Request->LogFile, ElfNormalLog);
  2828. if (!NT_SUCCESS(IStatus))
  2829. {
  2830. ELF_LOG2(ERROR,
  2831. "PerformClearRequest: Open of %ws after successful delete "
  2832. "failed %#x\n",
  2833. Request->LogFile->LogFileName->Buffer,
  2834. IStatus);
  2835. Status = IStatus;
  2836. //
  2837. // The open failed -- try to restore the old log file. If
  2838. // NewName is NULL, it means there was no backup file specified.
  2839. //
  2840. if (NewName != NULL)
  2841. {
  2842. //
  2843. // Opening the new log file failed, reopen the old log and
  2844. // return this error from the Api
  2845. //
  2846. PFILE_RENAME_INFORMATION OldName;
  2847. UNICODE_STRING UnicodeString;
  2848. //
  2849. // There shouldn't be any way to fail unless we successfully
  2850. // renamed the file, and there's no recovery if that happens.
  2851. //
  2852. //
  2853. // BUGBUG: We can hit this if the user asked for the backup
  2854. // file to be put on a different device, in which
  2855. // case the delete succeeded but FileRenamed is
  2856. // still set to FALSE if ElfOpenLogFile fails.
  2857. //
  2858. ASSERT(FileRenamed == TRUE);
  2859. //
  2860. // Rename the file back to the original name. Reuse ClearHandle.
  2861. //
  2862. RtlInitUnicodeString(&UnicodeString, NewName->FileName);
  2863. InitializeObjectAttributes(&ObjectAttributes,
  2864. &UnicodeString,
  2865. OBJ_CASE_INSENSITIVE,
  2866. NULL,
  2867. NULL);
  2868. IStatus = NtOpenFile(&ClearHandle,
  2869. GENERIC_READ | DELETE | SYNCHRONIZE,
  2870. &ObjectAttributes,
  2871. &IoStatusBlock,
  2872. FILE_SHARE_DELETE,
  2873. FILE_SYNCHRONOUS_IO_NONALERT);
  2874. if (NT_SUCCESS(IStatus))
  2875. {
  2876. //
  2877. // Set up the rename information structure with the old name
  2878. //
  2879. OldName = ElfpAllocateBuffer(Request->LogFile->LogFileName->Length
  2880. + sizeof(WCHAR) + sizeof(*OldName));
  2881. if (OldName)
  2882. {
  2883. PUNICODE_STRING pFileName = Request->LogFile->LogFileName;
  2884. RtlCopyMemory(OldName->FileName,
  2885. pFileName->Buffer,
  2886. pFileName->Length);
  2887. //
  2888. // Guarantee that it's NULL terminated
  2889. //
  2890. OldName->FileName[pFileName->Length / sizeof(WCHAR)] = L'\0';
  2891. OldName->ReplaceIfExists = FALSE;
  2892. OldName->RootDirectory = NULL;
  2893. OldName->FileNameLength = pFileName->Length;
  2894. //
  2895. // Change the name of the backed-up (i.e., cleared) log
  2896. // file to its original name.
  2897. //
  2898. IStatus = NtSetInformationFile(ClearHandle,
  2899. &IoStatusBlock,
  2900. OldName,
  2901. pFileName->Length
  2902. + sizeof(*OldName)
  2903. + sizeof(WCHAR),
  2904. FileRenameInformation);
  2905. ASSERT(NT_SUCCESS(IStatus));
  2906. //
  2907. // Reopen the original file. This has to work.
  2908. //
  2909. IStatus = ElfOpenLogFile(Request->LogFile, ElfNormalLog);
  2910. ASSERT(NT_SUCCESS(IStatus));
  2911. ElfpFreeBuffer(OldName);
  2912. }
  2913. NtClose(ClearHandle);
  2914. }
  2915. else
  2916. {
  2917. ELF_LOG2(ERROR,
  2918. "PerformClearRequest: Open of backed-up log file %ws "
  2919. "failed %#x\n",
  2920. NewName->FileName,
  2921. IStatus);
  2922. }
  2923. }
  2924. }
  2925. }
  2926. else
  2927. {
  2928. //
  2929. // The delete failed for some reason -- reopen the original log file
  2930. //
  2931. ELF_LOG1(FILES,
  2932. "PerformClearRequest: Delete of %ws failed -- reopening original file\n",
  2933. Request->LogFile->LogFileName->Buffer);
  2934. IStatus = ElfOpenLogFile(Request->LogFile, ElfNormalLog);
  2935. ASSERT(NT_SUCCESS(IStatus));
  2936. }
  2937. Request->LogFile->RefCount = FileRefCount; // Restore old value.
  2938. if (Request->LogFile->logpLogPopup == LOGPOPUP_ALREADY_SHOWN)
  2939. {
  2940. //
  2941. // This log has a viewable popup (i.e., it's not LOGPOPUP_NEVER_SHOW),
  2942. // so we should show it again if the log fills up.
  2943. //
  2944. Request->LogFile->logpLogPopup = LOGPOPUP_CLEARED;
  2945. }
  2946. Request->LogFile->bFullAlertDone = FALSE;
  2947. //
  2948. // Mark any open context handles that point to this file as "invalid for
  2949. // read." This will fail any further READ operations and force the caller
  2950. // to close and reopen the handle.
  2951. //
  2952. InvalidateContextHandlesForLogFile(Request->LogFile);
  2953. //
  2954. // Set status field in the request packet.
  2955. //
  2956. Request->Status = Status;
  2957. //
  2958. // Release the resource
  2959. //
  2960. RtlReleaseResource(&Request->Module->LogFile->Resource);
  2961. ElfpFreeBuffer(NewName);
  2962. }
  2963. VOID
  2964. PerformBackupRequest(
  2965. PELF_REQUEST_RECORD Request
  2966. )
  2967. /*++
  2968. Routine Description:
  2969. This routine will back up the log file specified.
  2970. This routine impersonates the client in order to ensure that the correct
  2971. access control is used.
  2972. This routine is entered with the ElfGlobalResource held in a shared
  2973. state and the logfile lock is acquired shared to prevent writing, but
  2974. allow people to still read.
  2975. This copies the file in two chunks, from the first record to the end
  2976. of the file, and then from the top of the file (excluding the header)
  2977. to the end of the EOF record.
  2978. Arguments:
  2979. Pointer to the request packet.
  2980. Return Value:
  2981. NONE, status is placed in the packet for later use by the API wrapper
  2982. --*/
  2983. {
  2984. NTSTATUS Status, IStatus;
  2985. IO_STATUS_BLOCK IoStatusBlock;
  2986. OBJECT_ATTRIBUTES ObjectAttributes;
  2987. LARGE_INTEGER MaximumSizeOfSection;
  2988. LARGE_INTEGER Offset;
  2989. ULONG LastRecordNumber;
  2990. ULONG OldestRecordNumber;
  2991. HANDLE BackupHandle = INVALID_HANDLE_VALUE;
  2992. PBYTE StartOfCopy;
  2993. PBYTE EndOfCopy;
  2994. ULONG BytesToCopy;
  2995. ULONG EndRecord = FILEHEADERBUFSIZE;
  2996. BOOL ImpersonatingClient = FALSE;
  2997. ELF_LOGFILE_HEADER FileHeaderBuf = { FILEHEADERBUFSIZE, // Size
  2998. ELF_LOG_FILE_SIGNATURE,
  2999. ELF_VERSION_MAJOR,
  3000. ELF_VERSION_MINOR,
  3001. FILEHEADERBUFSIZE, // Start offset
  3002. FILEHEADERBUFSIZE, // End offset
  3003. 1, // Next record #
  3004. 1, // Oldest record #
  3005. 0, // Maxsize
  3006. 0, // Flags
  3007. 0, // Retention
  3008. FILEHEADERBUFSIZE // Size
  3009. };
  3010. //
  3011. // Get shared access to the log file. This will ensure no one
  3012. // else clears the file.
  3013. //
  3014. RtlAcquireResourceShared(&Request->Module->LogFile->Resource,
  3015. TRUE); // Wait until available
  3016. //
  3017. // Save away the next record number. We'll stop copying when we get to
  3018. // the record before this one. Also save the first record number so we
  3019. // can update the header and EOF record.
  3020. //
  3021. LastRecordNumber = Request->LogFile->CurrentRecordNumber;
  3022. OldestRecordNumber = Request->LogFile->OldestRecordNumber;
  3023. //
  3024. // Impersonate the client
  3025. //
  3026. Status = I_RpcMapWin32Status(RpcImpersonateClient(NULL));
  3027. if (NT_SUCCESS(Status))
  3028. {
  3029. //
  3030. // Keep this info so I can only revert in 1 place
  3031. //
  3032. ImpersonatingClient = TRUE;
  3033. //
  3034. // Set up the object attributes structure for the backup file
  3035. //
  3036. InitializeObjectAttributes(&ObjectAttributes,
  3037. Request->Pkt.BackupPkt->BackupFileName,
  3038. OBJ_CASE_INSENSITIVE,
  3039. NULL,
  3040. NULL);
  3041. //
  3042. // Open the backup file. Fail if a file by this name already exists.
  3043. //
  3044. MaximumSizeOfSection =
  3045. RtlConvertUlongToLargeInteger(Request->LogFile->ActualMaxFileSize);
  3046. Status = NtCreateFile(&BackupHandle,
  3047. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  3048. &ObjectAttributes,
  3049. &IoStatusBlock,
  3050. &MaximumSizeOfSection,
  3051. FILE_ATTRIBUTE_NORMAL,
  3052. FILE_SHARE_READ,
  3053. FILE_CREATE,
  3054. FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
  3055. NULL,
  3056. 0);
  3057. if (!NT_SUCCESS(Status))
  3058. {
  3059. ELF_LOG2(ERROR,
  3060. "PerformBackupRequest: Open of backup file %ws failed %#x\n",
  3061. Request->Pkt.BackupPkt->BackupFileName->Buffer,
  3062. Status);
  3063. goto errorexit;
  3064. }
  3065. //
  3066. // Write out the header, we'll update it later
  3067. //
  3068. FileHeaderBuf.CurrentRecordNumber = LastRecordNumber;
  3069. FileHeaderBuf.OldestRecordNumber = OldestRecordNumber;
  3070. FileHeaderBuf.Flags = 0;
  3071. FileHeaderBuf.Retention = Request->LogFile->Retention;
  3072. Status = NtWriteFile(BackupHandle, // Filehandle
  3073. NULL, // Event
  3074. NULL, // APC routine
  3075. NULL, // APC context
  3076. &IoStatusBlock, // IO_STATUS_BLOCK
  3077. &FileHeaderBuf, // Buffer
  3078. FILEHEADERBUFSIZE, // Length
  3079. NULL, // Byteoffset
  3080. NULL); // Key
  3081. if (!NT_SUCCESS(Status))
  3082. {
  3083. ELF_LOG2(ERROR,
  3084. "PerformBackupRequest: Write of header to backup file %ws "
  3085. "failed %#x\n",
  3086. Request->Pkt.BackupPkt->BackupFileName->Buffer,
  3087. Status);
  3088. goto errorexit;
  3089. }
  3090. //
  3091. // Scan from the end of the file skipping over ELF_SKIP_DWORDs
  3092. // to figure out how far to copy. If we haven't wrapped, we just
  3093. // copy to the EndRecord offset.
  3094. //
  3095. if (Request->LogFile->Flags & ELF_LOGFILE_HEADER_WRAP)
  3096. {
  3097. EndOfCopy = (PBYTE) Request->LogFile->BaseAddress
  3098. + Request->LogFile->ActualMaxFileSize - sizeof(DWORD);
  3099. while (*((PDWORD) EndOfCopy) == ELF_SKIP_DWORD)
  3100. {
  3101. EndOfCopy -= sizeof(DWORD);
  3102. }
  3103. EndOfCopy += sizeof(DWORD);
  3104. }
  3105. else
  3106. {
  3107. EndOfCopy = (PBYTE) Request->LogFile->BaseAddress
  3108. + Request->LogFile->EndRecord;
  3109. }
  3110. //
  3111. // Now set the start position to be the first record and
  3112. // calculate the number of bytes to copy
  3113. //
  3114. StartOfCopy = (PBYTE) Request->LogFile->BaseAddress
  3115. + Request->LogFile->BeginRecord;
  3116. BytesToCopy = (ULONG) (EndOfCopy - StartOfCopy);
  3117. EndRecord += BytesToCopy;
  3118. Status = NtWriteFile(BackupHandle, // Filehandle
  3119. NULL, // Event
  3120. NULL, // APC routine
  3121. NULL, // APC context
  3122. &IoStatusBlock, // IO_STATUS_BLOCK
  3123. StartOfCopy, // Buffer
  3124. BytesToCopy, // Length
  3125. NULL, // Byteoffset
  3126. NULL); // Key
  3127. if (!NT_SUCCESS(Status))
  3128. {
  3129. ELF_LOG2(ERROR,
  3130. "PerformBackupRequest: Block write to backup file %ws (1st "
  3131. "call) failed %#x\n",
  3132. Request->Pkt.BackupPkt->BackupFileName->Buffer,
  3133. Status);
  3134. goto errorexit;
  3135. }
  3136. //
  3137. // If the file's not wrapped, we're done except for the EOF
  3138. // record. If the file is wrapped we have to copy the 2nd
  3139. // piece
  3140. //
  3141. if (Request->LogFile->Flags & ELF_LOGFILE_HEADER_WRAP)
  3142. {
  3143. StartOfCopy = (PBYTE) Request->LogFile->BaseAddress
  3144. + FILEHEADERBUFSIZE;
  3145. EndOfCopy = (PBYTE) Request->LogFile->BaseAddress
  3146. + Request->LogFile->EndRecord;
  3147. BytesToCopy = (ULONG) (EndOfCopy - StartOfCopy);
  3148. EndRecord += BytesToCopy;
  3149. Status = NtWriteFile(BackupHandle, // Filehandle
  3150. NULL, // Event
  3151. NULL, // APC routine
  3152. NULL, // APC context
  3153. &IoStatusBlock, // IO_STATUS_BLOCK
  3154. StartOfCopy, // Buffer
  3155. BytesToCopy, // Length
  3156. NULL, // Byteoffset
  3157. NULL); // Key
  3158. if (!NT_SUCCESS(Status))
  3159. {
  3160. ELF_LOG2(ERROR,
  3161. "PerformBackupRequest: Block write to backup file %ws "
  3162. "(2nd call) failed %#x\n",
  3163. Request->Pkt.BackupPkt->BackupFileName->Buffer,
  3164. Status);
  3165. goto errorexit;
  3166. }
  3167. }
  3168. //
  3169. // Write out the EOF record after updating the fields needed for
  3170. // recovery.
  3171. //
  3172. EOFRecord.BeginRecord = FILEHEADERBUFSIZE;
  3173. EOFRecord.EndRecord = EndRecord;
  3174. EOFRecord.CurrentRecordNumber = LastRecordNumber;
  3175. EOFRecord.OldestRecordNumber = OldestRecordNumber;
  3176. Status = NtWriteFile(BackupHandle, // Filehandle
  3177. NULL, // Event
  3178. NULL, // APC routine
  3179. NULL, // APC context
  3180. &IoStatusBlock, // IO_STATUS_BLOCK
  3181. &EOFRecord, // Buffer
  3182. ELFEOFRECORDSIZE, // Length
  3183. NULL, // Byteoffset
  3184. NULL); // Key
  3185. if (!NT_SUCCESS(Status))
  3186. {
  3187. ELF_LOG2(ERROR,
  3188. "PerformBackupRequest: Write of EOF record to backup file "
  3189. "%ws failed %#x\n",
  3190. Request->Pkt.BackupPkt->BackupFileName->Buffer,
  3191. Status);
  3192. goto errorexit;
  3193. }
  3194. //
  3195. // Update the header with valid information
  3196. //
  3197. FileHeaderBuf.EndOffset = EndRecord;
  3198. FileHeaderBuf.MaxSize = EndRecord + ELFEOFRECORDSIZE;
  3199. Offset = RtlConvertUlongToLargeInteger(0);
  3200. Status = NtWriteFile(BackupHandle, // Filehandle
  3201. NULL, // Event
  3202. NULL, // APC routine
  3203. NULL, // APC context
  3204. &IoStatusBlock, // IO_STATUS_BLOCK
  3205. &FileHeaderBuf, // Buffer
  3206. FILEHEADERBUFSIZE, // Length
  3207. &Offset, // Byteoffset
  3208. NULL); // Key
  3209. if (!NT_SUCCESS(Status))
  3210. {
  3211. ELF_LOG2(ERROR,
  3212. "PerformBackupRequest: Rewrite of header to backup file "
  3213. "%ws failed %#x\n",
  3214. Request->Pkt.BackupPkt->BackupFileName->Buffer,
  3215. Status);
  3216. goto errorexit;
  3217. }
  3218. //
  3219. // Clear the LogFile flag archive bit, assuming the caller will
  3220. // clear (or has cleared) this log's archive file attribute.
  3221. // Note: No big deal if the caller didn't clear the archive
  3222. // attribute.
  3223. //
  3224. // The next write to this log tests the LogFile flag archive bit.
  3225. // If the bit is clear, the archive file attribute is set on the
  3226. // log file.
  3227. //
  3228. Request->LogFile->Flags &= ~ELF_LOGFILE_ARCHIVE_SET;
  3229. }
  3230. else
  3231. {
  3232. ELF_LOG1(ERROR,
  3233. "PerformBackupRequest: RpcImpersonateClient failed %#x\n",
  3234. Status);
  3235. }
  3236. errorexit:
  3237. if (ImpersonatingClient)
  3238. {
  3239. IStatus = I_RpcMapWin32Status(RpcRevertToSelf());
  3240. if (!NT_SUCCESS(IStatus))
  3241. {
  3242. ELF_LOG1(ERROR,
  3243. "PerformBackupRequest: RpcRevertToSelf failed %#x\n",
  3244. IStatus);
  3245. }
  3246. }
  3247. //
  3248. // Close the output file
  3249. //
  3250. if (BackupHandle != INVALID_HANDLE_VALUE)
  3251. {
  3252. NtClose(BackupHandle);
  3253. }
  3254. //
  3255. // Set status field in the request packet.
  3256. //
  3257. Request->Status = Status;
  3258. //
  3259. // Release the resource
  3260. //
  3261. RtlReleaseResource(&Request->Module->LogFile->Resource);
  3262. }
  3263. VOID
  3264. ElfPerformRequest(
  3265. PELF_REQUEST_RECORD Request
  3266. )
  3267. /*++
  3268. Routine Description:
  3269. This routine takes the request packet and performs the operation
  3270. on the event log.
  3271. Before it does that, it takes the Global serialization resource
  3272. for a READ to prevent other threads from doing WRITE operations on
  3273. the resources of the service.
  3274. After it has performed the requested operation, it writes any records
  3275. generated by the eventlog service that have been put on the queued event
  3276. list.
  3277. Arguments:
  3278. Pointer to the request packet.
  3279. Return Value:
  3280. NONE
  3281. --*/
  3282. {
  3283. BOOL Acquired = FALSE;
  3284. //
  3285. // Acquire the global resource for shared access. If the resource is
  3286. // not immediately available (i.e., don't wait) then some other thread
  3287. // has it out for exclusive access.
  3288. //
  3289. // If we time out, one of two threads owns the global resource:
  3290. //
  3291. // 1) Thread monitoring the registry
  3292. // We can wait for this thread to finish so that the
  3293. // operation can continue.
  3294. //
  3295. // 2) Control thread
  3296. // In this case, it may turn out that the service is
  3297. // stopping. We examine the current service state to
  3298. // see if it is still running. If so, we loop around
  3299. // and try to get the resource again.
  3300. //
  3301. while ((GetElState() == RUNNING) && (!Acquired))
  3302. {
  3303. Acquired = RtlAcquireResourceShared(&GlobalElfResource,
  3304. FALSE); // Don't wait
  3305. if (!Acquired)
  3306. {
  3307. ELF_LOG1(TRACE,
  3308. "ElfPerformRequest: Sleep %d milliseconds waiting "
  3309. "for global resource\n",
  3310. ELF_GLOBAL_RESOURCE_WAIT);
  3311. Sleep(ELF_GLOBAL_RESOURCE_WAIT);
  3312. }
  3313. }
  3314. //
  3315. // If the resource was not available and the status of the service
  3316. // changed to one of the "non-working" states, then we just return
  3317. // unsuccesful. Rpc should not allow this to happen.
  3318. //
  3319. if (!Acquired)
  3320. {
  3321. ELF_LOG0(TRACE,
  3322. "ElfPerformRequest: Global resource not acquired\n");
  3323. Request->Status = STATUS_UNSUCCESSFUL;
  3324. }
  3325. else
  3326. {
  3327. switch (Request->Command)
  3328. {
  3329. case ELF_COMMAND_READ:
  3330. //
  3331. // The read/write code paths are high risk for exceptions.
  3332. // Ensure exceptions do not go beyond this point. Otherwise,
  3333. // services.exe will be taken out. Note that the try-except
  3334. // blocks are in PerformReadRequest and PerformWriteRequest
  3335. // since the risky calls are between calls to acquire and
  3336. // release a resource -- if the block were out here, a thrown
  3337. // exception would prevent the releasing of the resource
  3338. // (Bug #175768)
  3339. //
  3340. PerformReadRequest(Request);
  3341. break;
  3342. case ELF_COMMAND_WRITE:
  3343. PerformWriteRequest (Request);
  3344. break;
  3345. case ELF_COMMAND_CLEAR:
  3346. PerformClearRequest(Request);
  3347. break;
  3348. case ELF_COMMAND_BACKUP:
  3349. PerformBackupRequest(Request);
  3350. break;
  3351. case ELF_COMMAND_WRITE_QUEUED:
  3352. break;
  3353. }
  3354. //
  3355. // Now run the queued event list dequeueing elements and
  3356. // writing them
  3357. //
  3358. if (!IsListEmpty(&QueuedEventListHead))
  3359. {
  3360. //
  3361. // There are things queued up to write, do it
  3362. //
  3363. WriteQueuedEvents();
  3364. }
  3365. //
  3366. // Release the global resource.
  3367. //
  3368. ReleaseGlobalResource();
  3369. }
  3370. }
  3371. /****
  3372. @func NTSTATUS | FindSizeofEventsSinceStart| This routine walks
  3373. through all the logfile structures and returns the size of
  3374. events that were reported since the start of the eventlog service
  3375. and that need to be proapagated through the cluster-wide replicated
  3376. logs. For all logfiles that are returned in the list, the shared
  3377. lock for their log file is held and must be released by the caller.
  3378. @parm OUT PULONG | pulSize | Pointer to a LONG that contains the size on return.
  3379. @parm OUT PULONG | pulNumLogFiles | Pointer to a LONG that number of log files
  3380. configured for eventlogging.
  3381. @parm OUT PPROPLOGFILEINFO | *ppPropLogFileInfo | A pointer to a PROPLOGFILEINFO with
  3382. all the information about events that need to be propagated is returned via this.
  3383. @rdesc Returns a result code. ERROR_SUCCESS on success.
  3384. @comm This is called by ElfrRegisterClusterSvc
  3385. @xref <f ElfrRegisterClusterSvc>
  3386. ****/
  3387. NTSTATUS
  3388. FindSizeofEventsSinceStart(
  3389. OUT PULONG pulTotalEventSize,
  3390. OUT PULONG pulNumLogFiles,
  3391. OUT PPROPLOGFILEINFO *ppPropLogFileInfo
  3392. )
  3393. {
  3394. PLOGFILE pLogFile;
  3395. PVOID pStartPropPosition;
  3396. PVOID pEndPropPosition;
  3397. ULONG ulSize;
  3398. ULONG ulNumLogFiles;
  3399. PPROPLOGFILEINFO pPropLogFileInfo = NULL;
  3400. UINT i;
  3401. PVOID PhysicalEOF; // Physical end of file
  3402. PVOID PhysStart; // Physical start of file (after file hdr)
  3403. PVOID BeginRecord; // Points to first record
  3404. PVOID EndRecord; // Points to byte after last record
  3405. ELF_REQUEST_RECORD Request; // points to the elf request
  3406. NTSTATUS Status = STATUS_SUCCESS;
  3407. READ_PKT ReadPkt;
  3408. //
  3409. // Lock the linked list
  3410. //
  3411. RtlEnterCriticalSection(&LogFileCritSec);
  3412. //
  3413. // Initialize the number of files
  3414. //
  3415. ulNumLogFiles = 0; // Count of files
  3416. //
  3417. // Initialize the number of files/total event size
  3418. //
  3419. *pulNumLogFiles = 0; // Count of files with events to be propagated
  3420. *pulTotalEventSize = 0;
  3421. //
  3422. // Count the number of files
  3423. // Initialize to the first logfile in the list
  3424. //
  3425. pLogFile = CONTAINING_RECORD(LogFilesHead.Flink,
  3426. LOGFILE,
  3427. FileList);
  3428. //
  3429. // While there are more
  3430. //
  3431. while(pLogFile->FileList.Flink != LogFilesHead.Flink)
  3432. {
  3433. ulNumLogFiles++;
  3434. //
  3435. // Advance to the next log file
  3436. //
  3437. pLogFile = CONTAINING_RECORD(pLogFile->FileList.Flink,
  3438. LOGFILE,
  3439. FileList);
  3440. }
  3441. ELF_LOG1(CLUSTER,
  3442. "FindSizeOfEventsSinceStart: %d log files\n",
  3443. ulNumLogFiles);
  3444. if (!ulNumLogFiles)
  3445. {
  3446. goto FnExit;
  3447. }
  3448. //
  3449. // Allocate a structure for log file info
  3450. //
  3451. pPropLogFileInfo =
  3452. (PPROPLOGFILEINFO) ElfpAllocateBuffer(ulNumLogFiles * sizeof(PROPLOGFILEINFO));
  3453. if (!pPropLogFileInfo)
  3454. {
  3455. ELF_LOG0(ERROR,
  3456. "FindSizeOfEventsSinceStart: Unable to allocate memory "
  3457. "for pPropLogFileInfo\n");
  3458. Status = STATUS_NO_MEMORY;
  3459. goto FnExit;
  3460. }
  3461. //
  3462. // Gather information about the files
  3463. // Initialize to the first logfile in the list
  3464. //
  3465. pLogFile = CONTAINING_RECORD(LogFilesHead.Flink,
  3466. LOGFILE,
  3467. FileList);
  3468. i = 0;
  3469. //
  3470. // While there are more
  3471. //
  3472. //
  3473. // BUGBUG: Based on the generation of ulNumLogFiles above, these
  3474. // two checks are actually identical
  3475. //
  3476. while ((pLogFile->FileList.Flink != LogFilesHead.Flink)
  3477. &&
  3478. (i < ulNumLogFiles))
  3479. {
  3480. ELF_LOG1(CLUSTER,
  3481. "FindSizeOfEventsSinceStart: Processing file %ws\n",
  3482. pLogFile->LogFileName->Buffer);
  3483. //
  3484. // Get shared access to the log file. This will allow multiple
  3485. // readers to get to the file together.
  3486. //
  3487. RtlAcquireResourceShared(&pLogFile->Resource,
  3488. TRUE); // Wait until available
  3489. //
  3490. // Check if any records need to be propagated
  3491. //
  3492. if (pLogFile->CurrentRecordNumber == pLogFile->SessionStartRecordNumber)
  3493. {
  3494. ELF_LOG1(CLUSTER,
  3495. "FindSizeOfEventsSinceStart: No records to propagate from %ws log\n",
  3496. pLogFile->LogModuleName->Buffer);
  3497. goto process_nextlogfile;
  3498. }
  3499. //
  3500. // Records need to be propagated, so find the positions in the
  3501. // file where they are logged
  3502. //
  3503. PhysicalEOF = (LPBYTE) pLogFile->BaseAddress
  3504. + pLogFile->ViewSize;
  3505. PhysStart = (LPBYTE)pLogFile->BaseAddress
  3506. + FILEHEADERBUFSIZE;
  3507. BeginRecord = (LPBYTE) pLogFile->BaseAddress
  3508. + pLogFile->BeginRecord; // Start at first record
  3509. EndRecord = (LPBYTE)pLogFile->BaseAddress
  3510. + pLogFile->EndRecord; // Byte after end of last record
  3511. //
  3512. // Set up the request structure
  3513. //
  3514. Request.Pkt.ReadPkt = &ReadPkt;
  3515. Request.LogFile = pLogFile;
  3516. //
  3517. // Set up the read packet structure for the first event logged in this session
  3518. //
  3519. Request.Pkt.ReadPkt->LastSeekPos = 0;
  3520. Request.Pkt.ReadPkt->ReadFlags = EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ;
  3521. Request.Pkt.ReadPkt->RecordNumber = pLogFile->SessionStartRecordNumber;
  3522. //
  3523. // Chittur Subbaraman (chitturs) - 3/22/99
  3524. //
  3525. // Enclose the SeekToStartingRecord within a try-except block to
  3526. // account for the eventlog getting corrupted under certain
  3527. // circumstances (such as the system crashing). You don't want to
  3528. // read such corrupt records.
  3529. //
  3530. try
  3531. {
  3532. //
  3533. // Find the size of events in this log file
  3534. //
  3535. Status = SeekToStartingRecord(&Request,
  3536. &pStartPropPosition,
  3537. BeginRecord,
  3538. EndRecord,
  3539. PhysicalEOF,
  3540. PhysStart);
  3541. }
  3542. except(EXCEPTION_EXECUTE_HANDLER)
  3543. {
  3544. ELF_LOG2(ERROR,
  3545. "FindSizeOfEventsSinceStart: Caught exception %#x while "
  3546. "seeking first record in %ws log\n",
  3547. GetExceptionCode(),
  3548. pLogFile->LogModuleName->Buffer);
  3549. Status = STATUS_EVENTLOG_FILE_CORRUPT;
  3550. }
  3551. //
  3552. // Skip this log file if error
  3553. //
  3554. if (!NT_SUCCESS(Status))
  3555. {
  3556. ELF_LOG2(ERROR,
  3557. "FindSizeOfEventsSinceStart: SeekToStartingRecord (1st call) for %ws "
  3558. "log failed %#x\n",
  3559. pLogFile->LogModuleName->Buffer,
  3560. Status);
  3561. //
  3562. // Resetting status so that we skip only this file.
  3563. //
  3564. Status = STATUS_SUCCESS;
  3565. goto process_nextlogfile;
  3566. }
  3567. //
  3568. // SS: if this is not a valid position - the file could have wrapped since
  3569. // Should be try and find the last valid record after the session start record
  3570. // number then ? Since this is unlikely to happen-its not worth the trouble
  3571. // however valid position for session start record never succeeds even though
  3572. // it is valid, so we skip it
  3573. //
  3574. //
  3575. // Set up the read packet structure to seek till the start of the
  3576. // last record
  3577. //
  3578. //
  3579. // CODEWORK: We already have the position of the last record (via EndRecord)
  3580. // so just using ((PBYTE) EndRecord - *((PULONG) EndRecord - 1))
  3581. // should give the offset of the last record.
  3582. //
  3583. Request.Pkt.ReadPkt->LastSeekPos = 0;
  3584. Request.Pkt.ReadPkt->ReadFlags = EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ;
  3585. Request.Pkt.ReadPkt->RecordNumber = pLogFile->CurrentRecordNumber - 1;
  3586. //
  3587. // Chittur Subbaraman (chitturs) - 3/22/99
  3588. //
  3589. // Enclose the SeekToStartingRecord within a try-except block to
  3590. // account for the eventlog getting corrupted under certain
  3591. // circumstances (such as the system crashing). You don't want to
  3592. // read such corrupt records.
  3593. //
  3594. try
  3595. {
  3596. Status = SeekToStartingRecord(&Request,
  3597. &pEndPropPosition,
  3598. BeginRecord,
  3599. EndRecord,
  3600. PhysicalEOF,
  3601. PhysStart);
  3602. }
  3603. except(EXCEPTION_EXECUTE_HANDLER)
  3604. {
  3605. ELF_LOG2(ERROR,
  3606. "FindSizeOfEventsSinceStart: Caught exception %#x while "
  3607. "seeking last record in %ws log\n",
  3608. GetExceptionCode(),
  3609. pLogFile->LogModuleName->Buffer);
  3610. Status = STATUS_EVENTLOG_FILE_CORRUPT;
  3611. }
  3612. //
  3613. // Skip this log file if error
  3614. //
  3615. if (!NT_SUCCESS(Status))
  3616. {
  3617. ELF_LOG2(ERROR,
  3618. "FindSizeOfEventsSinceStart: SeekToStartingRecord (2nd call) for %ws "
  3619. "log failed %#x\n",
  3620. pLogFile->LogModuleName->Buffer,
  3621. Status);
  3622. //
  3623. // Resetting status so that we skip only this file.
  3624. //
  3625. Status = STATUS_SUCCESS;
  3626. goto process_nextlogfile;
  3627. }
  3628. //
  3629. // SS: if this is not a valid position - the file could have wrapped since
  3630. //
  3631. if (!ValidFilePos(pEndPropPosition,
  3632. BeginRecord,
  3633. EndRecord,
  3634. PhysicalEOF,
  3635. pLogFile->BaseAddress,
  3636. TRUE))
  3637. {
  3638. ELF_LOG1(ERROR,
  3639. "FindSizeOfEventsSinceStart: ValidFilePos for pEndPropPosition "
  3640. "in %ws log failed\n",
  3641. pLogFile->LogModuleName->Buffer);
  3642. goto process_nextlogfile;
  3643. }
  3644. //
  3645. // The end prop position
  3646. //
  3647. pEndPropPosition = (PBYTE) pEndPropPosition
  3648. + ((PEVENTLOGRECORD)pEndPropPosition)->Length;
  3649. ELF_LOG3(CLUSTER,
  3650. "FindSizeOfEventsSinceStart: Log %ws, pStartPosition %p, pEndPosition %p\n",
  3651. pLogFile->LogModuleName->Buffer,
  3652. pStartPropPosition,
  3653. pEndPropPosition);
  3654. //
  3655. // If no records to propagate - skip the file
  3656. //
  3657. if (pStartPropPosition == pEndPropPosition)
  3658. {
  3659. ELF_LOG1(CLUSTER,
  3660. "FindSizeOfEventsSinceStart: Start and end positions in %ws log "
  3661. "are equal -- no events to propagate\n",
  3662. pLogFile->LogModuleName->Buffer);
  3663. goto process_nextlogfile;
  3664. }
  3665. if (pEndPropPosition > pStartPropPosition)
  3666. {
  3667. ulSize = (ULONG) ((PBYTE) pEndPropPosition - (PBYTE) pStartPropPosition);
  3668. }
  3669. else
  3670. {
  3671. //
  3672. // BUGBUG: This ignores any ELF_SKIP_DWORDs at the end of the file
  3673. //
  3674. ulSize = (ULONG) ((PBYTE) PhysicalEOF - (PBYTE) pStartPropPosition)
  3675. +
  3676. (ULONG) ((PBYTE)pEndPropPosition - (PBYTE)PhysStart);
  3677. }
  3678. ELF_LOG2(CLUSTER,
  3679. "FindSizeOfEventsSinceStart: Need to propagate %d bytes from %ws log\n",
  3680. ulSize,
  3681. pLogFile->LogModuleName->Buffer);
  3682. pPropLogFileInfo[i].pLogFile = pLogFile;
  3683. pPropLogFileInfo[i].pStartPosition = pStartPropPosition;
  3684. pPropLogFileInfo[i].pEndPosition = pEndPropPosition;
  3685. pPropLogFileInfo[i].ulTotalEventSize = ulSize;
  3686. pPropLogFileInfo[i].ulNumRecords = pLogFile->CurrentRecordNumber
  3687. - pLogFile->SessionStartRecordNumber;
  3688. i++;
  3689. (*pulNumLogFiles)++;
  3690. *pulTotalEventSize += ulSize;
  3691. //
  3692. // Advance to the next log file
  3693. //
  3694. pLogFile = CONTAINING_RECORD(pLogFile->FileList.Flink,
  3695. LOGFILE,
  3696. FileList);
  3697. //
  3698. // NB: We were successful with this log file and we therefore hold on to
  3699. // the lock -- the caller will/must release it.
  3700. //
  3701. continue;
  3702. process_nextlogfile:
  3703. //
  3704. // We were not successful with the log file -- release the lock
  3705. //
  3706. RtlReleaseResource(&pLogFile->Resource);
  3707. //
  3708. // Advance to the next log file
  3709. //
  3710. pLogFile = CONTAINING_RECORD(pLogFile->FileList.Flink,
  3711. LOGFILE,
  3712. FileList);
  3713. }
  3714. //
  3715. // Free the memory if unsuccessful
  3716. //
  3717. if (!(*pulNumLogFiles))
  3718. {
  3719. ElfpFreeBuffer(pPropLogFileInfo);
  3720. pPropLogFileInfo = NULL;
  3721. }
  3722. FnExit:
  3723. *ppPropLogFileInfo = pPropLogFileInfo;
  3724. ELF_LOG3(CLUSTER,
  3725. "FindSizeOfEventsSinceStart: ulTotalEventSize = %d, ulNumLogFiles = %d, "
  3726. "pPropLogFileInfo = %p\n",
  3727. *pulTotalEventSize,
  3728. *pulNumLogFiles,
  3729. *ppPropLogFileInfo);
  3730. //
  3731. // Unlock the linked list
  3732. //
  3733. RtlLeaveCriticalSection(&LogFileCritSec);
  3734. return Status;
  3735. }
  3736. /****
  3737. @func NTSTATUS | GetEventsToProp| Given a propagate log file
  3738. info structure, this events prepares a block of eventlog
  3739. records to propagate. The shared lock to the logfile must
  3740. be held thru when the PROPLOGINFO structure is prepared
  3741. to when this routine is called.
  3742. @parm OUT PEVENTLOGRECORD | pEventLogRecords | Pointer to a EVENTLOGRECORD
  3743. structure where the events to be propagated are returned.
  3744. @parm IN PPROPLOGFILEINFO | pPropLogFileInfo | Pointer to a PROPLOGFILEINFO
  3745. structure that contains the information to retrieve events from the
  3746. corresponding eventlog file.
  3747. @rdesc Returns a result code. ERROR_SUCCESS on success.
  3748. @xref
  3749. ****/
  3750. NTSTATUS
  3751. GetEventsToProp(
  3752. IN PEVENTLOGRECORD pEventLogRecords,
  3753. IN PPROPLOGFILEINFO pPropLogFileInfo
  3754. )
  3755. {
  3756. PVOID BufferPosition;
  3757. PVOID XferPosition;
  3758. PVOID PhysicalEOF;
  3759. PVOID PhysicalStart;
  3760. ULONG ulBytesToMove;
  3761. NTSTATUS Status = STATUS_SUCCESS;
  3762. ELF_LOG1(CLUSTER,
  3763. "GetEventsToProp: Getting events for %ws log\n",
  3764. pPropLogFileInfo->pLogFile->LogModuleName->Buffer);
  3765. BufferPosition = pEventLogRecords;
  3766. ulBytesToMove = pPropLogFileInfo->ulTotalEventSize;
  3767. //
  3768. // If the start and end positions are the same there are no bytes to copy
  3769. //
  3770. if (pPropLogFileInfo->pStartPosition == pPropLogFileInfo->pEndPosition)
  3771. {
  3772. ASSERT(FALSE);
  3773. //
  3774. // Shouldn't come here as FindSizeofEventsSinceStart checks
  3775. // for this explicitly
  3776. //
  3777. return STATUS_SUCCESS;
  3778. }
  3779. //
  3780. // Chittur Subbaraman (chitturs) - 3/15/99
  3781. //
  3782. // Enclose the memcpy within a try-except block to account for
  3783. // the eventlog getting corrupted under certain circumstances (such
  3784. // as the system crashing). You don't want to read such corrupt
  3785. // records.
  3786. //
  3787. try
  3788. {
  3789. XferPosition = pPropLogFileInfo->pStartPosition;
  3790. ulBytesToMove = pPropLogFileInfo->ulTotalEventSize;
  3791. if (pPropLogFileInfo->pStartPosition > pPropLogFileInfo->pEndPosition)
  3792. {
  3793. //
  3794. // The log is wrapped -- copy the bytes from the start position
  3795. // to the end of the file
  3796. //
  3797. PhysicalEOF = (PBYTE) pPropLogFileInfo->pLogFile->BaseAddress
  3798. + pPropLogFileInfo->pLogFile->ViewSize;
  3799. PhysicalStart = (PBYTE) pPropLogFileInfo->pLogFile->BaseAddress
  3800. + FILEHEADERBUFSIZE;
  3801. //
  3802. // BUGBUG: This copies any ELF_SKIP_DWORDs that are at the
  3803. // end of the file
  3804. //
  3805. ulBytesToMove = (ULONG) ((PBYTE) PhysicalEOF
  3806. - (PBYTE) pPropLogFileInfo->pStartPosition);
  3807. RtlCopyMemory(BufferPosition, XferPosition, ulBytesToMove);
  3808. //
  3809. // Set it up for the second half
  3810. //
  3811. BufferPosition = (PBYTE) BufferPosition + ulBytesToMove;
  3812. ulBytesToMove = pPropLogFileInfo->ulTotalEventSize - ulBytesToMove;
  3813. XferPosition = PhysicalStart;
  3814. }
  3815. RtlCopyMemory(BufferPosition, XferPosition, ulBytesToMove);
  3816. }
  3817. except (EXCEPTION_EXECUTE_HANDLER)
  3818. {
  3819. ELF_LOG2(ERROR,
  3820. "GetEventsToProp: Caught exception %#x copying records from %ws log\n",
  3821. GetExceptionCode(),
  3822. pPropLogFileInfo->pLogFile->LogModuleName->Buffer);
  3823. Status = STATUS_EVENTLOG_FILE_CORRUPT;
  3824. }
  3825. return Status;
  3826. }
  3827. //SS:end of changes made to enable cluster wide event logging