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

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