Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4947 lines
156 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. smlogsvc.c
  5. Abstract:
  6. service to log performance counter and trace data,
  7. and to scan for alert conditions.
  8. --*/
  9. #ifndef UNICODE
  10. #define UNICODE 1
  11. #endif
  12. #ifndef _UNICODE
  13. #define _UNICODE 1
  14. #endif
  15. #ifndef _IMPLEMENT_WMI
  16. #define _IMPLEMENT_WMI 1
  17. #endif
  18. #ifndef _DEBUG_OUTPUT
  19. #define _DEBUG_OUTPUT 0
  20. #endif
  21. //
  22. // Windows Include files
  23. //
  24. #pragma warning ( disable : 4201)
  25. #pragma warning ( disable : 4127)
  26. // Define the following to use the minimum of shlwapip.h
  27. #include <nt.h>
  28. #include <ntrtl.h>
  29. #include <nturtl.h>
  30. #include <wtypes.h>
  31. #include <limits.h>
  32. #if _IMPLEMENT_WMI
  33. #include <wmistr.h>
  34. #include <objbase.h>
  35. #include <initguid.h>
  36. #include <evntrace.h>
  37. #include <wmiguid.h>
  38. #include <wmium.h>
  39. #include <pdhmsg.h> // For BuildCurrentLogFileName
  40. #include <pdhp.h>
  41. #endif
  42. #include <tchar.h>
  43. #include <assert.h>
  44. #include <limits.h>
  45. #include "common.h"
  46. #include "smlogsvc.h"
  47. #include "smlogmsg.h"
  48. #define NT_KERNEL_LOGGER ((LPWSTR)L"NT Kernel Logger")
  49. #define DEFAULT_LOG_FILE_FOLDER L"%SystemDrive%\\PerfLogs"
  50. #define STATUS_MASK ((DWORD)0x3FFFFFFF)
  51. // todo: Move SECONDS_IN_DAY definition
  52. #define SECONDS_IN_DAY ((LONGLONG)(86400))
  53. // Global variables used by all modules
  54. HANDLE hEventLog = NULL;
  55. HINSTANCE hModule = NULL;
  56. DWORD* arrPdhDataCollectSuccess = NULL;
  57. INT iPdhDataCollectSuccessCount = 0;
  58. // hNewQueryEvent is signalled when a new query is started. This tells the main
  59. // thread to reconfigure its array of Wait objects.
  60. HANDLE hNewQueryEvent = NULL;
  61. SERVICE_STATUS_HANDLE hSmLogStatus;
  62. SERVICE_STATUS ssSmLogStatus;
  63. // Static variables used by this module only
  64. static PLOG_QUERY_DATA pFirstQuery = NULL;
  65. static CRITICAL_SECTION QueryDataLock;
  66. static CRITICAL_SECTION ConfigurationLock;
  67. static TCHAR gszDefaultLogFileFolder[MAX_PATH+1] = TEXT("");
  68. // Active session count should match the number of query data objects.
  69. static DWORD dwActiveSessionCount = 0;
  70. static DWORD dwMaxActiveSessionCount = MAXIMUM_WAIT_OBJECTS - 1;
  71. static HANDLE arrSessionHandle[MAXIMUM_WAIT_OBJECTS];
  72. // Local function prototypes
  73. DWORD
  74. LoadCommonConfig(
  75. IN PLOG_QUERY_DATA pQuery);
  76. void
  77. LockQueryData ( void );
  78. void
  79. UnlockQueryData ( void );
  80. PLOG_QUERY_DATA
  81. GetQueryData (
  82. LPCTSTR szQueryName );
  83. void
  84. FreeQueryData (
  85. IN PLOG_QUERY_DATA pQuery );
  86. void
  87. RemoveAndFreeQueryData (
  88. HANDLE hThisQuery );
  89. BOOL
  90. AlertFieldsMatch (
  91. IN PLOG_QUERY_DATA pFirstQuery,
  92. IN PLOG_QUERY_DATA pSecondQuery );
  93. BOOL
  94. CommonFieldsMatch (
  95. IN PLOG_QUERY_DATA pFirstQuery,
  96. IN PLOG_QUERY_DATA pSecondQuery );
  97. BOOL
  98. FieldsMatch (
  99. IN PLOG_QUERY_DATA pFirstQuery,
  100. IN PLOG_QUERY_DATA pSecondQuery );
  101. DWORD
  102. ConfigureQuery (
  103. HKEY hKeyLogQuery,
  104. TCHAR* szQueryKeyNameBuffer,
  105. TCHAR* szQueryNameBuffer );
  106. void
  107. ClearTraceProperties (
  108. IN PLOG_QUERY_DATA pQuery );
  109. BOOL
  110. TraceStopRestartFieldsMatch (
  111. IN PLOG_QUERY_DATA pOrigQuery,
  112. IN PLOG_QUERY_DATA pNewQuery );
  113. DWORD
  114. ReconfigureQuery (
  115. IN PLOG_QUERY_DATA pQuery );
  116. DWORD
  117. StartQuery (
  118. IN PLOG_QUERY_DATA pQuery );
  119. DWORD
  120. HandleMaxQueriesExceeded (
  121. IN PLOG_QUERY_DATA pQuery );
  122. DWORD
  123. InitTraceGuids(
  124. IN PLOG_QUERY_DATA pQuery );
  125. BOOL
  126. IsKernelTraceMode (
  127. IN DWORD dwTraceFlags );
  128. DWORD
  129. LoadPdhLogUpdateSuccess ( void );
  130. void
  131. LoadDefaultLogFileFolder ( void );
  132. DWORD
  133. ProcessLogFileFolder (
  134. IN PLOG_QUERY_DATA pQuery,
  135. IN BOOL bReconfigure );
  136. #if _IMPLEMENT_WMI
  137. DWORD
  138. IsCreateNewFile (
  139. IN PLOG_QUERY_DATA pQuery,
  140. OUT BOOL* pbValidBySize,
  141. OUT BOOL* pbValidByTime );
  142. ULONG
  143. TraceNotificationCallback(
  144. IN PWNODE_HEADER pWnode,
  145. IN UINT_PTR LogFileIndex )
  146. {
  147. UNREFERENCED_PARAMETER(LogFileIndex);
  148. if ( (IsEqualGUID(& pWnode->Guid, & TraceErrorGuid))
  149. && (pWnode->BufferSize >= (sizeof(WNODE_HEADER) + sizeof(ULONG))))
  150. {
  151. ULONG LoggerId = (ULONG) pWnode->HistoricalContext;
  152. PLOG_QUERY_DATA pQuery = pFirstQuery;
  153. ULONG Status = * ((ULONG *)
  154. (((PUCHAR) pWnode) + sizeof(WNODE_HEADER)));
  155. LOG_QUERY_DATA lqdTemp;
  156. HRESULT hr = ERROR_SUCCESS;
  157. DWORD dwStatus = ERROR_SUCCESS;
  158. while ( NULL != pQuery ) {
  159. // todo: Need to lock queue?
  160. if (pQuery->Properties.Wnode.HistoricalContext == LoggerId) {
  161. break;
  162. }
  163. pQuery = pQuery->next;
  164. }
  165. if ( STATUS_LOG_FILE_FULL == Status
  166. || STATUS_THREAD_IS_TERMINATING == Status ) {
  167. if ( NULL != pQuery ) {
  168. SetEvent (pQuery->hExitEvent);
  169. }
  170. } else if ( STATUS_MEDIA_CHANGED == Status ) {
  171. BOOL bRun = TRUE;
  172. if ( NULL != pQuery ) {
  173. if( pQuery->hUserToken == NULL ){
  174. // see if we can get a user token
  175. hr = PdhiPlaRunAs( pQuery->szQueryName, NULL, &pQuery->hUserToken );
  176. if ( ERROR_SUCCESS != hr ){
  177. LPWSTR szStringArray[2];
  178. szStringArray[0] = pQuery->szQueryName;
  179. ReportEvent (hEventLog,
  180. EVENTLOG_WARNING_TYPE,
  181. 0,
  182. SMLOG_INVALID_CREDENTIALS,
  183. NULL,
  184. 1,
  185. sizeof(HRESULT),
  186. szStringArray,
  187. (LPVOID)&hr
  188. );
  189. bRun = FALSE;
  190. }
  191. }
  192. // Run command file, supplying previous filename
  193. if ( bRun && NULL != pQuery->szCmdFileName ) {
  194. DoLogCommandFile (pQuery, pQuery->szLogFileName, TRUE);
  195. }
  196. }
  197. // Retrieve the current log file name for the next notification.
  198. dwStatus = GetTraceQueryStatus ( pQuery, &lqdTemp );
  199. if ( ERROR_SUCCESS == dwStatus ) {
  200. lstrcpy ( pQuery->szLogFileName, lqdTemp.szLogFileName );
  201. RegisterCurrentFile( pQuery->hKeyQuery, pQuery->szLogFileName, 0 );
  202. } // else { todo report error
  203. // Query to get the new filename
  204. } else {
  205. // report error
  206. }
  207. }
  208. return ERROR_SUCCESS;
  209. }
  210. #endif
  211. // Functions
  212. DWORD
  213. GetSystemWideDefaultNullDataSource()
  214. {
  215. static BOOLEAN bRead = FALSE;
  216. static DWORD dwNullDataSource = DATA_SOURCE_REGISTRY;
  217. if (bRead == FALSE) {
  218. HKEY hKeyPDH = NULL;
  219. DWORD dwStatus;
  220. DWORD dwType = 0;
  221. DWORD dwSize = sizeof(DWORD);
  222. dwStatus = RegOpenKeyExW(
  223. HKEY_LOCAL_MACHINE,
  224. L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\PDH",
  225. 0L,
  226. KEY_READ,
  227. & hKeyPDH);
  228. if (dwStatus == ERROR_SUCCESS) {
  229. dwStatus = RegQueryValueExW(hKeyPDH,
  230. L"DefaultNullDataSource",
  231. NULL,
  232. & dwType,
  233. (LPBYTE) & dwNullDataSource,
  234. & dwSize);
  235. if ( dwStatus == ERROR_SUCCESS
  236. && dwType == REG_DWORD
  237. && dwNullDataSource == DATA_SOURCE_WBEM) {
  238. dwNullDataSource = DATA_SOURCE_WBEM;
  239. }
  240. else {
  241. dwNullDataSource = DATA_SOURCE_REGISTRY;
  242. }
  243. RegCloseKey(hKeyPDH);
  244. }
  245. bRead = TRUE;
  246. }
  247. return dwNullDataSource;
  248. }
  249. DWORD
  250. ScanHexFormat(
  251. IN const WCHAR* Buffer,
  252. IN ULONG MaximumLength,
  253. IN const WCHAR* Format,
  254. ...)
  255. /*++
  256. Routine Description:
  257. Scans a source Buffer and places values from that buffer into the parameters
  258. as specified by Format.
  259. Arguments:
  260. Buffer -
  261. Contains the source buffer which is to be scanned.
  262. MaximumLength -
  263. Contains the maximum length in characters for which Buffer is searched.
  264. This implies that Buffer need not be UNICODE_NULL terminated.
  265. Format -
  266. Contains the format string which defines both the acceptable string format
  267. contained in Buffer, and the variable parameters which follow.
  268. NOTE: This code is from \ntos\rtl\guid.c
  269. Return Value:
  270. Returns the number of parameters filled if the end of the Buffer is reached,
  271. else -1 on an error.
  272. --*/
  273. {
  274. va_list ArgList;
  275. int FormatItems;
  276. va_start(ArgList, Format);
  277. for (FormatItems = 0;;) {
  278. switch (*Format) {
  279. case 0:
  280. return (*Buffer && MaximumLength) ? -1 : FormatItems;
  281. case '%':
  282. Format++;
  283. if (*Format != '%') {
  284. ULONG Number;
  285. int Width;
  286. int Long;
  287. PVOID Pointer;
  288. for (Long = 0, Width = 0;; Format++) {
  289. if ((*Format >= '0') && (*Format <= '9')) {
  290. Width = Width * 10 + *Format - '0';
  291. } else if (*Format == 'l') {
  292. Long++;
  293. } else if ((*Format == 'X') || (*Format == 'x')) {
  294. break;
  295. }
  296. }
  297. Format++;
  298. for (Number = 0; Width--; Buffer++, MaximumLength--) {
  299. if (!MaximumLength)
  300. return (DWORD)(-1);
  301. Number *= 16;
  302. if ((*Buffer >= '0') && (*Buffer <= '9')) {
  303. Number += (*Buffer - '0');
  304. } else if ((*Buffer >= 'a') && (*Buffer <= 'f')) {
  305. Number += (*Buffer - 'a' + 10);
  306. } else if ((*Buffer >= 'A') && (*Buffer <= 'F')) {
  307. Number += (*Buffer - 'A' + 10);
  308. } else {
  309. return (DWORD)(-1);
  310. }
  311. }
  312. Pointer = va_arg(ArgList, PVOID);
  313. if (Long) {
  314. *(PULONG)Pointer = Number;
  315. } else {
  316. *(PUSHORT)Pointer = (USHORT)Number;
  317. }
  318. FormatItems++;
  319. break;
  320. }
  321. /* no break */
  322. default:
  323. if (!MaximumLength || (*Buffer != *Format)) {
  324. return (DWORD)(-1);
  325. }
  326. Buffer++;
  327. MaximumLength--;
  328. Format++;
  329. break;
  330. }
  331. }
  332. }
  333. DWORD
  334. GUIDFromString(
  335. IN PUNICODE_STRING GuidString,
  336. OUT GUID* Guid
  337. )
  338. /*++
  339. Routine Description:
  340. Retrieves a the binary format of a textual GUID presented in the standard
  341. string version of a GUID: "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}".
  342. Arguments:
  343. GuidString -
  344. Place from which to retrieve the textual form of the GUID.
  345. Guid -
  346. Place in which to put the binary form of the GUID.
  347. NOTE: This code is from \ntos\rtl\guid.c
  348. Return Value:
  349. Returns ERROR_SUCCESS if the buffer contained a valid GUID, else
  350. ERROR_INVALID_PARAMETER if the string was invalid.
  351. --*/
  352. {
  353. USHORT Data4[8];
  354. int Count;
  355. WCHAR GuidFormat[] = L"{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}";
  356. for (Count = 0; Count < sizeof(Data4)/sizeof(Data4[0]); Count++) {
  357. Data4[Count] = 0;
  358. }
  359. if (ScanHexFormat(GuidString->Buffer, GuidString->Length / sizeof(WCHAR), GuidFormat, &Guid->Data1, &Guid->Data2, &Guid->Data3, &Data4[0], &Data4[1], &Data4[2], &Data4[3], &Data4[4], &Data4[5], &Data4[6], &Data4[7]) == -1) {
  360. return (DWORD)(ERROR_INVALID_PARAMETER);
  361. }
  362. for (Count = 0; Count < sizeof(Data4)/sizeof(Data4[0]); Count++) {
  363. Guid->Data4[Count] = (UCHAR)Data4[Count];
  364. }
  365. return ERROR_SUCCESS;
  366. }
  367. LPWSTR
  368. FormatEventLogMessage(DWORD dwStatus)
  369. {
  370. LPVOID lpMsgBuf = NULL;
  371. HINSTANCE hPdh = NULL;
  372. DWORD dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM;
  373. hPdh = LoadLibrary (_T("PDH.DLL"));
  374. if (NULL != hPdh){
  375. dwFlags |= FORMAT_MESSAGE_FROM_HMODULE;
  376. }
  377. FormatMessage(
  378. dwFlags,
  379. hPdh,
  380. dwStatus,
  381. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  382. (LPTSTR)&lpMsgBuf,
  383. MAX_PATH,
  384. NULL );
  385. if ( NULL != hPdh ) {
  386. FreeLibrary( hPdh );
  387. }
  388. return lpMsgBuf;
  389. }
  390. BOOL
  391. IsKernelTraceMode (
  392. IN DWORD dwTraceFlags )
  393. {
  394. BOOL bReturn = FALSE;
  395. DWORD dwKernelMask = SLQ_TLI_ENABLE_KERNEL_TRACE
  396. | SLQ_TLI_ENABLE_KERNEL_TRACE
  397. | SLQ_TLI_ENABLE_MEMMAN_TRACE
  398. | SLQ_TLI_ENABLE_FILEIO_TRACE
  399. | SLQ_TLI_ENABLE_PROCESS_TRACE
  400. | SLQ_TLI_ENABLE_THREAD_TRACE
  401. | SLQ_TLI_ENABLE_DISKIO_TRACE
  402. | SLQ_TLI_ENABLE_NETWORK_TCPIP_TRACE;
  403. bReturn = ( dwKernelMask & dwTraceFlags ) ? TRUE : FALSE;
  404. return bReturn;
  405. }
  406. long
  407. JulianDateFromSystemTime(
  408. SYSTEMTIME *pST )
  409. {
  410. static WORD wDaysInRegularMonth[] = {
  411. 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
  412. };
  413. static WORD wDaysInLeapYearMonth[] = {
  414. 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366
  415. };
  416. long JDate = 0;
  417. // Check for leap year.
  418. if (pST->wMonth > 1) {
  419. if ( ( pST->wYear % 400 == 0 )
  420. || ( pST->wYear % 100 != 0
  421. && pST->wYear % 4 == 0 ) ) {
  422. // this is a leap year
  423. JDate += wDaysInLeapYearMonth[pST->wMonth - 2];
  424. } else {
  425. // this is not a leap year
  426. JDate += wDaysInRegularMonth[pST->wMonth - 2];
  427. }
  428. }
  429. // Add in days for this month.
  430. JDate += pST->wDay;
  431. // Add in year.
  432. JDate += (pST->wYear) * 1000;
  433. return JDate;
  434. }
  435. DWORD
  436. ReadRegistrySlqTime (
  437. HKEY hKey,
  438. LPCWSTR szQueryName, // For error logging
  439. LPCWSTR szValueName,
  440. PSLQ_TIME_INFO pPlqtDefault,
  441. PSLQ_TIME_INFO pPlqtValue
  442. )
  443. //
  444. // reads the time value "szValueName" from under hKey and
  445. // returns it in the Value buffer
  446. //
  447. {
  448. DWORD dwStatus = ERROR_SUCCESS;
  449. DWORD dwType = 0;
  450. DWORD dwBufferSize = 0;
  451. SLQ_TIME_INFO plqLocal;
  452. assert (pPlqtValue != NULL);
  453. assert (szValueName != NULL);
  454. if (hKey != NULL) {
  455. // then there should be something to read
  456. // find out the size of the required buffer
  457. dwStatus = RegQueryValueExW (
  458. hKey,
  459. szValueName,
  460. NULL,
  461. &dwType,
  462. NULL,
  463. &dwBufferSize);
  464. if (dwStatus == ERROR_SUCCESS) {
  465. if ((dwBufferSize == sizeof(SLQ_TIME_INFO)) && (dwType == REG_BINARY)) {
  466. // then there's something to read
  467. dwType = 0;
  468. memset (&plqLocal, 0, sizeof(SLQ_TIME_INFO));
  469. dwStatus = RegQueryValueExW (
  470. hKey,
  471. szValueName,
  472. NULL,
  473. &dwType,
  474. (LPBYTE)&plqLocal,
  475. &dwBufferSize);
  476. if ( ERROR_SUCCESS == dwStatus ) {
  477. *pPlqtValue = plqLocal;
  478. }
  479. } else {
  480. // nothing to read
  481. dwStatus = ERROR_NO_DATA;
  482. }
  483. } else {
  484. // unable to read buffer
  485. // dwStatus has error
  486. }
  487. } else {
  488. // null key
  489. dwStatus = ERROR_BADKEY;
  490. }
  491. if (dwStatus != ERROR_SUCCESS) {
  492. LPCWSTR szStringArray[2];
  493. szStringArray[0] = szValueName;
  494. szStringArray[1] = szQueryName;
  495. // apply default if it exists
  496. if (pPlqtDefault != NULL) {
  497. ReportEvent (hEventLog,
  498. EVENTLOG_WARNING_TYPE,
  499. 0,
  500. SMLOG_UNABLE_READ_QUERY_VALUE,
  501. NULL,
  502. 2,
  503. sizeof(DWORD),
  504. szStringArray,
  505. (LPVOID)&dwStatus);
  506. *pPlqtValue = *pPlqtDefault;
  507. dwStatus = ERROR_SUCCESS;
  508. }
  509. // else no default.
  510. // Leave it to the caller to log event.
  511. }
  512. return dwStatus;
  513. }
  514. DWORD
  515. ReadRegistryDwordValue (
  516. HKEY hKey,
  517. LPCWSTR szQueryName,
  518. LPCWSTR szValueName,
  519. PDWORD pdwDefault,
  520. LPDWORD pdwValue
  521. )
  522. //
  523. // reads the DWORD value "szValueName" from under hKey and
  524. // returns it in the Value buffer
  525. //
  526. {
  527. DWORD dwStatus = ERROR_SUCCESS;
  528. DWORD dwType = 0;
  529. DWORD dwBufferSize = 0;
  530. DWORD dwRegValue;
  531. assert (pdwValue != NULL);
  532. assert (szValueName != NULL);
  533. if (hKey != NULL) {
  534. // then there should be something to read
  535. // find out the size of the required buffer
  536. dwStatus = RegQueryValueExW (
  537. hKey,
  538. szValueName,
  539. NULL,
  540. &dwType,
  541. NULL,
  542. &dwBufferSize);
  543. if (dwStatus == ERROR_SUCCESS) {
  544. if ( (dwBufferSize == sizeof(DWORD))
  545. && ( (REG_DWORD == dwType) || ( REG_BINARY == dwType) ) ) {
  546. // then there's something to read
  547. dwType = 0;
  548. dwStatus = RegQueryValueExW (
  549. hKey,
  550. szValueName,
  551. NULL,
  552. &dwType,
  553. (LPBYTE)&dwRegValue,
  554. &dwBufferSize);
  555. if (dwStatus == ERROR_SUCCESS) {
  556. *pdwValue = dwRegValue;
  557. }
  558. } else {
  559. // nothing to read
  560. dwStatus = ERROR_NO_DATA;
  561. }
  562. } else {
  563. // unable to read buffer
  564. // dwStatus has error
  565. }
  566. } else {
  567. // null key
  568. dwStatus = ERROR_BADKEY;
  569. }
  570. if (dwStatus != ERROR_SUCCESS) {
  571. LPCWSTR szStringArray[2];
  572. szStringArray[0] = szValueName;
  573. szStringArray[1] = szQueryName;
  574. if (pdwDefault != NULL) {
  575. ReportEvent (hEventLog,
  576. EVENTLOG_WARNING_TYPE,
  577. 0,
  578. SMLOG_UNABLE_READ_QUERY_VALUE,
  579. NULL,
  580. 2,
  581. sizeof(DWORD),
  582. szStringArray,
  583. (LPVOID)&dwStatus);
  584. *pdwValue = *pdwDefault;
  585. dwStatus = ERROR_SUCCESS;
  586. } // else no default.
  587. // Leave it to the caller to log event.
  588. }
  589. return dwStatus;
  590. }
  591. DWORD
  592. ReadRegistryStringValue (
  593. HKEY hKey,
  594. LPCWSTR szQueryName,
  595. LPCWSTR szValueName,
  596. LPCWSTR szDefault,
  597. LPWSTR *pszBuffer,
  598. LPDWORD pdwLength
  599. )
  600. //
  601. // reads the string value "szValueName" from under hKey and
  602. // frees any existing buffer referenced by pszBuffer,
  603. // then allocates a new buffer returning it with the
  604. // string value read from the registry and the size of the
  605. // buffer (in bytes)
  606. //
  607. {
  608. DWORD dwStatus = ERROR_SUCCESS;
  609. DWORD dwType = 0;
  610. DWORD dwBufferSize = 0;
  611. WCHAR* szNewStringBuffer = NULL;
  612. assert (pdwLength!= NULL);
  613. assert (szValueName != NULL);
  614. *pdwLength = 0;
  615. if (hKey != NULL) {
  616. // then there should be something to read
  617. // find out the size of the required buffer
  618. dwStatus = RegQueryValueExW (
  619. hKey,
  620. szValueName,
  621. NULL,
  622. &dwType,
  623. NULL,
  624. &dwBufferSize);
  625. if (dwStatus == ERROR_SUCCESS) {
  626. // NULL character size is 2 bytes
  627. if (dwBufferSize > 2) {
  628. // then there's something to read
  629. szNewStringBuffer = (WCHAR*) G_ALLOC ( dwBufferSize ); // new UCHAR[dwBufferSize];
  630. if (szNewStringBuffer != NULL) {
  631. dwType = 0;
  632. dwStatus = RegQueryValueExW (
  633. hKey,
  634. szValueName,
  635. NULL,
  636. &dwType,
  637. (LPBYTE)szNewStringBuffer,
  638. &dwBufferSize);
  639. if ( 0 == lstrlenW ( szNewStringBuffer ) ) {
  640. dwStatus = ERROR_NO_DATA;
  641. }
  642. } else {
  643. // Todo: Report event for this case.
  644. dwStatus = ERROR_OUTOFMEMORY;
  645. }
  646. } else {
  647. // nothing to read
  648. dwStatus = ERROR_NO_DATA;
  649. }
  650. } // else unable to read buffer
  651. // dwStatus has error
  652. } else {
  653. // null key
  654. dwStatus = ERROR_BADKEY;
  655. }
  656. if (dwStatus != ERROR_SUCCESS) {
  657. LPCWSTR szStringArray[2];
  658. szStringArray[0] = szValueName;
  659. szStringArray[1] = szQueryName;
  660. if (szNewStringBuffer != NULL) {
  661. G_FREE ( szNewStringBuffer ); //delete (szNewStringBuffer);
  662. szNewStringBuffer = NULL;
  663. dwBufferSize = 0;
  664. }
  665. // apply default
  666. if (szDefault != NULL) {
  667. dwBufferSize = lstrlenW(szDefault) + 1;
  668. if ( 1 < dwBufferSize ) {
  669. dwBufferSize *= sizeof (WCHAR);
  670. szNewStringBuffer = (WCHAR*) G_ALLOC ( dwBufferSize );
  671. if (szNewStringBuffer != NULL) {
  672. ReportEvent (hEventLog,
  673. EVENTLOG_WARNING_TYPE,
  674. 0,
  675. SMLOG_UNABLE_READ_QUERY_VALUE,
  676. NULL,
  677. 2,
  678. sizeof(DWORD),
  679. szStringArray,
  680. (LPVOID)&dwStatus);
  681. lstrcpyW (
  682. szNewStringBuffer,
  683. szDefault);
  684. dwStatus = ERROR_SUCCESS;
  685. } else {
  686. dwStatus = ERROR_OUTOFMEMORY;
  687. ReportEvent (hEventLog,
  688. EVENTLOG_WARNING_TYPE,
  689. 0,
  690. SMLOG_UNABLE_READ_QUERY_DEF_VAL,
  691. NULL,
  692. 2,
  693. sizeof(DWORD),
  694. szStringArray,
  695. (LPVOID)&dwStatus);
  696. }
  697. }
  698. } // else no default so no data returned
  699. // Let the caller log the event if they want to.
  700. // Todo: Report event for OUTOFMEMORY case.
  701. }
  702. if (dwStatus == ERROR_SUCCESS) {
  703. // then delete the old buffer and replace it with
  704. // the new one
  705. if (*pszBuffer != NULL) {
  706. G_FREE (*pszBuffer ); //delete (*pszBuffer );
  707. }
  708. *pszBuffer = szNewStringBuffer;
  709. *pdwLength = dwBufferSize;
  710. } else {
  711. // if error then delete the buffer
  712. if (szNewStringBuffer != NULL) {
  713. G_FREE ( szNewStringBuffer ); //delete (szNewStringBuffer);
  714. *pdwLength = 0;
  715. }
  716. }
  717. return dwStatus;
  718. }
  719. DWORD
  720. ReadRegistryIndirectStringValue (
  721. HKEY hKey,
  722. LPCWSTR szQueryName, // For error logging
  723. LPCWSTR szValueName,
  724. LPCWSTR szDefault,
  725. LPWSTR* pszBuffer,
  726. UINT* puiLength )
  727. {
  728. DWORD dwStatus = ERROR_SUCCESS;
  729. LPCWSTR szStringArray[2];
  730. szStringArray[0] = szValueName;
  731. szStringArray[1] = szQueryName;
  732. dwStatus = SmReadRegistryIndirectStringValue (
  733. hKey,
  734. szValueName,
  735. szDefault,
  736. pszBuffer,
  737. puiLength );
  738. /*
  739. Todo: Report event on failure
  740. if ( NULL != szDefault ) {
  741. ReportEvent (hEventLog,
  742. EVENTLOG_WARNING_TYPE,
  743. 0,
  744. SMLOG_UNABLE_READ_QUERY_VALUE_NODEF,
  745. NULL,
  746. 2,
  747. sizeof(DWORD),
  748. szStringArray,
  749. (LPVOID)&dwStatus);
  750. }
  751. */
  752. return dwStatus;
  753. }
  754. DWORD
  755. WriteRegistryDwordValue (
  756. HKEY hKey,
  757. LPCWSTR szValueName,
  758. LPDWORD pdwValue,
  759. DWORD dwType
  760. )
  761. {
  762. DWORD dwStatus = ERROR_SUCCESS;
  763. DWORD dwValue = sizeof(DWORD);
  764. assert ((dwType == REG_DWORD) ||
  765. (dwType == REG_BINARY));
  766. dwStatus = RegSetValueEx (
  767. hKey, szValueName, 0L,
  768. dwType,
  769. (CONST BYTE *)pdwValue,
  770. dwValue);
  771. return dwStatus;
  772. }
  773. DWORD
  774. WriteRegistrySlqTime (
  775. HKEY hKey,
  776. LPCWSTR szValueName,
  777. PSLQ_TIME_INFO pSlqTime
  778. )
  779. {
  780. DWORD dwStatus = ERROR_SUCCESS;
  781. DWORD dwValue = sizeof(SLQ_TIME_INFO);
  782. dwStatus = RegSetValueEx (
  783. hKey, szValueName, 0L,
  784. REG_BINARY,
  785. (CONST BYTE *)pSlqTime,
  786. dwValue);
  787. return dwStatus;
  788. }
  789. DWORD
  790. BuildCurrentLogFileName (
  791. IN LPCTSTR szQueryName,
  792. IN LPCTSTR szBaseFileName,
  793. IN LPCTSTR szDefaultDir,
  794. IN LPCTSTR szSqlLogName,
  795. IN LPTSTR szOutFileBuffer,
  796. IN LPDWORD lpdwSerialNumber,
  797. IN DWORD dwAutoNameFormat,
  798. IN DWORD dwLogFileType,
  799. IN INT iCnfSerial
  800. )
  801. // presumes OutFileBuffer is large enough (i.e. >= MAX_PATH+1)
  802. {
  803. DWORD dwStatus = ERROR_SUCCESS;
  804. PPDH_PLA_INFO pInfo = NULL;
  805. DWORD dwStrBufLen = 0;
  806. DWORD dwInfoSize = 0;
  807. DWORD dwFlags = 0;
  808. dwStatus = PdhPlaGetInfo(
  809. (LPTSTR)szQueryName,
  810. NULL,
  811. &dwInfoSize,
  812. pInfo );
  813. if( ERROR_SUCCESS == dwStatus && 0 != dwInfoSize ){
  814. pInfo = (PPDH_PLA_INFO)G_ALLOC(dwInfoSize);
  815. if( NULL != pInfo && (sizeof(PDH_PLA_INFO) <= dwInfoSize) ){
  816. ZeroMemory( pInfo, dwInfoSize );
  817. pInfo->dwMask = PLA_INFO_FLAG_FORMAT|
  818. PLA_INFO_FLAG_FILENAME|
  819. PLA_INFO_FLAG_AUTOFORMAT|
  820. PLA_INFO_FLAG_TYPE|
  821. PLA_INFO_FLAG_DEFAULTDIR|
  822. PLA_INFO_FLAG_SRLNUMBER|
  823. PLA_INFO_FLAG_SQLNAME|
  824. PLA_INFO_FLAG_STATUS;
  825. dwStatus = PdhPlaGetInfo(
  826. (LPTSTR)szQueryName,
  827. NULL,
  828. &dwInfoSize,
  829. pInfo );
  830. pInfo->dwFileFormat = dwLogFileType;
  831. pInfo->strBaseFileName = (LPTSTR)szBaseFileName;
  832. pInfo->dwAutoNameFormat = dwAutoNameFormat;
  833. // PLA_INFO_FLAG_TYPE is counter log vs trace log vs alert
  834. pInfo->strDefaultDir = (LPTSTR)szDefaultDir;
  835. pInfo->dwLogFileSerialNumber = *lpdwSerialNumber;
  836. pInfo->strSqlName = (LPTSTR)szSqlLogName;
  837. dwFlags = PLA_FILENAME_CREATEONLY;
  838. // iCnfSerial = 0 - No serial suffix for Create New File
  839. // iCnfSerial = -1 - Include format string for trace file serial number.
  840. if ( 0 == iCnfSerial ) {
  841. pInfo->ptCreateNewFile.dwAutoMode = SLQ_AUTO_MODE_NONE;
  842. } else {
  843. dwFlags |= PLA_FILENAME_USE_SUBEXT;
  844. if ( -1 == iCnfSerial ) {
  845. dwFlags |= PLA_FILENAME_GET_SUBFMT;
  846. pInfo->ptCreateNewFile.dwAutoMode = SLQ_AUTO_MODE_SIZE;
  847. } else {
  848. pInfo->ptCreateNewFile.dwAutoMode = SLQ_AUTO_MODE_AFTER;
  849. pInfo->dwReserved1 = iCnfSerial;
  850. }
  851. }
  852. dwStatus = PdhPlaGetLogFileName (
  853. (LPTSTR)szQueryName,
  854. NULL,
  855. pInfo,
  856. dwFlags,
  857. &dwStrBufLen,
  858. NULL );
  859. if ( ERROR_SUCCESS == dwStatus || PDH_INSUFFICIENT_BUFFER == dwStatus ) {
  860. // todo: remove buf length restriction
  861. if ( dwStrBufLen <= MAX_PATH * sizeof(WCHAR) ) {
  862. dwStatus = PdhPlaGetLogFileName (
  863. (LPTSTR)szQueryName,
  864. NULL,
  865. pInfo,
  866. dwFlags,
  867. &dwStrBufLen,
  868. szOutFileBuffer );
  869. }
  870. }
  871. }
  872. }
  873. if ( NULL != pInfo ) {
  874. G_FREE( pInfo );
  875. }
  876. return dwStatus;
  877. }
  878. BOOL
  879. FileExists (
  880. IN LPCTSTR szFileName )
  881. {
  882. DWORD dwStatus = ERROR_SUCCESS;
  883. BOOL bFileExists = FALSE;
  884. HANDLE hFile = NULL;
  885. LONG lErrorMode;
  886. if ( NULL != szFileName ) {
  887. lErrorMode = SetErrorMode ( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
  888. hFile = CreateFile(
  889. szFileName,
  890. GENERIC_READ | GENERIC_WRITE,
  891. FILE_SHARE_READ | FILE_SHARE_WRITE,
  892. NULL,
  893. OPEN_EXISTING,
  894. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
  895. NULL
  896. );
  897. if (INVALID_HANDLE_VALUE == hFile ) {
  898. dwStatus = GetLastError();
  899. }
  900. if ( NULL != hFile
  901. && INVALID_HANDLE_VALUE != hFile
  902. && ERROR_SUCCESS == dwStatus )
  903. {
  904. bFileExists = TRUE;
  905. }
  906. CloseHandle(hFile);
  907. SetErrorMode ( lErrorMode );
  908. } else {
  909. dwStatus = ERROR_INVALID_PARAMETER;
  910. }
  911. return bFileExists;
  912. }
  913. DWORD
  914. LoadCommonConfig(
  915. IN PLOG_QUERY_DATA pQuery)
  916. {
  917. DWORD dwStatus = ERROR_SUCCESS;
  918. DWORD dwBufferSize = 0;
  919. UINT uiBufferLen = 0;
  920. SLQ_TIME_INFO stiDefault;
  921. DWORD dwDefault;
  922. DWORD dwTempRestart;
  923. SYSTEMTIME stLocalTime;
  924. FILETIME ftLocalTime;
  925. DWORD dwLocalMask = 0;
  926. DWORD dwLocalAttributes = 0;
  927. // Schedule
  928. dwDefault = SLQ_QUERY_STOPPED;
  929. dwStatus = ReadRegistryDwordValue (
  930. pQuery->hKeyQuery,
  931. pQuery->szQueryName,
  932. (LPCTSTR)L"Current State",
  933. &dwDefault,
  934. &pQuery->dwCurrentState);
  935. if ( ERROR_SUCCESS == dwStatus ) {
  936. // Pass NULL default to avoid warning message.
  937. // A missing value here is normal, converting from Win2000 config.
  938. dwStatus = ReadRegistryDwordValue (
  939. pQuery->hKeyQuery,
  940. pQuery->szQueryName,
  941. (LPCTSTR)L"RealTime DataSource",
  942. NULL,
  943. &pQuery->dwRealTimeQuery);
  944. if ( ERROR_NO_DATA == dwStatus
  945. || ERROR_FILE_NOT_FOUND == dwStatus
  946. || ( 0 == pQuery->dwRealTimeQuery ) ) {
  947. pQuery->dwRealTimeQuery = GetSystemWideDefaultNullDataSource();
  948. dwStatus = ERROR_SUCCESS;
  949. }
  950. }
  951. if ( ERROR_SUCCESS == dwStatus ) {
  952. GetLocalTime (&stLocalTime);
  953. SystemTimeToFileTime (&stLocalTime, &ftLocalTime);
  954. stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
  955. stiDefault.wTimeType = SLQ_TT_TTYPE_START;
  956. stiDefault.dwAutoMode = SLQ_AUTO_MODE_AT;
  957. stiDefault.llDateTime = *(LONGLONG *)&ftLocalTime;
  958. dwStatus = ReadRegistrySlqTime (
  959. pQuery->hKeyQuery,
  960. pQuery->szQueryName,
  961. (LPCTSTR)L"Start",
  962. &stiDefault,
  963. &pQuery->stiRegStart);
  964. }
  965. if ( ERROR_SUCCESS == dwStatus ) {
  966. stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
  967. stiDefault.wTimeType = SLQ_TT_TTYPE_STOP;
  968. stiDefault.dwAutoMode = SLQ_AUTO_MODE_NONE;
  969. stiDefault.llDateTime = MIN_TIME_VALUE;
  970. dwStatus = ReadRegistrySlqTime (
  971. pQuery->hKeyQuery,
  972. pQuery->szQueryName,
  973. (LPCTSTR)L"Stop",
  974. &stiDefault,
  975. &pQuery->stiRegStop);
  976. }
  977. if ( ERROR_SUCCESS == dwStatus ) {
  978. // Apply default value outside of Read method, to avoid
  979. // error message. This value does not exist in Windows 2000
  980. dwStatus = ReadRegistrySlqTime (
  981. pQuery->hKeyQuery,
  982. pQuery->szQueryName,
  983. (LPCTSTR)L"Create New File",
  984. NULL,
  985. &pQuery->stiCreateNewFile);
  986. if ( ERROR_NO_DATA == dwStatus || ERROR_FILE_NOT_FOUND == dwStatus ) {
  987. stiDefault.wDataType = SLQ_TT_DTYPE_UNITS;
  988. stiDefault.wTimeType = SLQ_TT_TTYPE_CREATE_NEW_FILE;
  989. stiDefault.dwAutoMode = SLQ_AUTO_MODE_NONE;
  990. stiDefault.dwUnitType = SLQ_TT_UTYPE_SECONDS;
  991. stiDefault.dwValue = 0;
  992. pQuery->stiCreateNewFile = stiDefault;
  993. dwStatus = ERROR_SUCCESS;
  994. }
  995. }
  996. // Restart flag is replaced by the Repeat time structure after Windows 2000.
  997. if ( ERROR_SUCCESS == dwStatus ) {
  998. // If autostop, collect Restart value.
  999. // Apply default value outside of Read method, to avoid
  1000. // error message. This value does not exist in Windows 2000
  1001. if ( pQuery->stiRegStop.dwAutoMode != SLQ_AUTO_MODE_NONE ) {
  1002. dwStatus = ReadRegistryDwordValue (
  1003. pQuery->hKeyQuery,
  1004. pQuery->szQueryName,
  1005. (LPCTSTR)L"Restart",
  1006. NULL,
  1007. &dwTempRestart );
  1008. if ( ERROR_NO_DATA == dwStatus
  1009. || ERROR_FILE_NOT_FOUND == dwStatus )
  1010. {
  1011. dwTempRestart = SLQ_AUTO_MODE_NONE;
  1012. dwStatus = ERROR_SUCCESS;
  1013. }
  1014. }
  1015. }
  1016. if ( ERROR_SUCCESS == dwStatus ) {
  1017. // If autostop, collect Repeat value.
  1018. // Apply default value outside of Read method, to avoid
  1019. // error message. This value does not exist in Windows 2000
  1020. if ( pQuery->stiRegStop.dwAutoMode != SLQ_AUTO_MODE_NONE ) {
  1021. dwStatus = ReadRegistrySlqTime (
  1022. pQuery->hKeyQuery,
  1023. pQuery->szQueryName,
  1024. (LPCTSTR)L"Repeat Schedule",
  1025. NULL,
  1026. &pQuery->stiRepeat );
  1027. if ( ERROR_NO_DATA == dwStatus
  1028. || ERROR_FILE_NOT_FOUND == dwStatus
  1029. || SLQ_AUTO_MODE_NONE == pQuery->stiRepeat.dwAutoMode )
  1030. {
  1031. // If the repeat value doesn't exist or is set to NONE,
  1032. // default to the Restart mode value: NONE or AFTER
  1033. stiDefault.wDataType = SLQ_TT_DTYPE_UNITS;
  1034. stiDefault.wTimeType = SLQ_TT_TTYPE_REPEAT_SCHEDULE;
  1035. stiDefault.dwAutoMode = dwTempRestart;
  1036. stiDefault.dwUnitType = SLQ_TT_UTYPE_MINUTES;
  1037. stiDefault.dwValue = 0;
  1038. pQuery->stiRepeat = stiDefault;
  1039. dwStatus = ERROR_SUCCESS;
  1040. }
  1041. }
  1042. }
  1043. if ( ERROR_SUCCESS == dwStatus ) {
  1044. // Todo: Log error events
  1045. if ( NULL == pQuery->szLogFileComment ) {
  1046. uiBufferLen = 0;
  1047. } else {
  1048. uiBufferLen = lstrlen ( pQuery->szLogFileComment ) + 1;
  1049. }
  1050. ReadRegistryIndirectStringValue (
  1051. pQuery->hKeyQuery,
  1052. pQuery->szQueryName,
  1053. (LPCWSTR)L"Comment",
  1054. NULL,
  1055. &pQuery->szLogFileComment,
  1056. &uiBufferLen );
  1057. // Ignore status, default is empty.
  1058. }
  1059. // Todo: File attributes only for counter and trace logs
  1060. // File attributes
  1061. if ( ERROR_SUCCESS == dwStatus ) {
  1062. dwDefault = (DWORD)-1;
  1063. dwStatus = ReadRegistryDwordValue (
  1064. pQuery->hKeyQuery,
  1065. pQuery->szQueryName,
  1066. (LPCTSTR)L"Log File Max Size",
  1067. &dwDefault,
  1068. &pQuery->dwMaxFileSize);
  1069. }
  1070. if ( ERROR_SUCCESS == dwStatus ) {
  1071. dwDefault = SLF_BIN_FILE;
  1072. dwStatus = ReadRegistryDwordValue (
  1073. pQuery->hKeyQuery,
  1074. pQuery->szQueryName,
  1075. (LPCTSTR)L"Log File Type",
  1076. &dwDefault,
  1077. &pQuery->dwLogFileType);
  1078. if (dwStatus == ERROR_SUCCESS) {
  1079. pQuery->dwLogFileType = LOWORD(pQuery->dwLogFileType);
  1080. // For Whistler Beta 1, append mode stored in high word of
  1081. // the log type registry value
  1082. pQuery->dwAppendMode =
  1083. (pQuery->dwLogFileType & 0xFFFF0000) == SLF_FILE_APPEND;
  1084. }
  1085. }
  1086. if ( ERROR_SUCCESS == dwStatus ) {
  1087. // Pass NULL default to avoid warning message.
  1088. // A missing value here is normal, converting from Win2000 config.
  1089. dwLocalAttributes = 0;
  1090. dwStatus = ReadRegistryDwordValue (
  1091. pQuery->hKeyQuery,
  1092. pQuery->szQueryName,
  1093. (LPCTSTR)L"Data Store Attributes",
  1094. NULL,
  1095. &dwLocalAttributes );
  1096. // Extract log file size units
  1097. if ( ERROR_NO_DATA == dwStatus
  1098. || ERROR_FILE_NOT_FOUND == dwStatus
  1099. || ( 0 == ( dwLocalAttributes & SLF_DATA_STORE_SIZE_MASK ) ) ) {
  1100. // If file size unit value is missing, default to Win2000 values
  1101. if ( SLQ_COUNTER_LOG == pQuery->dwLogType ) {
  1102. if ( SLF_SQL_LOG != pQuery->dwLogFileType ) {
  1103. pQuery->dwLogFileSizeUnit = ONE_KB;
  1104. } else {
  1105. pQuery->dwLogFileSizeUnit = ONE_RECORD;
  1106. }
  1107. } else if ( SLQ_TRACE_LOG == pQuery->dwLogType ) {
  1108. pQuery->dwLogFileSizeUnit = ONE_MB;
  1109. }
  1110. } else {
  1111. if ( dwLocalAttributes & SLF_DATA_STORE_SIZE_ONE_MB ) {
  1112. pQuery->dwLogFileSizeUnit = ONE_MB;
  1113. } else if ( dwLocalAttributes & SLF_DATA_STORE_SIZE_ONE_KB ) {
  1114. pQuery->dwLogFileSizeUnit = ONE_KB;
  1115. } else if ( dwLocalAttributes & SLF_DATA_STORE_SIZE_ONE_RECORD ) {
  1116. pQuery->dwLogFileSizeUnit = ONE_RECORD;
  1117. }
  1118. }
  1119. // Extract append flag if not already set by Whistler Beta 1 code
  1120. if ( 0 == pQuery->dwAppendMode ) {
  1121. if ( ERROR_NO_DATA == dwStatus
  1122. || ERROR_FILE_NOT_FOUND == dwStatus
  1123. || ( 0 == ( dwLocalAttributes & SLF_DATA_STORE_APPEND_MASK ) ) )
  1124. {
  1125. // If file append mode value is missing, default to Win2000 values
  1126. assert ( SLF_SQL_LOG != pQuery->dwLogFileType );
  1127. if ( SLF_SQL_LOG != pQuery->dwLogFileType ) {
  1128. pQuery->dwAppendMode = 0;
  1129. }
  1130. } else {
  1131. pQuery->dwAppendMode = ( dwLocalAttributes & SLF_DATA_STORE_APPEND );
  1132. }
  1133. }
  1134. dwStatus = ERROR_SUCCESS;
  1135. }
  1136. if ( ERROR_SUCCESS == dwStatus ) {
  1137. dwDefault = SLF_NAME_NNNNNN;
  1138. dwStatus = ReadRegistryDwordValue (
  1139. pQuery->hKeyQuery,
  1140. pQuery->szQueryName,
  1141. (LPCTSTR)L"Log File Auto Format",
  1142. &dwDefault,
  1143. &pQuery->dwAutoNameFormat );
  1144. }
  1145. if ( ERROR_SUCCESS == dwStatus ) {
  1146. WCHAR szDefault[MAX_PATH+1];
  1147. // Dependent on AutoNameFormat setting.
  1148. if ( SLF_NAME_NONE == pQuery->dwAutoNameFormat ) {
  1149. // Default log file name is query name, if no autoformat.
  1150. lstrcpyW ( ( LPWSTR)szDefault, pQuery->szQueryName );
  1151. } else {
  1152. szDefault[0] = _T('\0');
  1153. }
  1154. if ( NULL == pQuery->szBaseFileName ) {
  1155. uiBufferLen = 0;
  1156. } else {
  1157. uiBufferLen = lstrlen ( pQuery->szBaseFileName ) + 1;
  1158. }
  1159. ReadRegistryIndirectStringValue (
  1160. pQuery->hKeyQuery,
  1161. pQuery->szQueryName,
  1162. (LPCWSTR)L"Log File Base Name",
  1163. szDefault,
  1164. &pQuery->szBaseFileName,
  1165. &uiBufferLen );
  1166. ReplaceBlanksWithUnderscores ( pQuery->szBaseFileName );
  1167. if ( 0 == lstrlen (szDefault) ) {
  1168. if ( NULL != pQuery->szBaseFileName ) {
  1169. if ( 0 == lstrlen ( pQuery->szBaseFileName ) ) {
  1170. // Ignore bad status if the base log file name
  1171. //is NULL and auto format is enabled.
  1172. dwStatus = ERROR_SUCCESS;
  1173. }
  1174. } else {
  1175. // Ignore bad status if the base log file name
  1176. //is NULL and auto format is enabled.
  1177. dwStatus = ERROR_SUCCESS;
  1178. }
  1179. }
  1180. }
  1181. if ( ERROR_SUCCESS == dwStatus ) {
  1182. TCHAR* pszTemp = NULL;
  1183. DWORD cchLen = 0;
  1184. DWORD cchExpandedLen = 0;
  1185. dwStatus = ReadRegistryStringValue (
  1186. pQuery->hKeyQuery,
  1187. pQuery->szQueryName,
  1188. (LPCTSTR)L"Log File Folder",
  1189. gszDefaultLogFileFolder,
  1190. &pszTemp,
  1191. &dwBufferSize );
  1192. //
  1193. // Parse all environment variables
  1194. //
  1195. if (pszTemp != NULL) {
  1196. cchLen = ExpandEnvironmentStrings ( pszTemp, NULL, 0 );
  1197. if ( 0 < cchLen ) {
  1198. //
  1199. // cchLen includes NULL.
  1200. //
  1201. if ( NULL != pQuery->szLogFileFolder ) {
  1202. G_FREE (pQuery->szLogFileFolder );
  1203. pQuery->szLogFileFolder = NULL;
  1204. }
  1205. pQuery->szLogFileFolder = G_ALLOC ( cchLen * sizeof(WCHAR) );
  1206. if ( NULL != pQuery->szLogFileFolder ) {
  1207. cchExpandedLen = ExpandEnvironmentStrings (
  1208. pszTemp,
  1209. pQuery->szLogFileFolder,
  1210. cchLen );
  1211. if ( 0 == cchExpandedLen ) {
  1212. dwStatus = GetLastError();
  1213. pQuery->szLogFileFolder[0] = L'\0';
  1214. }
  1215. } else {
  1216. dwStatus = ERROR_OUTOFMEMORY;
  1217. }
  1218. } else {
  1219. dwStatus = GetLastError();
  1220. }
  1221. }
  1222. if ( NULL != pszTemp ) {
  1223. G_FREE ( pszTemp );
  1224. }
  1225. }
  1226. if ( ERROR_SUCCESS == dwStatus ) {
  1227. ReadRegistryStringValue (
  1228. pQuery->hKeyQuery,
  1229. pQuery->szQueryName,
  1230. (LPCTSTR)L"Sql Log Base Name",
  1231. NULL,
  1232. &pQuery->szSqlLogName,
  1233. &dwBufferSize );
  1234. // Ignore status, default is empty.
  1235. }
  1236. if ( ERROR_SUCCESS == dwStatus ) {
  1237. dwDefault = 1;
  1238. dwStatus = ReadRegistryDwordValue (
  1239. pQuery->hKeyQuery,
  1240. pQuery->szQueryName,
  1241. (LPCTSTR)L"Log File Serial Number",
  1242. &dwDefault,
  1243. &pQuery->dwCurrentSerialNumber );
  1244. }
  1245. return dwStatus;
  1246. }
  1247. DWORD
  1248. LoadQueryConfig(
  1249. IN PLOG_QUERY_DATA pQuery )
  1250. {
  1251. DWORD dwStatus = ERROR_SUCCESS;
  1252. DWORD dwBufferSize;
  1253. UINT uiBufferLen = 0;
  1254. LPTSTR szStringArray[2];
  1255. SLQ_TIME_INFO stiDefault;
  1256. SLQ_TIME_INFO stiTemp;
  1257. DWORD dwDefault;
  1258. DWORD dwType;
  1259. // Do not write event for invalid log type.
  1260. dwType = REG_DWORD;
  1261. dwBufferSize = sizeof(DWORD);
  1262. dwStatus = RegQueryValueExW (
  1263. pQuery->hKeyQuery,
  1264. (LPCTSTR)L"Log Type",
  1265. NULL,
  1266. &dwType,
  1267. (LPBYTE)&pQuery->dwLogType,
  1268. &dwBufferSize);
  1269. if ( SLQ_COUNTER_LOG == pQuery->dwLogType ) {
  1270. // Counters
  1271. dwStatus = ReadRegistryStringValue (
  1272. pQuery->hKeyQuery,
  1273. pQuery->szQueryName,
  1274. (LPCTSTR)L"Counter List",
  1275. NULL,
  1276. &pQuery->mszCounterList,
  1277. &dwBufferSize );
  1278. if ( (ERROR_SUCCESS != dwStatus ) || ( 0 == dwBufferSize ) ) {
  1279. // no counter list retrieved so there's not much
  1280. // point in continuing
  1281. szStringArray[0] = pQuery->szQueryName;
  1282. ReportEvent (hEventLog,
  1283. EVENTLOG_WARNING_TYPE,
  1284. 0,
  1285. SMLOG_UNABLE_READ_COUNTER_LIST,
  1286. NULL,
  1287. 1,
  1288. sizeof(DWORD),
  1289. szStringArray,
  1290. (LPVOID)&dwStatus);
  1291. } else {
  1292. // Schedule
  1293. // Collect Command file value.
  1294. if ( ERROR_SUCCESS == dwStatus ) {
  1295. ReadRegistryStringValue (
  1296. pQuery->hKeyQuery,
  1297. pQuery->szQueryName,
  1298. (LPCTSTR)L"EOF Command File",
  1299. NULL,
  1300. &pQuery->szCmdFileName,
  1301. &dwBufferSize );
  1302. // Ignore status, default is empty.
  1303. }
  1304. if ( ERROR_SUCCESS == dwStatus ) {
  1305. stiDefault.wDataType = SLQ_TT_DTYPE_UNITS;
  1306. stiDefault.wTimeType = SLQ_TT_TTYPE_SAMPLE;
  1307. stiDefault.dwAutoMode = SLQ_AUTO_MODE_AFTER;
  1308. stiDefault.dwUnitType = SLQ_TT_UTYPE_SECONDS;
  1309. stiDefault.dwValue = 15;
  1310. dwStatus = ReadRegistrySlqTime (
  1311. pQuery->hKeyQuery,
  1312. pQuery->szQueryName,
  1313. (LPCTSTR)L"Sample Interval",
  1314. &stiDefault,
  1315. &stiTemp);
  1316. if ( ERROR_SUCCESS == dwStatus ) {
  1317. LONGLONG llMillisecInterval;
  1318. TimeInfoToMilliseconds( &stiTemp, &llMillisecInterval );
  1319. assert ( ULONG_MAX > llMillisecInterval );
  1320. if ( ULONG_MAX > llMillisecInterval ) {
  1321. pQuery->dwMillisecondSampleInterval = (DWORD)(llMillisecInterval);
  1322. } else {
  1323. pQuery->dwMillisecondSampleInterval = ULONG_MAX - 1;
  1324. }
  1325. }
  1326. }
  1327. }
  1328. } else if ( SLQ_ALERT == pQuery->dwLogType) {
  1329. // Counters & alert limits
  1330. dwStatus = ReadRegistryStringValue (
  1331. pQuery->hKeyQuery,
  1332. pQuery->szQueryName,
  1333. (LPCTSTR)L"Counter List",
  1334. NULL,
  1335. &pQuery->mszCounterList,
  1336. &dwBufferSize );
  1337. if ( (ERROR_SUCCESS != dwStatus ) || ( 0 == dwBufferSize ) ) {
  1338. // no counter list retrieved so there's not much
  1339. // point in continuing
  1340. szStringArray[0] = pQuery->szQueryName;
  1341. ReportEvent (hEventLog,
  1342. EVENTLOG_WARNING_TYPE,
  1343. 0,
  1344. SMLOG_UNABLE_READ_COUNTER_LIST,
  1345. NULL,
  1346. 1,
  1347. sizeof(DWORD),
  1348. szStringArray,
  1349. (LPVOID)&dwStatus);
  1350. } else {
  1351. // Schedule
  1352. if ( ERROR_SUCCESS == dwStatus ) {
  1353. stiDefault.wDataType = SLQ_TT_DTYPE_UNITS;
  1354. stiDefault.wTimeType = SLQ_TT_TTYPE_SAMPLE;
  1355. stiDefault.dwAutoMode = SLQ_AUTO_MODE_AFTER;
  1356. stiDefault.dwUnitType = SLQ_TT_UTYPE_SECONDS;
  1357. stiDefault.dwValue = 15;
  1358. dwStatus = ReadRegistrySlqTime (
  1359. pQuery->hKeyQuery,
  1360. pQuery->szQueryName,
  1361. (LPCTSTR)L"Sample Interval",
  1362. &stiDefault,
  1363. &stiTemp);
  1364. if ( ERROR_SUCCESS == dwStatus ) {
  1365. LONGLONG llMillisecInterval;
  1366. TimeInfoToMilliseconds( &stiTemp, &llMillisecInterval );
  1367. assert ( ULONG_MAX > llMillisecInterval );
  1368. if ( ULONG_MAX > llMillisecInterval ) {
  1369. pQuery->dwMillisecondSampleInterval = (DWORD)(llMillisecInterval);
  1370. } else {
  1371. pQuery->dwMillisecondSampleInterval = ULONG_MAX - 1;
  1372. }
  1373. }
  1374. }
  1375. if ( ERROR_SUCCESS == dwStatus ) {
  1376. // get action flags
  1377. dwDefault = 0;
  1378. dwStatus = ReadRegistryDwordValue (
  1379. pQuery->hKeyQuery,
  1380. pQuery->szQueryName,
  1381. (LPCTSTR)L"Action Flags",
  1382. &dwDefault,
  1383. &pQuery->dwAlertActionFlags);
  1384. }
  1385. if (( ERROR_SUCCESS == dwStatus ) &&
  1386. ((pQuery->dwAlertActionFlags & ALRT_ACTION_SEND_MSG) != 0)) {
  1387. dwStatus = ReadRegistryStringValue (
  1388. pQuery->hKeyQuery,
  1389. pQuery->szQueryName,
  1390. (LPCTSTR)L"Network Name",
  1391. (LPCTSTR)L"",
  1392. &pQuery->szNetName,
  1393. &dwBufferSize );
  1394. }
  1395. if (( ERROR_SUCCESS == dwStatus ) &&
  1396. ((pQuery->dwAlertActionFlags & ALRT_ACTION_EXEC_CMD) != 0)) {
  1397. ReadRegistryStringValue (
  1398. pQuery->hKeyQuery,
  1399. pQuery->szQueryName,
  1400. (LPCTSTR)L"Command File",
  1401. NULL,
  1402. &pQuery->szCmdFileName,
  1403. &dwBufferSize );
  1404. if (( ERROR_SUCCESS == dwStatus ) &&
  1405. ((pQuery->dwAlertActionFlags & ALRT_CMD_LINE_U_TEXT) != 0)) {
  1406. // Todo: Log error events
  1407. if ( NULL == pQuery->szUserText ) {
  1408. uiBufferLen = 0;
  1409. } else {
  1410. uiBufferLen = lstrlen ( pQuery->szUserText ) + 1;
  1411. }
  1412. ReadRegistryIndirectStringValue (
  1413. pQuery->hKeyQuery,
  1414. pQuery->szQueryName,
  1415. (LPCTSTR)L"User Text",
  1416. (LPCTSTR)L"",
  1417. &pQuery->szUserText,
  1418. &uiBufferLen );
  1419. // Ignore status, default is empty.
  1420. }
  1421. }
  1422. if (( ERROR_SUCCESS == dwStatus ) &&
  1423. ((pQuery->dwAlertActionFlags & ALRT_ACTION_START_LOG) != 0)) {
  1424. dwStatus = ReadRegistryStringValue (
  1425. pQuery->hKeyQuery,
  1426. pQuery->szQueryName,
  1427. (LPCTSTR)L"Perf Log Name",
  1428. (LPCTSTR)L"",
  1429. &pQuery->szPerfLogName,
  1430. &dwBufferSize );
  1431. }
  1432. }
  1433. } else if ( SLQ_TRACE_LOG == pQuery->dwLogType ) {
  1434. // get trace log values
  1435. DWORD dwProviderStatus;
  1436. dwDefault = 0;
  1437. dwStatus = ReadRegistryDwordValue (
  1438. pQuery->hKeyQuery,
  1439. pQuery->szQueryName,
  1440. (LPCTSTR)L"Trace Flags",
  1441. &dwDefault,
  1442. &pQuery->dwFlags);
  1443. dwProviderStatus = ReadRegistryStringValue (
  1444. pQuery->hKeyQuery,
  1445. pQuery->szQueryName,
  1446. (LPCTSTR)L"Trace Provider List",
  1447. NULL,
  1448. &pQuery->mszProviderList,
  1449. &dwBufferSize );
  1450. if ( 0 == dwBufferSize ) {
  1451. if ( (ERROR_SUCCESS != dwProviderStatus )
  1452. && ( ! IsKernelTraceMode( pQuery->dwFlags ) ) ) {
  1453. // No provider list retrieved and not kernel trace so there's not much
  1454. // point in continuing
  1455. if ( ERROR_SUCCESS == dwStatus ) {
  1456. dwStatus = SMLOG_UNABLE_READ_PROVIDER_LIST;
  1457. }
  1458. szStringArray[0] = pQuery->szQueryName;
  1459. ReportEvent (hEventLog,
  1460. EVENTLOG_WARNING_TYPE,
  1461. 0,
  1462. SMLOG_UNABLE_READ_PROVIDER_LIST,
  1463. NULL,
  1464. 1,
  1465. sizeof(DWORD),
  1466. szStringArray,
  1467. (LPVOID)&dwStatus);
  1468. } else {
  1469. // Allocate a minimal buffer for the NULL character to simplify later logic.
  1470. pQuery->mszProviderList = G_ALLOC ( sizeof(TCHAR) );
  1471. if ( NULL != pQuery->mszProviderList ) {
  1472. pQuery->mszProviderList[0] = _T('\0');
  1473. } else{
  1474. dwStatus = ERROR_OUTOFMEMORY;
  1475. szStringArray[0] = pQuery->szQueryName;
  1476. ReportEvent (hEventLog,
  1477. EVENTLOG_WARNING_TYPE,
  1478. 0,
  1479. SMLOG_UNABLE_READ_PROVIDER_LIST,
  1480. NULL,
  1481. 1,
  1482. sizeof(DWORD),
  1483. szStringArray,
  1484. (LPVOID)&dwStatus);
  1485. }
  1486. }
  1487. }
  1488. if ( ERROR_SUCCESS == dwStatus ) {
  1489. dwDefault = 4;
  1490. dwStatus = ReadRegistryDwordValue (
  1491. pQuery->hKeyQuery,
  1492. pQuery->szQueryName,
  1493. (LPCTSTR)L"Trace Buffer Size",
  1494. &dwDefault,
  1495. &pQuery->dwBufferSize);
  1496. }
  1497. if ( ERROR_SUCCESS == dwStatus ) {
  1498. dwDefault = 2;
  1499. dwStatus = ReadRegistryDwordValue (
  1500. pQuery->hKeyQuery,
  1501. pQuery->szQueryName,
  1502. (LPCTSTR)L"Trace Buffer Min Count",
  1503. &dwDefault,
  1504. &pQuery->dwBufferMinCount);
  1505. }
  1506. if ( ERROR_SUCCESS == dwStatus ) {
  1507. dwDefault = 25;
  1508. dwStatus = ReadRegistryDwordValue (
  1509. pQuery->hKeyQuery,
  1510. pQuery->szQueryName,
  1511. (LPCTSTR)L"Trace Buffer Max Count",
  1512. &dwDefault,
  1513. &pQuery->dwBufferMaxCount);
  1514. }
  1515. if ( ERROR_SUCCESS == dwStatus ) {
  1516. dwDefault = 0;
  1517. dwStatus = ReadRegistryDwordValue (
  1518. pQuery->hKeyQuery,
  1519. pQuery->szQueryName,
  1520. (LPCTSTR)L"Trace Buffer Flush Interval",
  1521. &dwDefault,
  1522. &pQuery->dwBufferFlushInterval);
  1523. }
  1524. // Schedule
  1525. // Collect Command file value.
  1526. // This is true for both Counter and Trace log files.
  1527. // Alerts use the Command file field for Alert command file.
  1528. if ( ERROR_SUCCESS == dwStatus ) {
  1529. ReadRegistryStringValue (
  1530. pQuery->hKeyQuery,
  1531. pQuery->szQueryName,
  1532. (LPCTSTR)L"EOF Command File",
  1533. NULL,
  1534. &pQuery->szCmdFileName,
  1535. &dwBufferSize );
  1536. // Ignore status, default is empty.
  1537. }
  1538. } else {
  1539. // Ignore partly created logs and alerts.
  1540. assert ( SLQ_NEW_LOG == pQuery->dwLogType );
  1541. if ( SLQ_NEW_LOG == pQuery->dwLogType ) {
  1542. dwStatus = SMLOG_LOG_TYPE_NEW;
  1543. } else {
  1544. dwStatus = SMLOG_INVALID_LOG_TYPE;
  1545. szStringArray[0] = pQuery->szQueryName;
  1546. ReportEvent (hEventLog,
  1547. EVENTLOG_WARNING_TYPE,
  1548. 0,
  1549. SMLOG_INVALID_LOG_TYPE,
  1550. NULL,
  1551. 1,
  1552. sizeof(DWORD),
  1553. szStringArray,
  1554. (LPVOID)&pQuery->dwLogType);
  1555. }
  1556. }
  1557. if ( ERROR_SUCCESS == dwStatus ) {
  1558. dwStatus = LoadCommonConfig ( pQuery );
  1559. }
  1560. return dwStatus;
  1561. }
  1562. void
  1563. LockQueryData ( void )
  1564. {
  1565. EnterCriticalSection ( &QueryDataLock );
  1566. }
  1567. void
  1568. UnlockQueryData ( void )
  1569. {
  1570. LeaveCriticalSection ( &QueryDataLock );
  1571. }
  1572. void
  1573. EnterConfigure ( void )
  1574. {
  1575. EnterCriticalSection ( &QueryDataLock );
  1576. }
  1577. void
  1578. ExitConfigure ( void )
  1579. {
  1580. LeaveCriticalSection ( &QueryDataLock );
  1581. }
  1582. PLOG_QUERY_DATA
  1583. GetQueryData (
  1584. LPCTSTR szQueryName )
  1585. {
  1586. PLOG_QUERY_DATA pQuery;
  1587. LockQueryData();
  1588. pQuery = pFirstQuery;
  1589. while ( NULL != pQuery ) {
  1590. if ( !lstrcmpi(pQuery->szQueryName, szQueryName ) ) {
  1591. // If the exit event isn't set, then this query is still active.
  1592. if ((WaitForSingleObject (pQuery->hExitEvent, 0)) != WAIT_OBJECT_0) {
  1593. break;
  1594. }
  1595. #if _DEBUG_OUTPUT
  1596. else {
  1597. {
  1598. TCHAR szDebugString[MAX_PATH];
  1599. swprintf (szDebugString, (LPCWSTR)L" Query %s: Exit event is set\n", pQuery->szQueryName);
  1600. OutputDebugString (szDebugString);
  1601. }
  1602. }
  1603. #endif
  1604. }
  1605. pQuery = pQuery->next;
  1606. }
  1607. UnlockQueryData();
  1608. return pQuery;
  1609. }
  1610. PLOG_QUERY_DATA
  1611. GetQueryDataPtr (
  1612. HANDLE hThisQuery
  1613. )
  1614. {
  1615. PLOG_QUERY_DATA pQuery = NULL;
  1616. LockQueryData();
  1617. // Find the query data block in the list.
  1618. if ( hThisQuery == pFirstQuery->hThread ) {
  1619. pQuery = pFirstQuery;
  1620. }
  1621. if ( NULL == pQuery ) {
  1622. for ( pQuery = pFirstQuery;
  1623. NULL != pQuery->next;
  1624. pQuery = pQuery->next ) {
  1625. if ( hThisQuery == pQuery->next->hThread ) {
  1626. pQuery = pQuery->next;
  1627. break;
  1628. }
  1629. }
  1630. }
  1631. UnlockQueryData();
  1632. return pQuery;
  1633. }
  1634. void
  1635. DeallocateQueryBuffers (
  1636. IN PLOG_QUERY_DATA pQuery )
  1637. {
  1638. // Deallocate the buffers that can be deleted when the collection
  1639. // thread is reconfigured.
  1640. if (( SLQ_COUNTER_LOG == pQuery->dwLogType ) ||
  1641. ( SLQ_ALERT == pQuery->dwLogType)) {
  1642. if (pQuery->mszCounterList != NULL) {
  1643. G_FREE(pQuery->mszCounterList);
  1644. pQuery->mszCounterList = NULL;
  1645. }
  1646. }
  1647. if ( SLQ_ALERT == pQuery->dwLogType) {
  1648. if (pQuery->szNetName != NULL) {
  1649. G_FREE(pQuery->szNetName);
  1650. pQuery->szNetName = NULL;
  1651. }
  1652. if (pQuery->szPerfLogName != NULL) {
  1653. G_FREE(pQuery->szPerfLogName);
  1654. pQuery->szPerfLogName = NULL;
  1655. }
  1656. if (pQuery->szUserText != NULL) {
  1657. G_FREE (pQuery->szUserText);
  1658. pQuery->szUserText = NULL;
  1659. }
  1660. }
  1661. if ( SLQ_TRACE_LOG == pQuery->dwLogType) {
  1662. if (pQuery->mszProviderList != NULL) {
  1663. G_FREE(pQuery->mszProviderList);
  1664. pQuery->mszProviderList = NULL;
  1665. }
  1666. }
  1667. if (pQuery->szLogFileComment != NULL) {
  1668. G_FREE(pQuery->szLogFileComment);
  1669. pQuery->szLogFileComment = NULL;
  1670. }
  1671. if (pQuery->szBaseFileName != NULL) {
  1672. G_FREE(pQuery->szBaseFileName);
  1673. pQuery->szBaseFileName = NULL;
  1674. }
  1675. if (pQuery->szLogFileFolder != NULL) {
  1676. G_FREE(pQuery->szLogFileFolder);
  1677. pQuery->szLogFileFolder = NULL;
  1678. }
  1679. if (pQuery->szSqlLogName != NULL) {
  1680. G_FREE(pQuery->szSqlLogName);
  1681. pQuery->szSqlLogName = NULL;
  1682. }
  1683. if (pQuery->szCmdFileName != NULL) {
  1684. G_FREE(pQuery->szCmdFileName);
  1685. pQuery->szCmdFileName = NULL;
  1686. }
  1687. }
  1688. void
  1689. ClearTraceProperties (
  1690. IN PLOG_QUERY_DATA pQuery )
  1691. {
  1692. #if _IMPLEMENT_WMI
  1693. G_ZERO (& pQuery->Properties, sizeof(EVENT_TRACE_PROPERTIES));
  1694. G_ZERO (pQuery->szLoggerName, sizeof(pQuery->szLoggerName));
  1695. G_ZERO (pQuery->szLogFileName, sizeof(pQuery->szLogFileName));
  1696. if ( NULL != pQuery->arrpGuid ) {
  1697. ULONG ulIndex;
  1698. for ( ulIndex = 0; ulIndex < pQuery->ulGuidCount; ulIndex++ ) {
  1699. if ( NULL != pQuery->arrpGuid[ulIndex] ) {
  1700. G_FREE ( pQuery->arrpGuid[ulIndex] );
  1701. pQuery->arrpGuid[ulIndex] = NULL;
  1702. }
  1703. if ( NULL != pQuery->arrpszProviderName[ulIndex] ) {
  1704. G_FREE ( pQuery->arrpszProviderName[ulIndex] );
  1705. pQuery->arrpszProviderName[ulIndex] = NULL;
  1706. }
  1707. }
  1708. G_FREE ( pQuery->arrpGuid );
  1709. pQuery->arrpGuid = NULL;
  1710. if ( NULL != pQuery->arrpszProviderName ) {
  1711. G_FREE ( pQuery->arrpszProviderName );
  1712. pQuery->arrpszProviderName = NULL;
  1713. }
  1714. }
  1715. pQuery->ulGuidCount = 0;
  1716. pQuery->Properties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
  1717. pQuery->Properties.LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES)
  1718. + sizeof(pQuery->szLoggerName);
  1719. #endif
  1720. }
  1721. DWORD
  1722. LoadPdhLogUpdateSuccess ( void )
  1723. {
  1724. DWORD dwStatus = ERROR_SUCCESS;
  1725. HKEY hKeySysmonLog = NULL;
  1726. dwStatus = RegOpenKeyEx (
  1727. (HKEY)HKEY_LOCAL_MACHINE,
  1728. (LPCTSTR)TEXT("SYSTEM\\CurrentControlSet\\Services\\SysmonLog"),
  1729. 0L,
  1730. KEY_READ,
  1731. (PHKEY)&hKeySysmonLog);
  1732. if (dwStatus == ERROR_SUCCESS) {
  1733. TCHAR* mszStatusList = NULL;
  1734. DWORD dwBufferSize = 0;
  1735. DWORD dwType = 0;
  1736. // find out the size of the required buffer
  1737. dwStatus = RegQueryValueExW (
  1738. hKeySysmonLog,
  1739. (LPCTSTR)_T("PdhDataCollectSuccessStatus"),
  1740. NULL,
  1741. &dwType,
  1742. NULL,
  1743. &dwBufferSize); // In bytes
  1744. // If there is something to read
  1745. if ( (ERROR_SUCCESS == dwStatus ) && ( 0 < dwBufferSize ) ) {
  1746. mszStatusList = G_ALLOC ( dwBufferSize );
  1747. if ( NULL != mszStatusList ) {
  1748. mszStatusList[0] = _T('\0');
  1749. dwType = 0;
  1750. dwStatus = RegQueryValueExW (
  1751. hKeySysmonLog,
  1752. (LPCTSTR)_T("PdhDataCollectSuccessStatus"),
  1753. NULL,
  1754. &dwType,
  1755. (UCHAR*)mszStatusList,
  1756. &dwBufferSize);
  1757. if ( (ERROR_SUCCESS == dwStatus )
  1758. && ( 0 < dwBufferSize )
  1759. && ( _T('\0') != mszStatusList[0] ) ) {
  1760. // Allocate and load Pdh data collection status value array.
  1761. INT iStatusCount = 0;
  1762. TCHAR* szThisStatus;
  1763. for (szThisStatus = mszStatusList;
  1764. *szThisStatus != 0;
  1765. szThisStatus += lstrlen(szThisStatus) + 1) {
  1766. iStatusCount++;
  1767. }
  1768. arrPdhDataCollectSuccess = G_ALLOC ( iStatusCount * sizeof ( DWORD ) );
  1769. if ( NULL != arrPdhDataCollectSuccess ) {
  1770. INT iStatusIndex;
  1771. szThisStatus = mszStatusList;
  1772. for ( iStatusIndex = 0; iStatusIndex < iStatusCount; iStatusIndex++ ) {
  1773. if (0 != *szThisStatus ) {
  1774. arrPdhDataCollectSuccess[iStatusIndex] = (DWORD)_ttoi( szThisStatus );
  1775. szThisStatus += lstrlen(szThisStatus) + 1;
  1776. } else {
  1777. break;
  1778. }
  1779. }
  1780. }
  1781. iPdhDataCollectSuccessCount = iStatusCount;
  1782. }
  1783. if ( NULL != mszStatusList ) {
  1784. G_FREE ( mszStatusList );
  1785. }
  1786. } else {
  1787. dwStatus = ERROR_OUTOFMEMORY;
  1788. }
  1789. }
  1790. }
  1791. return dwStatus;
  1792. }
  1793. DWORD
  1794. InitTraceGuids(
  1795. IN PLOG_QUERY_DATA pQuery )
  1796. {
  1797. DWORD dwStatus = ERROR_SUCCESS;
  1798. #if _IMPLEMENT_WMI
  1799. LPTSTR pszThisGuid;
  1800. LONG ulGuidIndex;
  1801. LONG ulpszGuidIndex;
  1802. LONG ulGuidCount = 0;
  1803. LPGUID* arrpGuid = NULL;
  1804. PTCHAR* arrpszGuid = NULL;
  1805. WCHAR pszThisGuidBuffer[64];
  1806. UNICODE_STRING ustrGuid;
  1807. if ( NULL != pQuery ) {
  1808. if ( NULL != pQuery->mszProviderList ) {
  1809. for (pszThisGuid = pQuery->mszProviderList;
  1810. *pszThisGuid != 0;
  1811. pszThisGuid += lstrlen(pszThisGuid) + 1) {
  1812. ulGuidCount += 1;
  1813. if ( NULL == pszThisGuid ) {
  1814. dwStatus = ERROR_INVALID_PARAMETER;
  1815. break;
  1816. }
  1817. }
  1818. }
  1819. if ( ERROR_SUCCESS == dwStatus ) {
  1820. arrpGuid = G_ALLOC ( ulGuidCount * sizeof ( LPGUID ) );
  1821. if (NULL == arrpGuid) {
  1822. dwStatus = ERROR_OUTOFMEMORY;
  1823. } else {
  1824. G_ZERO ( arrpGuid, ulGuidCount * sizeof ( LPGUID ) );
  1825. for ( ulGuidIndex = 0; ulGuidIndex < ulGuidCount; ulGuidIndex++) {
  1826. arrpGuid[ulGuidIndex] = G_ALLOC ( sizeof(GUID) );
  1827. if (NULL == arrpGuid[ulGuidIndex]) {
  1828. dwStatus = ERROR_OUTOFMEMORY;
  1829. break;
  1830. }
  1831. }
  1832. }
  1833. }
  1834. if ( ERROR_SUCCESS == dwStatus ) {
  1835. // Create an array of pointers to individual provider Guids in the
  1836. // mszProviderList. The provider Guids are used as provider
  1837. // names in error messages, and for comparison with provider list
  1838. arrpszGuid = G_ALLOC ( ulGuidCount * sizeof ( TCHAR* ) );
  1839. if (NULL == arrpszGuid) {
  1840. dwStatus = ERROR_OUTOFMEMORY;
  1841. } else {
  1842. G_ZERO ( arrpszGuid, ulGuidCount * sizeof ( TCHAR* ) );
  1843. for ( ulpszGuidIndex = 0; ulpszGuidIndex < ulGuidCount; ulpszGuidIndex++) {
  1844. arrpszGuid[ulpszGuidIndex] = G_ALLOC ( sizeof(TCHAR[MAX_PATH]) );
  1845. if (NULL == arrpszGuid[ulpszGuidIndex]) {
  1846. dwStatus = ERROR_OUTOFMEMORY;
  1847. break;
  1848. }
  1849. }
  1850. }
  1851. if (ERROR_SUCCESS == dwStatus) {
  1852. ulGuidIndex = 0;
  1853. for (pszThisGuid = pQuery->mszProviderList;
  1854. *pszThisGuid != 0;
  1855. pszThisGuid += lstrlen(pszThisGuid) + 1) {
  1856. lstrcpyW ((LPWSTR)pszThisGuidBuffer, pszThisGuid);
  1857. ustrGuid.Length = (USHORT)(lstrlen(pszThisGuidBuffer)*sizeof(TCHAR)); // Size of GUID length << USHORT
  1858. ustrGuid.MaximumLength = sizeof (pszThisGuidBuffer);
  1859. ustrGuid.Buffer = pszThisGuidBuffer;
  1860. dwStatus = GUIDFromString (&ustrGuid, arrpGuid[ulGuidIndex] );
  1861. lstrcpy ( arrpszGuid[ulGuidIndex], pszThisGuid );
  1862. ulGuidIndex++;
  1863. }
  1864. pQuery->ulGuidCount = ulGuidCount;
  1865. pQuery->arrpGuid = arrpGuid;
  1866. pQuery->arrpszProviderName = arrpszGuid;
  1867. }
  1868. }
  1869. if (ERROR_SUCCESS != dwStatus) {
  1870. // If failure anywhere, deallocate arrays
  1871. if ( NULL != arrpszGuid ) {
  1872. for (ulpszGuidIndex--; ulpszGuidIndex>=0; ulpszGuidIndex--) {
  1873. G_FREE(arrpszGuid[ulpszGuidIndex]);
  1874. }
  1875. G_FREE(arrpszGuid);
  1876. }
  1877. if (NULL != arrpGuid) {
  1878. for (ulGuidIndex--; ulGuidIndex>=0; ulGuidIndex--) {
  1879. G_FREE(arrpGuid[ulGuidIndex]);
  1880. }
  1881. G_FREE(arrpGuid);
  1882. }
  1883. }
  1884. } else {
  1885. dwStatus = ERROR_INVALID_PARAMETER;
  1886. }
  1887. #else
  1888. dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
  1889. #endif
  1890. return dwStatus;
  1891. }
  1892. DWORD
  1893. IsCreateNewFile (
  1894. IN PLOG_QUERY_DATA pQuery,
  1895. OUT BOOL* pbValidBySize,
  1896. OUT BOOL* pbValidByTime )
  1897. {
  1898. DWORD dwStatus = ERROR_SUCCESS;
  1899. BOOL bLocalValidBySize = FALSE;
  1900. BOOL bLocalValidByTime = FALSE;
  1901. if ( ( NULL != pQuery ) ) {
  1902. if ( SLQ_AUTO_MODE_SIZE == pQuery->stiCreateNewFile.dwAutoMode ) {
  1903. if ( ( SLF_SEQ_TRACE_FILE == pQuery->dwLogFileType )
  1904. && ( -1 != pQuery->dwMaxFileSize )
  1905. && ( 0 != pQuery->dwMaxFileSize ) )
  1906. {
  1907. bLocalValidBySize = TRUE;
  1908. }
  1909. } else if ( SLQ_AUTO_MODE_AFTER == pQuery->stiCreateNewFile.dwAutoMode ) {
  1910. bLocalValidByTime = TRUE;
  1911. }
  1912. if ( NULL != pbValidBySize ) {
  1913. *pbValidBySize = bLocalValidBySize;
  1914. }
  1915. if ( NULL != pbValidByTime ) {
  1916. *pbValidByTime = bLocalValidByTime;
  1917. }
  1918. } else {
  1919. assert ( FALSE );
  1920. dwStatus = ERROR_INVALID_PARAMETER;
  1921. }
  1922. return dwStatus;
  1923. }
  1924. void
  1925. InitTraceProperties (
  1926. IN PLOG_QUERY_DATA pQuery,
  1927. IN BOOL bUpdateSerial,
  1928. IN OUT DWORD* pdwSessionSerial,
  1929. IN OUT INT* piCnfSerial )
  1930. {
  1931. #if _IMPLEMENT_WMI
  1932. HRESULT hr;
  1933. DWORD dwStatus = ERROR_SUCCESS;
  1934. PPDH_PLA_INFO pInfo = NULL;
  1935. DWORD dwInfoSize = 0;
  1936. BOOL bBySize = FALSE;
  1937. BOOL bByTime = FALSE;
  1938. INT iLocalCnfSerial;
  1939. DWORD dwLocalSessionSerial = 0; // Init for Prefix check
  1940. BOOL bFileExists;
  1941. if ( NULL != pQuery && NULL != piCnfSerial ) {
  1942. hr = PdhPlaGetInfoW( pQuery->szQueryName, NULL, &dwInfoSize, pInfo );
  1943. if( ERROR_SUCCESS == hr && 0 != dwInfoSize ) {
  1944. pInfo = (PPDH_PLA_INFO)G_ALLOC(dwInfoSize);
  1945. if( NULL != pInfo && (sizeof(PDH_PLA_INFO) <= dwInfoSize) ){
  1946. ZeroMemory( pInfo, dwInfoSize );
  1947. pInfo->dwMask = PLA_INFO_FLAG_MODE|PLA_INFO_FLAG_LOGGERNAME;
  1948. hr = PdhPlaGetInfoW( pQuery->szQueryName, NULL, &dwInfoSize, pInfo );
  1949. }
  1950. }
  1951. ClearTraceProperties ( pQuery );
  1952. dwStatus = IsCreateNewFile ( pQuery, &bBySize, &bByTime );
  1953. // Create format string, store it in pQuery->szLogFileName
  1954. if ( bBySize ) {
  1955. // In BuildCurrentLogFileName, iCnfSerial of -1 signals code to
  1956. // return the format string for cnf serial number
  1957. iLocalCnfSerial = -1;
  1958. } else {
  1959. if ( bByTime ) {
  1960. *piCnfSerial += 1;
  1961. iLocalCnfSerial = *piCnfSerial;
  1962. } else {
  1963. iLocalCnfSerial = 0;
  1964. }
  1965. }
  1966. if ( NULL != pdwSessionSerial ) {
  1967. dwLocalSessionSerial = *pdwSessionSerial;
  1968. } else {
  1969. dwLocalSessionSerial = pQuery->dwCurrentSerialNumber;
  1970. }
  1971. dwStatus = BuildCurrentLogFileName (
  1972. pQuery->szQueryName,
  1973. pQuery->szBaseFileName,
  1974. pQuery->szLogFileFolder,
  1975. pQuery->szSqlLogName,
  1976. pQuery->szLogFileName,
  1977. &dwLocalSessionSerial,
  1978. pQuery->dwAutoNameFormat,
  1979. pQuery->dwLogFileType,
  1980. iLocalCnfSerial );
  1981. RegisterCurrentFile( pQuery->hKeyQuery, pQuery->szLogFileName, iLocalCnfSerial );
  1982. // Update log serial number if modified.
  1983. if ( bUpdateSerial && SLF_NAME_NNNNNN == pQuery->dwAutoNameFormat ) {
  1984. pQuery->dwCurrentSerialNumber++;
  1985. // Todo: Info event on number wrap - Server Beta 3.
  1986. if ( MAXIMUM_SERIAL_NUMBER < pQuery->dwCurrentSerialNumber ) {
  1987. pQuery->dwCurrentSerialNumber = MINIMUM_SERIAL_NUMBER;
  1988. }
  1989. WriteRegistryDwordValue (
  1990. pQuery->hKeyQuery,
  1991. (LPCTSTR)L"Log File Serial Number",
  1992. &pQuery->dwCurrentSerialNumber,
  1993. REG_DWORD);
  1994. // Todo: log event on error.
  1995. }
  1996. pQuery->Properties.Wnode.BufferSize = sizeof(pQuery->Properties)
  1997. + sizeof(pQuery->szLoggerName)
  1998. + sizeof(pQuery->szLogFileName);
  1999. if ( TRUE == bBySize ) {
  2000. // Add room for trace code to to return formatted filename string.
  2001. pQuery->Properties.Wnode.BufferSize += 8;
  2002. }
  2003. pQuery->Properties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  2004. // Fill out properties block and start.
  2005. pQuery->Properties.BufferSize = pQuery->dwBufferSize;
  2006. pQuery->Properties.MinimumBuffers = pQuery->dwBufferMinCount;
  2007. pQuery->Properties.MaximumBuffers = pQuery->dwBufferMaxCount;
  2008. if ( pInfo ) {
  2009. if ( pInfo->Trace.strLoggerName != NULL ) {
  2010. lstrcpy ( pQuery->szLoggerName, pInfo->Trace.strLoggerName );
  2011. }
  2012. } else {
  2013. lstrcpy ( pQuery->szLoggerName, pQuery->szQueryName );
  2014. }
  2015. if ( (BOOL)( 0 == (pQuery->dwFlags & SLQ_TLI_ENABLE_BUFFER_FLUSH)) )
  2016. pQuery->Properties.FlushTimer = 0;
  2017. else
  2018. pQuery->Properties.FlushTimer = pQuery->dwBufferFlushInterval;
  2019. if ( IsKernelTraceMode ( pQuery->dwFlags ) ) {
  2020. pQuery->Properties.Wnode.Guid = SystemTraceControlGuid;
  2021. lstrcpy ( pQuery->szLoggerName, NT_KERNEL_LOGGER );
  2022. if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_KERNEL_TRACE)) ) {
  2023. // NT5 Beta 2 Single Kernel flag
  2024. pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_PROCESS |
  2025. EVENT_TRACE_FLAG_THREAD |
  2026. EVENT_TRACE_FLAG_DISK_IO |
  2027. EVENT_TRACE_FLAG_NETWORK_TCPIP;
  2028. } else {
  2029. if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_PROCESS_TRACE)) )
  2030. pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_PROCESS;
  2031. if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_THREAD_TRACE)) )
  2032. pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_THREAD;
  2033. if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_DISKIO_TRACE)) )
  2034. pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_DISK_IO;
  2035. if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_NETWORK_TCPIP_TRACE)) )
  2036. pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP;
  2037. }
  2038. if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_MEMMAN_TRACE)) )
  2039. pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS;
  2040. if ( (BOOL)( 0 != (pQuery->dwFlags & SLQ_TLI_ENABLE_FILEIO_TRACE)) )
  2041. pQuery->Properties.EnableFlags |= EVENT_TRACE_FLAG_DISK_FILE_IO;
  2042. } else {
  2043. InitTraceGuids ( pQuery );
  2044. }
  2045. if ( -1 == pQuery->dwMaxFileSize ) {
  2046. pQuery->Properties.MaximumFileSize = 0;
  2047. } else {
  2048. pQuery->Properties.MaximumFileSize = pQuery->dwMaxFileSize;
  2049. }
  2050. if ( ERROR_SUCCESS == dwStatus && TRUE == bBySize ) {
  2051. pQuery->Properties.LogFileMode =
  2052. EVENT_TRACE_FILE_MODE_SEQUENTIAL | EVENT_TRACE_FILE_MODE_NEWFILE;
  2053. } else if ( SLF_SEQ_TRACE_FILE == pQuery->dwLogFileType ) {
  2054. pQuery->Properties.LogFileMode = EVENT_TRACE_FILE_MODE_SEQUENTIAL;
  2055. // Only set Append mode if the file already exists.
  2056. if ( pQuery->dwAppendMode && FileExists ( pQuery->szLogFileName ) ) {
  2057. pQuery->Properties.LogFileMode |= EVENT_TRACE_FILE_MODE_APPEND;
  2058. }
  2059. } else {
  2060. assert ( SLF_CIRC_TRACE_FILE == pQuery->dwLogFileType );
  2061. pQuery->Properties.LogFileMode = EVENT_TRACE_FILE_MODE_CIRCULAR;
  2062. }
  2063. if ( pInfo ) {
  2064. pQuery->Properties.LogFileMode |= pInfo->Trace.dwMode;
  2065. G_FREE( pInfo );
  2066. }
  2067. if ( NULL != pdwSessionSerial ) {
  2068. *pdwSessionSerial = dwLocalSessionSerial;
  2069. }
  2070. } // Todo: else report error, return error
  2071. #endif
  2072. }
  2073. void
  2074. FreeQueryData (
  2075. IN PLOG_QUERY_DATA pQuery )
  2076. {
  2077. // Caller must remove the thread data block from the list.
  2078. // Threads are deleted by only one thread, so this should not
  2079. // be deleted out from under.
  2080. assert ( NULL != pQuery );
  2081. if ( NULL != pQuery ) {
  2082. // Free this entry.
  2083. if (( SLQ_COUNTER_LOG == pQuery->dwLogType ) ||
  2084. ( SLQ_ALERT == pQuery->dwLogType ) ){
  2085. while ( NULL != pQuery->pFirstCounter ) {
  2086. PLOG_COUNTER_INFO pDelCI = pQuery->pFirstCounter;
  2087. pQuery->pFirstCounter = pDelCI->next;
  2088. G_FREE( pDelCI );
  2089. }
  2090. } else {
  2091. if ( NULL != pQuery->arrpGuid ) {
  2092. ULONG ulIndex;
  2093. for ( ulIndex = 0; ulIndex < pQuery->ulGuidCount; ulIndex++ ) {
  2094. if ( NULL != pQuery->arrpGuid[ulIndex] ) {
  2095. G_FREE ( pQuery->arrpGuid[ulIndex] );
  2096. pQuery->arrpGuid[ulIndex] = NULL;
  2097. }
  2098. }
  2099. G_FREE ( pQuery->arrpGuid );
  2100. pQuery->arrpGuid = NULL;
  2101. }
  2102. }
  2103. if ( NULL != pQuery->hThread ) {
  2104. CloseHandle ( pQuery->hThread );
  2105. pQuery->hThread = NULL;
  2106. }
  2107. if ( NULL != pQuery->hUserToken ) {
  2108. CloseHandle ( pQuery->hUserToken );
  2109. pQuery->hUserToken = NULL;
  2110. }
  2111. if ( NULL != pQuery->hExitEvent ) {
  2112. CloseHandle ( pQuery->hExitEvent );
  2113. pQuery->hExitEvent = NULL;
  2114. }
  2115. if ( NULL != pQuery->hReconfigEvent ) {
  2116. CloseHandle ( pQuery->hReconfigEvent );
  2117. pQuery->hReconfigEvent = NULL;
  2118. }
  2119. if ( NULL != pQuery->hKeyQuery ) {
  2120. RegCloseKey ( pQuery->hKeyQuery );
  2121. pQuery->hKeyQuery = NULL;
  2122. }
  2123. DeallocateQueryBuffers( pQuery );
  2124. G_FREE (pQuery);
  2125. }
  2126. }
  2127. void
  2128. RemoveAndFreeQueryData (
  2129. HANDLE hThisQuery
  2130. )
  2131. {
  2132. PLOG_QUERY_DATA pQuery = NULL;
  2133. BOOL bFound = FALSE;
  2134. LockQueryData();
  2135. // Find the query data block and remove it from the list.
  2136. if ( hThisQuery == pFirstQuery->hThread ) {
  2137. bFound = TRUE;
  2138. }
  2139. if ( bFound ) {
  2140. pQuery = pFirstQuery;
  2141. pFirstQuery = pFirstQuery->next;
  2142. } else {
  2143. PLOG_QUERY_DATA pQueryRemaining;
  2144. for ( pQuery = pFirstQuery;
  2145. NULL != pQuery->next;
  2146. pQuery = pQuery->next ) {
  2147. if ( hThisQuery == pQuery->next->hThread ) {
  2148. pQueryRemaining = pQuery;
  2149. pQuery = pQuery->next;
  2150. pQueryRemaining->next = pQuery->next;
  2151. bFound = TRUE;
  2152. break;
  2153. }
  2154. }
  2155. }
  2156. assert ( bFound );
  2157. if ( bFound ) {
  2158. dwActiveSessionCount -= 1;
  2159. }
  2160. UnlockQueryData();
  2161. assert ( NULL != pQuery );
  2162. #if _DEBUG_OUTPUT
  2163. {
  2164. TCHAR szDebugString[MAX_PATH];
  2165. swprintf (szDebugString, (LPCWSTR)L" Query %s: Query removed\n", pQuery->szQueryName);
  2166. OutputDebugString (szDebugString);
  2167. }
  2168. #endif
  2169. if ( bFound ) {
  2170. FreeQueryData( pQuery );
  2171. }
  2172. }
  2173. LONGLONG
  2174. ComputeStartWaitTics(
  2175. IN PLOG_QUERY_DATA pQuery,
  2176. IN BOOL bWriteToRegistry
  2177. )
  2178. {
  2179. LONGLONG llWaitTics = ((LONGLONG)0);
  2180. LONGLONG llLocalDateTime;
  2181. LONGLONG llRptLocalDays = 0;
  2182. LONGLONG llRptStartTime = 0;
  2183. LONGLONG llRptStopTime = 0;
  2184. LONGLONG llRptLocalTime = 0;
  2185. SLQ_TIME_INFO stiSched;
  2186. // Compute time to wait before logging starts.
  2187. //
  2188. // Time returned is millisecond granularity.
  2189. //
  2190. // Return value:
  2191. //
  2192. // Start time minus Now when At time is in the future.
  2193. //
  2194. // 0 signals no wait. This is true when:
  2195. // Start is either Manual or At mode and start time set to before now.
  2196. // Exceptions for both of these cases are noted below.
  2197. //
  2198. // NULL_INTERVAL_TICS signals exit immediately. This is true when:
  2199. // Start is Manual and Start time is MAX_TIME_VALUE
  2200. // Stop is At mode and Stop time is past.
  2201. // Stop is Manual mode and Stop time is MIN_TIME_VALUE or any value <= Now
  2202. // Stop is After mode, After value is 0 (UI should protect against this).
  2203. // Stop is After mode, Start is At mode, stop time is past and repeat mode is Manual.
  2204. //
  2205. GetLocalFileTime (&llLocalDateTime);
  2206. if ( ( MAX_TIME_VALUE == pQuery->stiRegStart.llDateTime )
  2207. && ( SLQ_AUTO_MODE_NONE == pQuery->stiRegStart.dwAutoMode ) ) {
  2208. // Manual Start, start time is MAX_TIME_VALUE
  2209. // Note: For repeat funcionality, manual start time might be > now.
  2210. // Need to keep the start mode Manual in this case to ensure that
  2211. // SetStoppedStatus works.
  2212. // Todo: Don't allow repeat or restart with Manual mode?
  2213. llWaitTics = NULL_INTERVAL_TICS;
  2214. } else if ( ( SLQ_AUTO_MODE_NONE == pQuery->stiRegStop.dwAutoMode )
  2215. && ( pQuery->stiRegStop.llDateTime <= llLocalDateTime ) ) {
  2216. // Past Stop Manual time.
  2217. llWaitTics = NULL_INTERVAL_TICS;
  2218. } else if ( ( ( SLQ_AUTO_MODE_AT == pQuery->stiRegStop.dwAutoMode )
  2219. && ( SLQ_AUTO_MODE_CALENDAR != pQuery->stiRepeat.dwAutoMode ) )
  2220. && ( pQuery->stiRegStop.llDateTime <= llLocalDateTime ) ) {
  2221. // Past Stop At or time and repeat mode not set to calendar.
  2222. llWaitTics = NULL_INTERVAL_TICS;
  2223. } else if ( SLQ_AUTO_MODE_AFTER == pQuery->stiRegStop.dwAutoMode ) {
  2224. if ( 0 == pQuery->stiRegStop.dwValue ) {
  2225. // Stop After mode and value is 0.
  2226. llWaitTics = NULL_INTERVAL_TICS;
  2227. } else if ( ( SLQ_AUTO_MODE_AT == pQuery->stiRegStart.dwAutoMode )
  2228. && ( SLQ_AUTO_MODE_NONE == pQuery->stiRepeat.dwAutoMode ) ) {
  2229. LONGLONG llTics;
  2230. TimeInfoToTics ( &pQuery->stiRegStop, &llTics );
  2231. if ( ( pQuery->stiRegStart.llDateTime + llTics ) < llLocalDateTime ) {
  2232. // Start at, Stop After modes, stop time is past and no restart.
  2233. llWaitTics = NULL_INTERVAL_TICS;
  2234. }
  2235. }
  2236. }
  2237. // This code writes to local start and stop time structures to compute
  2238. // start wait tics. This avoids excessive log stops and starts, since
  2239. // the original registry data structures are compared when the registry
  2240. // has been modified, to determine if a log config has been changed by the UI.
  2241. if ( NULL_INTERVAL_TICS != llWaitTics ) {
  2242. pQuery->stiCurrentStart = pQuery->stiRegStart;
  2243. pQuery->stiCurrentStop = pQuery->stiRegStop;
  2244. // Handle repeat option separately.
  2245. if ( SLQ_AUTO_MODE_CALENDAR == pQuery->stiRepeat.dwAutoMode ) {
  2246. assert ( SLQ_AUTO_MODE_AT == pQuery->stiCurrentStart.dwAutoMode );
  2247. assert ( SLQ_AUTO_MODE_AT == pQuery->stiCurrentStop.dwAutoMode );
  2248. // assert ( ( pQuery->stiCurrentStop.llDateTime - pQuery->stiCurrentStart.llDateTime )
  2249. // < (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) );
  2250. if ( pQuery->stiCurrentStop.llDateTime <= llLocalDateTime ) {
  2251. llRptLocalDays = llLocalDateTime / (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY);
  2252. llRptLocalTime = llLocalDateTime - llRptLocalDays;
  2253. llRptStopTime = pQuery->stiCurrentStop.llDateTime
  2254. - ( pQuery->stiCurrentStop.llDateTime
  2255. / (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) );
  2256. pQuery->stiCurrentStop.llDateTime = llRptLocalDays + llRptStopTime;
  2257. if ( llRptStopTime < llRptLocalTime ) {
  2258. // Set to stop tomorrow.
  2259. pQuery->stiCurrentStop.llDateTime += (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) ;
  2260. }
  2261. llRptStartTime = pQuery->stiCurrentStart.llDateTime
  2262. - ( pQuery->stiCurrentStart.llDateTime
  2263. / (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) );
  2264. pQuery->stiCurrentStart.llDateTime = llRptLocalDays + llRptStartTime;
  2265. if ( (pQuery->stiCurrentStop.llDateTime - pQuery->stiCurrentStart.llDateTime)
  2266. > (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY) ) {
  2267. // Set to start tomorrow.
  2268. pQuery->stiCurrentStart.llDateTime += (FILETIME_TICS_PER_SECOND * SECONDS_IN_DAY);
  2269. }
  2270. }
  2271. if ( bWriteToRegistry ) {
  2272. stiSched.wDataType = SLQ_TT_DTYPE_DATETIME;
  2273. stiSched.wTimeType = SLQ_TT_TTYPE_REPEAT_START;
  2274. stiSched.dwAutoMode = SLQ_AUTO_MODE_AT;
  2275. stiSched.llDateTime = pQuery->stiCurrentStart.llDateTime;
  2276. WriteRegistrySlqTime (
  2277. pQuery->hKeyQuery,
  2278. (LPCWSTR)L"Repeat Schedule Start",
  2279. &stiSched );
  2280. stiSched.wTimeType = SLQ_TT_TTYPE_REPEAT_STOP;
  2281. stiSched.dwAutoMode = SLQ_AUTO_MODE_AT;
  2282. stiSched.llDateTime = pQuery->stiCurrentStop.llDateTime;
  2283. WriteRegistrySlqTime (
  2284. pQuery->hKeyQuery,
  2285. (LPCWSTR)L"Repeat Schedule Stop",
  2286. &stiSched );
  2287. }
  2288. }
  2289. if ( pQuery->stiCurrentStart.llDateTime <= llLocalDateTime ) {
  2290. llWaitTics = ((LONGLONG)(0));
  2291. } else {
  2292. llWaitTics = pQuery->stiCurrentStart.llDateTime - llLocalDateTime;
  2293. }
  2294. // If manual mode, set the start time to now, to handle repeat schedule.
  2295. // If any thread other than the log thread accesses this field for a
  2296. // running query, then need to synchronize access to the field.
  2297. if( SLQ_AUTO_MODE_NONE == pQuery->stiCurrentStart.dwAutoMode
  2298. && MIN_TIME_VALUE == pQuery->stiCurrentStart.llDateTime )
  2299. {
  2300. pQuery->stiCurrentStart.llDateTime = llLocalDateTime + llWaitTics;
  2301. }
  2302. }
  2303. return llWaitTics;
  2304. }
  2305. void
  2306. LoadDefaultLogFileFolder ( void )
  2307. {
  2308. HKEY hKeyLogService = NULL;
  2309. TCHAR szLocalPath[MAX_PATH+1] = TEXT("");
  2310. DWORD cchExpandedLen;
  2311. DWORD dwStatus;
  2312. dwStatus = RegOpenKeyEx (
  2313. (HKEY)HKEY_LOCAL_MACHINE,
  2314. (LPCTSTR)TEXT("SYSTEM\\CurrentControlSet\\Services\\SysmonLog"),
  2315. 0L,
  2316. KEY_READ,
  2317. (PHKEY)&hKeyLogService);
  2318. // update the service status
  2319. ssSmLogStatus.dwCheckPoint++;
  2320. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  2321. if (dwStatus == ERROR_SUCCESS) {
  2322. DWORD dwBufferSize = sizeof ( szLocalPath );
  2323. dwStatus = RegQueryValueExW (
  2324. hKeyLogService,
  2325. (LPCTSTR)L"DefaultLogFileFolder",
  2326. NULL,
  2327. 0L,
  2328. (LPBYTE)szLocalPath,
  2329. &dwBufferSize);
  2330. RegCloseKey (hKeyLogService);
  2331. } // No message on error. Just use load the local default.
  2332. if ( 0 == lstrlen (szLocalPath ) ) {
  2333. lstrcpy ( szLocalPath, DEFAULT_LOG_FILE_FOLDER );
  2334. }
  2335. // Todo: local and global buffer sizes are fixed.
  2336. cchExpandedLen = ExpandEnvironmentStrings (
  2337. szLocalPath,
  2338. gszDefaultLogFileFolder,
  2339. MAX_PATH+1 );
  2340. if ( 0 == cchExpandedLen ) {
  2341. gszDefaultLogFileFolder[0] = L'\0';
  2342. }
  2343. }
  2344. DWORD
  2345. ProcessLogFileFolder (
  2346. IN PLOG_QUERY_DATA pQuery,
  2347. IN BOOL bReconfigure )
  2348. {
  2349. DWORD dwStatus = ERROR_SUCCESS;
  2350. TCHAR szLocalPath [MAX_PATH];
  2351. szLocalPath[0] = _T('\0');
  2352. if (GetFullPathName (
  2353. pQuery->szLogFileFolder,
  2354. MAX_PATH,
  2355. szLocalPath,
  2356. NULL) > 0) {
  2357. LPTSTR szEnd;
  2358. LPSECURITY_ATTRIBUTES lpSA = NULL;
  2359. TCHAR cBackslash = TEXT('\\');
  2360. szEnd = &szLocalPath[3];
  2361. if (*szEnd != 0) {
  2362. LONG lErrorMode;
  2363. lErrorMode = SetErrorMode ( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
  2364. // then there are sub dirs to create
  2365. while (*szEnd != 0) {
  2366. // go to next backslash
  2367. while ((*szEnd != cBackslash) && (*szEnd != 0)) szEnd++;
  2368. if (*szEnd == cBackslash) {
  2369. // terminate path here and create directory
  2370. *szEnd = 0;
  2371. if (!CreateDirectory (szLocalPath, lpSA)) {
  2372. // see what the error was and "adjust" it if necessary
  2373. dwStatus = GetLastError();
  2374. if ( ERROR_ALREADY_EXISTS == dwStatus ) {
  2375. // this is OK
  2376. dwStatus = ERROR_SUCCESS;
  2377. }
  2378. }
  2379. // replace backslash and go to next dir
  2380. *szEnd++ = cBackslash;
  2381. }
  2382. }
  2383. // create last dir in path now
  2384. if (!CreateDirectory (szLocalPath, lpSA)) {
  2385. // see what the error was and "adjust" it if necessary
  2386. dwStatus = GetLastError();
  2387. if ( ERROR_ALREADY_EXISTS == dwStatus ) {
  2388. // this is OK
  2389. dwStatus = ERROR_SUCCESS;
  2390. }
  2391. }
  2392. SetErrorMode ( lErrorMode );
  2393. } else {
  2394. // Root directory is ok.
  2395. dwStatus = ERROR_SUCCESS;
  2396. }
  2397. } else {
  2398. dwStatus = GetLastError();
  2399. }
  2400. // Report event on error
  2401. if ( ERROR_SUCCESS != dwStatus ) {
  2402. DWORD dwMessageId;
  2403. LPCWSTR szStringArray[3];
  2404. szStringArray[0] = pQuery->szLogFileFolder;
  2405. szStringArray[1] = pQuery->szQueryName;
  2406. szStringArray[2] = FormatEventLogMessage(dwStatus);
  2407. if ( bReconfigure ) {
  2408. dwMessageId = SMLOG_INVALID_LOG_FOLDER_STOP;
  2409. } else {
  2410. dwMessageId = SMLOG_INVALID_LOG_FOLDER_START;
  2411. }
  2412. ReportEvent (hEventLog,
  2413. EVENTLOG_WARNING_TYPE,
  2414. 0,
  2415. dwMessageId,
  2416. NULL,
  2417. 3,
  2418. sizeof(DWORD),
  2419. szStringArray,
  2420. (LPVOID)&dwStatus);
  2421. }
  2422. return dwStatus;
  2423. }
  2424. DWORD
  2425. OpenLogQueriesKey (
  2426. REGSAM regsamAccess,
  2427. PHKEY phKeyLogQueries )
  2428. {
  2429. DWORD dwStatus;
  2430. dwStatus = RegOpenKeyEx (
  2431. (HKEY)HKEY_LOCAL_MACHINE,
  2432. (LPCTSTR)TEXT("SYSTEM\\CurrentControlSet\\Services\\SysmonLog\\Log Queries"),
  2433. 0L,
  2434. regsamAccess,
  2435. phKeyLogQueries);
  2436. return dwStatus;
  2437. }
  2438. DWORD
  2439. ClearQueryRunStates ( void )
  2440. {
  2441. DWORD dwStatus;
  2442. HKEY hKeyLogQueries = NULL;
  2443. HKEY hKeyThisLogQuery = NULL;
  2444. DWORD dwQueryIndex;
  2445. TCHAR szQueryNameBuffer[MAX_PATH+1];
  2446. DWORD dwQueryNameBufferSize;
  2447. TCHAR szQueryClassBuffer[MAX_PATH+1];
  2448. DWORD dwQueryClassBufferSize;
  2449. LPTSTR szCollectionName = NULL;
  2450. UINT uiCollectionNameLen = 0;
  2451. LPTSTR szStringArray[2];
  2452. DWORD dwCurrentState;
  2453. DWORD dwDefault;
  2454. DWORD dwLogType;
  2455. // For every query in the registry, if the state is SLQ_QUERY_RUNNING,
  2456. // set it to SLQ_QUERY_STOPPED.
  2457. //
  2458. // This method must be called before starting the query threads.
  2459. //
  2460. // Only the service sets the state to SLQ_QUERY_RUNNING, so there is no
  2461. // race condition.
  2462. // Open (each) query in the registry
  2463. dwStatus = OpenLogQueriesKey (
  2464. KEY_READ | KEY_SET_VALUE,
  2465. (PHKEY)&hKeyLogQueries);
  2466. if (dwStatus != ERROR_SUCCESS) {
  2467. if (dwStatus == ERROR_FILE_NOT_FOUND) {
  2468. // there is no logs nor alerts setting, bail out quietly
  2469. //
  2470. dwStatus = ERROR_SUCCESS;
  2471. }
  2472. else {
  2473. // unable to read the log query information from the registry
  2474. dwStatus = GetLastError();
  2475. ReportEvent (hEventLog,
  2476. EVENTLOG_ERROR_TYPE,
  2477. 0,
  2478. SMLOG_UNABLE_OPEN_LOG_QUERY,
  2479. NULL,
  2480. 0,
  2481. 0,
  2482. NULL,
  2483. NULL);
  2484. dwStatus = SMLOG_UNABLE_OPEN_LOG_QUERY;
  2485. }
  2486. } else {
  2487. dwQueryIndex = 0;
  2488. *szQueryNameBuffer = 0;
  2489. dwQueryNameBufferSize = MAX_PATH+1;
  2490. *szQueryClassBuffer = 0;
  2491. dwQueryClassBufferSize = MAX_PATH+1;
  2492. while ((dwStatus = RegEnumKeyEx (
  2493. hKeyLogQueries,
  2494. dwQueryIndex,
  2495. szQueryNameBuffer,
  2496. &dwQueryNameBufferSize,
  2497. NULL,
  2498. szQueryClassBuffer,
  2499. &dwQueryClassBufferSize,
  2500. NULL)) != ERROR_NO_MORE_ITEMS) {
  2501. // open this key
  2502. dwStatus = RegOpenKeyEx (
  2503. hKeyLogQueries,
  2504. szQueryNameBuffer,
  2505. 0L,
  2506. KEY_READ | KEY_WRITE,
  2507. (PHKEY)&hKeyThisLogQuery);
  2508. if (dwStatus != ERROR_SUCCESS) {
  2509. szStringArray[0] = szQueryNameBuffer;
  2510. ReportEvent (hEventLog,
  2511. EVENTLOG_WARNING_TYPE,
  2512. 0,
  2513. SMLOG_UNABLE_READ_LOG_QUERY,
  2514. NULL,
  2515. 1,
  2516. sizeof(DWORD),
  2517. szStringArray,
  2518. (LPVOID)&dwStatus);
  2519. // skip to next item
  2520. goto CONTINUE_ENUM_LOOP;
  2521. }
  2522. // update the service status
  2523. ssSmLogStatus.dwCheckPoint++;
  2524. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  2525. dwStatus = SmReadRegistryIndirectStringValue (
  2526. hKeyThisLogQuery,
  2527. L"Collection Name",
  2528. NULL,
  2529. &szCollectionName,
  2530. &uiCollectionNameLen );
  2531. if ( NULL != szCollectionName ) {
  2532. if ( 0 < lstrlen ( szCollectionName ) ) {
  2533. lstrcpyn (
  2534. szQueryNameBuffer,
  2535. szCollectionName,
  2536. min(MAX_PATH, lstrlen(szCollectionName)+1 ) );
  2537. }
  2538. G_FREE ( szCollectionName );
  2539. szCollectionName = NULL;
  2540. uiCollectionNameLen = 0;
  2541. }
  2542. dwDefault = ((DWORD)-1);
  2543. dwStatus = ReadRegistryDwordValue (
  2544. hKeyThisLogQuery,
  2545. szQueryNameBuffer,
  2546. (LPCTSTR)L"Log Type",
  2547. &dwDefault,
  2548. &dwLogType );
  2549. if ( ( SLQ_COUNTER_LOG == dwLogType )
  2550. || ( SLQ_TRACE_LOG == dwLogType )
  2551. || ( SLQ_ALERT == dwLogType ) ) {
  2552. // Check the current state of the query. If it is SLQ_QUERY_RUNNING,
  2553. // set it to SLQ_QUERY_STOPPED. If, in addition, the Start mode is
  2554. // manual, set the start time to MAX, so that the query doesn't
  2555. // start automatically.
  2556. // If the current state is SLQ_QUERY_START_PENDING, it is assumed to be a new
  2557. // request, so leave the registry as is.
  2558. //
  2559. // Note: For trace logs, this code only coordinates between trace log
  2560. // configs that are stored in the registry.
  2561. dwDefault = SLQ_QUERY_STOPPED;
  2562. dwStatus = ReadRegistryDwordValue (
  2563. hKeyThisLogQuery,
  2564. szQueryNameBuffer,
  2565. (LPCTSTR)L"Current State",
  2566. &dwDefault,
  2567. &dwCurrentState );
  2568. assert (dwStatus == ERROR_SUCCESS);
  2569. // Status always success if default provided.
  2570. // If query is in START_PENDING or STOPPED state, then
  2571. // the registry contents are correct. If it is in
  2572. // RUNNING state, then the service was stopped before
  2573. // it could clean up the registry state.
  2574. if ( SLQ_QUERY_RUNNING == dwCurrentState ) {
  2575. SLQ_TIME_INFO stiDefault;
  2576. SLQ_TIME_INFO stiActual;
  2577. LONGLONG ftLocalTime;
  2578. dwCurrentState = SLQ_QUERY_STOPPED;
  2579. dwStatus = WriteRegistryDwordValue (
  2580. hKeyThisLogQuery,
  2581. (LPCTSTR)L"Current State",
  2582. &dwCurrentState,
  2583. REG_DWORD );
  2584. if (dwStatus != ERROR_SUCCESS) {
  2585. szStringArray[0] = szQueryNameBuffer;
  2586. ReportEvent (hEventLog,
  2587. EVENTLOG_WARNING_TYPE,
  2588. 0,
  2589. SMLOG_UNABLE_WRITE_STOP_STATE,
  2590. NULL,
  2591. 1,
  2592. sizeof(DWORD),
  2593. szStringArray,
  2594. (LPVOID)&dwStatus);
  2595. // skip to next item
  2596. goto CONTINUE_ENUM_LOOP;
  2597. }
  2598. // If Start is manual mode, set start time to MAX, to signal
  2599. // not started.
  2600. GetLocalFileTime ( &ftLocalTime );
  2601. stiDefault.wTimeType = SLQ_TT_TTYPE_START;
  2602. stiDefault.dwAutoMode = SLQ_AUTO_MODE_AT;
  2603. stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
  2604. stiDefault.llDateTime = *(LONGLONG *)&ftLocalTime;
  2605. dwStatus = ReadRegistrySlqTime (
  2606. hKeyThisLogQuery,
  2607. szQueryNameBuffer,
  2608. (LPCTSTR)L"Start",
  2609. &stiDefault,
  2610. &stiActual );
  2611. assert (dwStatus == ERROR_SUCCESS);
  2612. // Status always success if default provided.
  2613. if ( ( SLQ_AUTO_MODE_NONE == stiActual.dwAutoMode )
  2614. && ( MAX_TIME_VALUE != stiActual.llDateTime ) ) {
  2615. stiActual.llDateTime = MAX_TIME_VALUE;
  2616. dwStatus = WriteRegistrySlqTime (
  2617. hKeyThisLogQuery,
  2618. (LPCTSTR)L"Start",
  2619. &stiActual);
  2620. if (dwStatus != ERROR_SUCCESS) {
  2621. szStringArray[0] = szQueryNameBuffer;
  2622. ReportEvent (hEventLog,
  2623. EVENTLOG_WARNING_TYPE,
  2624. 0,
  2625. SMLOG_UNABLE_RESET_START_TIME,
  2626. NULL,
  2627. 1,
  2628. sizeof(DWORD),
  2629. szStringArray,
  2630. (LPVOID)&dwStatus);
  2631. // skip to next item
  2632. goto CONTINUE_ENUM_LOOP;
  2633. }
  2634. }
  2635. // If Stop is manual mode, set stop time to MIN, to signal
  2636. // not started.
  2637. GetLocalFileTime ( &ftLocalTime );
  2638. stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
  2639. stiDefault.wTimeType = SLQ_TT_TTYPE_STOP;
  2640. stiDefault.dwAutoMode = SLQ_AUTO_MODE_NONE;
  2641. stiDefault.llDateTime = MIN_TIME_VALUE;
  2642. dwStatus = ReadRegistrySlqTime (
  2643. hKeyThisLogQuery,
  2644. szQueryNameBuffer,
  2645. (LPCTSTR)L"Stop",
  2646. &stiDefault,
  2647. &stiActual );
  2648. assert (dwStatus == ERROR_SUCCESS);
  2649. // Status always success if default provided.
  2650. if ( ( SLQ_AUTO_MODE_NONE == stiActual.dwAutoMode )
  2651. && ( MIN_TIME_VALUE != stiActual.llDateTime ) ) {
  2652. stiActual.llDateTime = MIN_TIME_VALUE;
  2653. dwStatus = WriteRegistrySlqTime (
  2654. hKeyThisLogQuery,
  2655. (LPCTSTR)L"Stop",
  2656. &stiActual);
  2657. if (dwStatus != ERROR_SUCCESS) {
  2658. szStringArray[0] = szQueryNameBuffer;
  2659. ReportEvent (hEventLog,
  2660. EVENTLOG_WARNING_TYPE,
  2661. 0,
  2662. SMLOG_UNABLE_RESET_STOP_TIME,
  2663. NULL,
  2664. 1,
  2665. sizeof(DWORD),
  2666. szStringArray,
  2667. (LPVOID)&dwStatus);
  2668. // skip to next item
  2669. goto CONTINUE_ENUM_LOOP;
  2670. }
  2671. }
  2672. }
  2673. } // Ignore invalid log types when clearing status.
  2674. CONTINUE_ENUM_LOOP:
  2675. if ( NULL != hKeyThisLogQuery )
  2676. RegCloseKey (hKeyThisLogQuery);
  2677. hKeyThisLogQuery = NULL;
  2678. // prepare for next loop
  2679. dwQueryIndex++;
  2680. *szQueryNameBuffer = 0;
  2681. dwQueryNameBufferSize = MAX_PATH+1;
  2682. *szQueryClassBuffer = 0;
  2683. dwQueryClassBufferSize = MAX_PATH+1;
  2684. } // end enumeration of log queries
  2685. }
  2686. if ( NULL != hKeyLogQueries ) {
  2687. RegCloseKey (hKeyLogQueries);
  2688. }
  2689. return dwStatus;
  2690. }
  2691. BOOL
  2692. TraceStopRestartFieldsMatch (
  2693. IN PLOG_QUERY_DATA pOrigQuery,
  2694. IN PLOG_QUERY_DATA pNewQuery )
  2695. {
  2696. #if _IMPLEMENT_WMI
  2697. // These are fields for which trace logging must
  2698. // be stopped and restarted in order to reconfigure.
  2699. BOOL bRequested;
  2700. BOOL bCurrent;
  2701. ULONG ulGuidCount = 0;
  2702. ULONG ulGuidIndex = 0;
  2703. TCHAR* pszThisGuid = NULL;
  2704. assert ( SLQ_TRACE_LOG == pOrigQuery->dwLogType );
  2705. assert ( SLQ_TRACE_LOG == pNewQuery->dwLogType );
  2706. if ( !CommonFieldsMatch ( pOrigQuery, pNewQuery ) )
  2707. return FALSE;
  2708. if ( pOrigQuery->stiCreateNewFile.dwAutoMode != pNewQuery->stiCreateNewFile.dwAutoMode ) {
  2709. return FALSE;
  2710. } else {
  2711. if ( ( SLQ_AUTO_MODE_AFTER == pOrigQuery->stiCreateNewFile.dwAutoMode )
  2712. && ( pOrigQuery->stiCreateNewFile.llDateTime != pNewQuery->stiCreateNewFile.llDateTime ) ) {
  2713. return FALSE;
  2714. }
  2715. }
  2716. // Compare new query fields against the existing properties structure.
  2717. // Compare everything but flush interval, max buffer count and file name.
  2718. if ( pOrigQuery->Properties.BufferSize != pNewQuery->dwBufferSize )
  2719. return FALSE;
  2720. if ( pOrigQuery->Properties.MinimumBuffers != pNewQuery->dwBufferMinCount )
  2721. return FALSE;
  2722. // Not kernel trace, so check query name
  2723. if ((BOOL)( 0 == ( pNewQuery->dwFlags & SLQ_TLI_ENABLE_KERNEL_TRACE ) ) ) {
  2724. if ( 0 != lstrcmpi ( pOrigQuery->szLoggerName, pNewQuery->szQueryName ) ) {
  2725. return FALSE;
  2726. }
  2727. }
  2728. bRequested = (BOOL)( 0 != ( pNewQuery->dwFlags & SLQ_TLI_ENABLE_KERNEL_TRACE ) );
  2729. bCurrent = IsEqualGUID( &pOrigQuery->Properties.Wnode.Guid, &SystemTraceControlGuid );
  2730. if ( bRequested != bCurrent ) {
  2731. return FALSE;
  2732. }
  2733. // Extended memory trace
  2734. bRequested = (BOOL)( 0 != ( pNewQuery->dwFlags & SLQ_TLI_ENABLE_MEMMAN_TRACE ) );
  2735. bCurrent = (BOOL)( 0 != ( pOrigQuery->Properties.EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS ) );
  2736. if ( bRequested != bCurrent ) {
  2737. return FALSE;
  2738. }
  2739. // Extended I/O trace
  2740. bRequested = (BOOL)( 0 != ( pNewQuery->dwFlags & SLQ_TLI_ENABLE_FILEIO_TRACE ) );
  2741. bCurrent = (BOOL)( 0 != ( pOrigQuery->Properties.EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO ) );
  2742. if ( bRequested != bCurrent ) {
  2743. return FALSE;
  2744. }
  2745. if ( -1 == pNewQuery->dwMaxFileSize ) {
  2746. if ( 0 != pOrigQuery->Properties.MaximumFileSize ) {
  2747. return FALSE;
  2748. }
  2749. } else if ( pOrigQuery->Properties.MaximumFileSize != pNewQuery->dwMaxFileSize ) {
  2750. return FALSE;
  2751. }
  2752. if ( ( SLF_SEQ_TRACE_FILE == pNewQuery->dwLogFileType )
  2753. && ( EVENT_TRACE_FILE_MODE_SEQUENTIAL != pOrigQuery->Properties.LogFileMode ) ) {
  2754. return FALSE;
  2755. } else if ( ( SLF_CIRC_TRACE_FILE == pNewQuery->dwLogFileType )
  2756. && ( EVENT_TRACE_FILE_MODE_CIRCULAR != pOrigQuery->Properties.LogFileMode ) ) {
  2757. return FALSE;
  2758. }
  2759. // Compare each provider string against array element.
  2760. for (pszThisGuid = pNewQuery->mszProviderList;
  2761. *pszThisGuid != 0;
  2762. pszThisGuid += lstrlen(pszThisGuid) + 1) {
  2763. ulGuidCount += 1;
  2764. }
  2765. if ( pOrigQuery->ulGuidCount != ulGuidCount )
  2766. return FALSE;
  2767. ulGuidIndex = 0;
  2768. for (pszThisGuid = pNewQuery->mszProviderList;
  2769. *pszThisGuid != 0;
  2770. pszThisGuid += lstrlen(pszThisGuid) + 1) {
  2771. if ( 0 != lstrcmpi ( pOrigQuery->arrpszProviderName[ulGuidIndex], pszThisGuid ) )
  2772. return FALSE;
  2773. ulGuidIndex++;
  2774. assert ( ulGuidIndex <= ulGuidCount );
  2775. }
  2776. return TRUE;
  2777. #else
  2778. return FALSE;
  2779. #endif
  2780. }
  2781. BOOL
  2782. AlertFieldsMatch (
  2783. IN PLOG_QUERY_DATA pFirstQuery,
  2784. IN PLOG_QUERY_DATA pSecondQuery )
  2785. {
  2786. if ( pFirstQuery->dwAlertActionFlags != pSecondQuery->dwAlertActionFlags )
  2787. return FALSE;
  2788. if ( 0 != (pFirstQuery->dwAlertActionFlags & ALRT_ACTION_SEND_MSG) ) {
  2789. if ( 0 != lstrcmpi ( pFirstQuery->szNetName, pSecondQuery->szNetName ) ) {
  2790. return FALSE;
  2791. }
  2792. }
  2793. if ( 0 != (pFirstQuery->dwAlertActionFlags & ALRT_ACTION_EXEC_CMD) ) {
  2794. if ( 0 != lstrcmpi ( pFirstQuery->szCmdFileName, pSecondQuery->szCmdFileName ) ) {
  2795. return FALSE;
  2796. }
  2797. if ( 0 != (pFirstQuery->dwAlertActionFlags & ALRT_CMD_LINE_U_TEXT ) ) {
  2798. if ( 0 != lstrcmpi ( pFirstQuery->szUserText, pSecondQuery->szUserText ) ) {
  2799. return FALSE;
  2800. }
  2801. }
  2802. }
  2803. if ( 0 != (pFirstQuery->dwAlertActionFlags & ALRT_ACTION_START_LOG) ) {
  2804. if ( 0 != lstrcmpi ( pFirstQuery->szPerfLogName, pSecondQuery->szPerfLogName ) ) {
  2805. return FALSE;
  2806. }
  2807. }
  2808. return TRUE;
  2809. }
  2810. BOOL
  2811. CommonFieldsMatch (
  2812. IN PLOG_QUERY_DATA pFirstQuery,
  2813. IN PLOG_QUERY_DATA pSecondQuery )
  2814. {
  2815. if ( pFirstQuery->dwCurrentState != pSecondQuery->dwCurrentState )
  2816. return FALSE;
  2817. if ( pFirstQuery->dwLogFileType != pSecondQuery->dwLogFileType )
  2818. return FALSE;
  2819. if ( pFirstQuery->dwAutoNameFormat != pSecondQuery->dwAutoNameFormat )
  2820. return FALSE;
  2821. if ( pFirstQuery->dwMaxFileSize != pSecondQuery->dwMaxFileSize )
  2822. return FALSE;
  2823. if ( pFirstQuery->stiRegStart.dwAutoMode != pSecondQuery->stiRegStart.dwAutoMode )
  2824. return FALSE;
  2825. if ( pFirstQuery->stiRegStop.dwAutoMode != pSecondQuery->stiRegStop.dwAutoMode )
  2826. return FALSE;
  2827. if ( pFirstQuery->stiRepeat.dwAutoMode != pSecondQuery->stiRepeat.dwAutoMode )
  2828. return FALSE;
  2829. if ( pFirstQuery->stiRegStart.llDateTime != pSecondQuery->stiRegStart.llDateTime )
  2830. return FALSE;
  2831. if ( pFirstQuery->stiRegStop.llDateTime != pSecondQuery->stiRegStop.llDateTime )
  2832. return FALSE;
  2833. if ( pFirstQuery->stiRepeat.llDateTime != pSecondQuery->stiRepeat.llDateTime )
  2834. return FALSE;
  2835. if (( SLQ_COUNTER_LOG == pFirstQuery->dwLogType ) ||
  2836. ( SLQ_TRACE_LOG == pFirstQuery->dwLogType)) {
  2837. if ( 0 != lstrcmpi ( pFirstQuery->szBaseFileName, pSecondQuery->szBaseFileName ) )
  2838. return FALSE;
  2839. if ( 0 != lstrcmpi ( pFirstQuery->szLogFileFolder, pSecondQuery->szLogFileFolder ) )
  2840. return FALSE;
  2841. if ( 0 != lstrcmpi ( pFirstQuery->szSqlLogName, pSecondQuery->szSqlLogName ) )
  2842. return FALSE;
  2843. if ( 0 != lstrcmpi ( pFirstQuery->szLogFileComment, pSecondQuery->szLogFileComment ) )
  2844. return FALSE;
  2845. if ( pFirstQuery->dwCurrentSerialNumber != pSecondQuery->dwCurrentSerialNumber )
  2846. return FALSE;
  2847. if ( pFirstQuery->dwLogFileSizeUnit != pSecondQuery->dwLogFileSizeUnit )
  2848. return FALSE;
  2849. if ( pFirstQuery->dwAppendMode != pSecondQuery->dwAppendMode )
  2850. return FALSE;
  2851. if ( pFirstQuery->stiCreateNewFile.dwAutoMode != pSecondQuery->stiCreateNewFile.dwAutoMode )
  2852. return FALSE;
  2853. if ( pFirstQuery->stiCreateNewFile.llDateTime != pSecondQuery->stiCreateNewFile.llDateTime )
  2854. return FALSE;
  2855. if ( 0 != lstrcmpi(pFirstQuery->szCmdFileName, pSecondQuery->szCmdFileName ) )
  2856. return FALSE;
  2857. }
  2858. if (( SLQ_COUNTER_LOG == pFirstQuery->dwLogType ) ||
  2859. ( SLQ_ALERT == pFirstQuery->dwLogType)) {
  2860. LPTSTR szFirstPath;
  2861. LPTSTR szSecondPath;
  2862. if ( pFirstQuery->dwMillisecondSampleInterval != pSecondQuery->dwMillisecondSampleInterval ) {
  2863. return FALSE;
  2864. }
  2865. // Compare each counter string. Note: If counter order has changed, the query is
  2866. // reconfigured.
  2867. // For Alert queries, this code also checks the limit threshold logic and value.
  2868. szSecondPath = pSecondQuery->mszCounterList;
  2869. for ( szFirstPath = pFirstQuery->mszCounterList;
  2870. *szFirstPath != 0;
  2871. szFirstPath += lstrlen(szFirstPath) + 1) {
  2872. if ( 0 != lstrcmpi( szFirstPath, szSecondPath ) ) {
  2873. return FALSE;
  2874. }
  2875. szSecondPath += lstrlen(szSecondPath) + 1;
  2876. }
  2877. if ( 0 != *szSecondPath ) {
  2878. return FALSE;
  2879. }
  2880. }
  2881. return TRUE;
  2882. }
  2883. BOOL
  2884. FieldsMatch (
  2885. IN PLOG_QUERY_DATA pFirstQuery,
  2886. IN PLOG_QUERY_DATA pSecondQuery )
  2887. {
  2888. assert ( pFirstQuery->dwLogType == pSecondQuery->dwLogType );
  2889. if ( !CommonFieldsMatch ( pFirstQuery, pSecondQuery ) )
  2890. return FALSE;
  2891. if ( SLQ_ALERT == pFirstQuery->dwLogType ) {
  2892. if ( !AlertFieldsMatch( pFirstQuery, pSecondQuery ) ) {
  2893. return FALSE;
  2894. }
  2895. } else if ( SLQ_TRACE_LOG == pFirstQuery->dwLogType ) {
  2896. LPTSTR szFirstProv;
  2897. LPTSTR szSecondProv;
  2898. if ( pFirstQuery->dwBufferSize != pSecondQuery->dwBufferSize )
  2899. return FALSE;
  2900. if ( pFirstQuery->dwBufferMinCount != pSecondQuery->dwBufferMinCount )
  2901. return FALSE;
  2902. if ( pFirstQuery->dwBufferMaxCount != pSecondQuery->dwBufferMaxCount )
  2903. return FALSE;
  2904. if ( pFirstQuery->dwBufferFlushInterval != pSecondQuery->dwBufferFlushInterval )
  2905. return FALSE;
  2906. if ( pFirstQuery->dwFlags != pSecondQuery->dwFlags )
  2907. return FALSE;
  2908. szSecondProv = pSecondQuery->mszProviderList;
  2909. for ( szFirstProv = pFirstQuery->mszProviderList;
  2910. *szFirstProv != 0;
  2911. szFirstProv += lstrlen(szFirstProv) + 1) {
  2912. if ( 0 != lstrcmpi ( szFirstProv, szSecondProv ) )
  2913. return FALSE;
  2914. szSecondProv += lstrlen(szSecondProv) + 1;
  2915. }
  2916. if ( 0 != *szSecondProv) {
  2917. return FALSE;
  2918. }
  2919. } else if ( SLQ_COUNTER_LOG == pFirstQuery->dwLogType ) {
  2920. if ( pFirstQuery->stiCreateNewFile.dwAutoMode != pSecondQuery->stiCreateNewFile.dwAutoMode ) {
  2921. return FALSE;
  2922. } else {
  2923. if ( SLQ_AUTO_MODE_AFTER == pFirstQuery->stiCreateNewFile.dwAutoMode
  2924. && pFirstQuery->stiCreateNewFile.llDateTime != pSecondQuery->stiCreateNewFile.llDateTime ) {
  2925. return FALSE;
  2926. } // else change in max size handled in commmon fields match check.
  2927. }
  2928. }
  2929. return TRUE;
  2930. }
  2931. DWORD
  2932. IsModified (
  2933. IN PLOG_QUERY_DATA pQuery,
  2934. OUT BOOL* pbModified
  2935. )
  2936. {
  2937. DWORD dwStatus;
  2938. SLQ_TIME_INFO stiLastModified;
  2939. SLQ_TIME_INFO stiDefault;
  2940. *pbModified = TRUE;
  2941. // Check the last read date against 'last modified' in
  2942. // the registry.
  2943. // If it is earlier than the registry, and the data in the
  2944. // registry has changed, return TRUE.
  2945. //
  2946. // The check of thread data against registry data reduces the
  2947. // number of times that the logging thread is interrupted.
  2948. // This is necessary because each property page OnApply
  2949. // generates this check.
  2950. //
  2951. stiDefault.wDataType = SLQ_TT_DTYPE_DATETIME;
  2952. stiDefault.wTimeType = SLQ_TT_TTYPE_LAST_MODIFIED;
  2953. stiDefault.dwAutoMode = SLQ_AUTO_MODE_AT;
  2954. stiDefault.llDateTime = MAX_TIME_VALUE;
  2955. dwStatus = ReadRegistrySlqTime (
  2956. pQuery->hKeyQuery,
  2957. pQuery->szQueryName,
  2958. (LPCTSTR)L"Last Modified",
  2959. &stiDefault,
  2960. &stiLastModified );
  2961. assert( ERROR_SUCCESS == dwStatus );
  2962. // Status always success if default provided.
  2963. if ( stiLastModified.llDateTime <= pQuery->llLastConfigured ) {
  2964. *pbModified = FALSE;
  2965. } else {
  2966. LOG_QUERY_DATA TempQuery;
  2967. memset (&TempQuery, 0, sizeof(TempQuery));
  2968. lstrcpy (TempQuery.szQueryName, pQuery->szQueryName);
  2969. TempQuery.hKeyQuery = pQuery->hKeyQuery;
  2970. if ( ERROR_SUCCESS != LoadQueryConfig( &TempQuery ) ) {
  2971. // Event has been logged. Set mod flag to stop the query.
  2972. *pbModified = TRUE;
  2973. } else {
  2974. *pbModified = !FieldsMatch ( pQuery, &TempQuery );
  2975. }
  2976. // Delete memory allocated by registry data load.
  2977. DeallocateQueryBuffers ( &TempQuery );
  2978. }
  2979. return dwStatus;
  2980. }
  2981. DWORD
  2982. ReconfigureQuery (
  2983. IN PLOG_QUERY_DATA pQuery )
  2984. {
  2985. DWORD dwStatus = ERROR_SUCCESS;
  2986. // *** Optimization - perform this check within IsModified, to avoid extra
  2987. // load from the registry.
  2988. LOG_QUERY_DATA TempQuery;
  2989. BOOL bStopQuery = FALSE;
  2990. memset (&TempQuery, 0, sizeof(TempQuery));
  2991. lstrcpy (TempQuery.szQueryName, pQuery->szQueryName);
  2992. TempQuery.hKeyQuery = pQuery->hKeyQuery;
  2993. if ( ERROR_SUCCESS != LoadQueryConfig( &TempQuery ) ) {
  2994. // Event has been logged. Stop the query.
  2995. bStopQuery = TRUE;
  2996. } else {
  2997. bStopQuery = ( NULL_INTERVAL_TICS == ComputeStartWaitTics ( &TempQuery, FALSE ) );
  2998. }
  2999. if ( !bStopQuery ) {
  3000. if ( SLQ_TRACE_LOG == pQuery->dwLogType
  3001. || SLQ_COUNTER_LOG == pQuery->dwLogType ) {
  3002. // Stop the query if new log file folder is not valid.
  3003. bStopQuery = ( ERROR_SUCCESS != ProcessLogFileFolder( &TempQuery, TRUE ) );
  3004. }
  3005. }
  3006. if ( bStopQuery ) {
  3007. #if _DEBUG_OUTPUT
  3008. {
  3009. TCHAR szDebugString[MAX_PATH];
  3010. swprintf (szDebugString, (LPCWSTR)L" Query %s: Set exit event\n", pQuery->szQueryName);
  3011. OutputDebugString (szDebugString);
  3012. }
  3013. #endif
  3014. SetEvent (pQuery->hExitEvent);
  3015. } else {
  3016. if (( SLQ_COUNTER_LOG == pQuery->dwLogType ) ||
  3017. ( SLQ_ALERT == pQuery->dwLogType ) ){
  3018. // Signal the logging thread to reconfigure.
  3019. pQuery->bLoadNewConfig= TRUE;
  3020. SetEvent (pQuery->hReconfigEvent);
  3021. } else {
  3022. #if _IMPLEMENT_WMI
  3023. BOOL bMustStopRestart;
  3024. assert( SLQ_TRACE_LOG == pQuery->dwLogType );
  3025. //
  3026. // Change the current query. For some properties, this
  3027. // means stopping then restarting the query.
  3028. //
  3029. bMustStopRestart = !TraceStopRestartFieldsMatch ( pQuery, &TempQuery );
  3030. if ( !bMustStopRestart ) {
  3031. if ( ERROR_SUCCESS != LoadQueryConfig( pQuery ) ) {
  3032. SetEvent (pQuery->hExitEvent);
  3033. } else {
  3034. // Update the trace log session. Do not increment
  3035. // the file autoformat serial number.
  3036. // Todo: File name serial number is already incremented.
  3037. InitTraceProperties ( pQuery, FALSE, NULL, NULL );
  3038. dwStatus = GetTraceQueryStatus ( pQuery, NULL );
  3039. if ( ERROR_SUCCESS == dwStatus ) {
  3040. dwStatus = UpdateTrace(
  3041. pQuery->LoggerHandle,
  3042. pQuery->szLoggerName,
  3043. &pQuery->Properties );
  3044. }
  3045. }
  3046. } else {
  3047. // Signal the logging thread to reconfigure.
  3048. pQuery->bLoadNewConfig= TRUE;
  3049. SetEvent (pQuery->hReconfigEvent);
  3050. }
  3051. }
  3052. }
  3053. #else
  3054. dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
  3055. #endif
  3056. return dwStatus;
  3057. }
  3058. DWORD
  3059. GetTraceQueryStatus (
  3060. IN PLOG_QUERY_DATA pQuery,
  3061. IN OUT PLOG_QUERY_DATA pReturnQuery )
  3062. {
  3063. DWORD dwStatus = ERROR_SUCCESS;
  3064. #if _IMPLEMENT_WMI
  3065. PLOG_QUERY_DATA pLocalQuery = NULL;
  3066. if ( NULL != pQuery ) {
  3067. if ( NULL != pReturnQuery ) {
  3068. pLocalQuery = pReturnQuery;
  3069. } else {
  3070. pLocalQuery = G_ALLOC ( sizeof (LOG_QUERY_DATA) );
  3071. }
  3072. if ( NULL != pLocalQuery ) {
  3073. ClearTraceProperties ( pLocalQuery );
  3074. pLocalQuery->Properties.Wnode.BufferSize = sizeof(pQuery->Properties)
  3075. + sizeof(pQuery->szLoggerName)
  3076. + sizeof(pQuery->szLogFileName);
  3077. pLocalQuery->Properties.Wnode.Flags = WNODE_FLAG_TRACED_GUID;
  3078. dwStatus = QueryTrace (
  3079. pQuery->LoggerHandle,
  3080. pQuery->szLoggerName,
  3081. &pLocalQuery->Properties );
  3082. if ( NULL == pReturnQuery ) {
  3083. G_FREE ( pLocalQuery );
  3084. }
  3085. } else {
  3086. dwStatus = ERROR_OUTOFMEMORY;
  3087. }
  3088. } else {
  3089. dwStatus = ERROR_INVALID_PARAMETER;
  3090. }
  3091. #else
  3092. dwStatus = ERROR_CALL_NOT_IMPLEMENTED;
  3093. #endif
  3094. return dwStatus;
  3095. }
  3096. DWORD
  3097. StartQuery (
  3098. IN PLOG_QUERY_DATA pQuery )
  3099. {
  3100. DWORD dwStatus = ERROR_SUCCESS;
  3101. LPTSTR szStringArray[2];
  3102. HANDLE hThread = NULL;
  3103. DWORD dwThreadId;
  3104. pQuery->bLoadNewConfig= FALSE;
  3105. // Create the logging thread.
  3106. hThread = CreateThread (
  3107. NULL, 0, LoggingThreadProc,
  3108. (LPVOID)pQuery, 0, &dwThreadId);
  3109. if ( NULL != hThread ) {
  3110. pQuery->hThread = hThread;
  3111. } else {
  3112. // unable to start thread
  3113. dwStatus = GetLastError();
  3114. szStringArray[0] = pQuery->szQueryName;
  3115. ReportEvent (hEventLog,
  3116. EVENTLOG_WARNING_TYPE,
  3117. 0,
  3118. SMLOG_UNABLE_START_THREAD,
  3119. NULL,
  3120. 1,
  3121. sizeof(DWORD),
  3122. szStringArray,
  3123. (LPVOID)&dwStatus);
  3124. }
  3125. if ( ERROR_SUCCESS != dwStatus ) {
  3126. SetStoppedStatus ( pQuery );
  3127. }
  3128. return dwStatus;
  3129. }
  3130. DWORD
  3131. SetStoppedStatus (
  3132. IN PLOG_QUERY_DATA pQuery )
  3133. {
  3134. DWORD dwStatus;
  3135. SYSTEMTIME st;
  3136. LONGLONG llTime;
  3137. pQuery->dwCurrentState = SLQ_QUERY_STOPPED;
  3138. dwStatus = WriteRegistryDwordValue (
  3139. pQuery->hKeyQuery,
  3140. (LPCTSTR)L"Current State",
  3141. &pQuery->dwCurrentState,
  3142. REG_DWORD );
  3143. if ( SLQ_AUTO_MODE_NONE == pQuery->stiRegStart.dwAutoMode ) {
  3144. pQuery->stiRegStart.llDateTime = MAX_TIME_VALUE;
  3145. dwStatus = WriteRegistrySlqTime (
  3146. pQuery->hKeyQuery,
  3147. (LPCTSTR)L"Start",
  3148. &pQuery->stiRegStart);
  3149. }
  3150. GetLocalTime(&st);
  3151. SystemTimeToFileTime (&st, (FILETIME *)&llTime);
  3152. // If stop is manual or StopAt with time before now (no repeat), set to manual
  3153. // with MIN_TIME_VALUE
  3154. if ( SLQ_AUTO_MODE_NONE == pQuery->stiRegStop.dwAutoMode
  3155. && llTime >= pQuery->stiRegStop.llDateTime )
  3156. {
  3157. pQuery->stiRegStop.dwAutoMode = SLQ_AUTO_MODE_NONE;
  3158. pQuery->stiRegStop.llDateTime = MIN_TIME_VALUE;
  3159. dwStatus = WriteRegistrySlqTime (
  3160. pQuery->hKeyQuery,
  3161. (LPCTSTR)L"Stop",
  3162. &pQuery->stiRegStop);
  3163. } else if ( ( SLQ_AUTO_MODE_AT == pQuery->stiRegStop.dwAutoMode
  3164. && ( SLQ_AUTO_MODE_CALENDAR != pQuery->stiRepeat.dwAutoMode ) )
  3165. && ( llTime >= pQuery->stiRegStop.llDateTime ) ) {
  3166. pQuery->stiRegStop.dwAutoMode = SLQ_AUTO_MODE_NONE;
  3167. pQuery->stiRegStop.llDateTime = MIN_TIME_VALUE;
  3168. dwStatus = WriteRegistrySlqTime (
  3169. pQuery->hKeyQuery,
  3170. (LPCTSTR)L"Stop",
  3171. &pQuery->stiRegStop);
  3172. }
  3173. return dwStatus;
  3174. }
  3175. DWORD
  3176. HandleMaxQueriesExceeded (
  3177. IN PLOG_QUERY_DATA pQuery )
  3178. {
  3179. DWORD dwStatus = ERROR_SUCCESS;
  3180. // The query has not been started yet, but still in "Start Pending" state.
  3181. SetStoppedStatus ( pQuery );
  3182. return dwStatus;
  3183. }
  3184. DWORD
  3185. ConfigureQuery (
  3186. HKEY hKeyLogQuery,
  3187. TCHAR* szQueryKeyNameBuffer,
  3188. TCHAR* szQueryNameBuffer )
  3189. {
  3190. DWORD dwStatus = ERROR_SUCCESS;
  3191. PLOG_QUERY_DATA pQuery = NULL;
  3192. pQuery = GetQueryData ( szQueryNameBuffer );
  3193. if ( NULL != pQuery ) {
  3194. BOOL bModified;
  3195. dwStatus = IsModified ( pQuery, &bModified );
  3196. if (dwStatus == ERROR_SUCCESS) {
  3197. if ( bModified ) {
  3198. dwStatus = ReconfigureQuery ( pQuery );
  3199. // LastModified and LastConfigured values are stored as GMT
  3200. GetSystemTimeAsFileTime ( (LPFILETIME)(&pQuery->llLastConfigured) );
  3201. }
  3202. }
  3203. } else {
  3204. // No query data block found. Create one and insert it into the list.
  3205. BOOL bStartQuery = FALSE;
  3206. LPTSTR szStringArray[2];
  3207. // Allocate a thread info block.
  3208. pQuery = G_ALLOC (sizeof(LOG_QUERY_DATA));
  3209. if (pQuery != NULL) {
  3210. // initialize the query data block
  3211. G_ZERO (pQuery, sizeof(LOG_QUERY_DATA));
  3212. pQuery->hKeyQuery = hKeyLogQuery;
  3213. lstrcpy (pQuery->szQueryName, szQueryNameBuffer);
  3214. lstrcpy (pQuery->szQueryKeyName, szQueryKeyNameBuffer);
  3215. // Determine whether to continue, based on whether start wait time
  3216. // is 0 or greater.
  3217. // The thread is reinitialized in the logging procedure.
  3218. // This pre-check avoids spurious thread creation.
  3219. dwStatus = LoadQueryConfig( pQuery );
  3220. if ( ERROR_SUCCESS != dwStatus ) {
  3221. // Event already logged.
  3222. bStartQuery = FALSE;
  3223. } else {
  3224. bStartQuery = ( NULL_INTERVAL_TICS != ComputeStartWaitTics ( pQuery, FALSE ) );
  3225. }
  3226. if ( bStartQuery ) {
  3227. if ( SLQ_TRACE_LOG == pQuery->dwLogType
  3228. || SLQ_COUNTER_LOG == pQuery->dwLogType ) {
  3229. bStartQuery = ( ERROR_SUCCESS == ProcessLogFileFolder( pQuery, FALSE ) );
  3230. }
  3231. }
  3232. if ( bStartQuery ) {
  3233. LockQueryData();
  3234. if ( dwActiveSessionCount < dwMaxActiveSessionCount ) {
  3235. pQuery->hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  3236. if ( NULL != pQuery->hExitEvent ) {
  3237. pQuery->hReconfigEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  3238. if ( NULL != pQuery->hReconfigEvent ) {
  3239. // LastModified and LastConfigured values are stored as GMT
  3240. GetSystemTimeAsFileTime ( (LPFILETIME)(&pQuery->llLastConfigured) );
  3241. dwStatus = StartQuery( pQuery );
  3242. if ( ERROR_SUCCESS == dwStatus ) {
  3243. // add it to the list and continue
  3244. if (pFirstQuery == NULL) {
  3245. // then this is the first thread so add it
  3246. pQuery->next = NULL;
  3247. pFirstQuery = pQuery;
  3248. } else {
  3249. // insert this at the head of the list since
  3250. // that's the easiest and the order isn't
  3251. // really important
  3252. pQuery->next = pFirstQuery;
  3253. pFirstQuery = pQuery;
  3254. }
  3255. dwActiveSessionCount += 1;
  3256. SetEvent (hNewQueryEvent );
  3257. } else {
  3258. // Unable to start query.
  3259. // Event has already been logged.
  3260. FreeQueryData ( pQuery );
  3261. }
  3262. } else {
  3263. // Unable to create reconfig event.
  3264. dwStatus = GetLastError();
  3265. szStringArray[0] = szQueryNameBuffer;
  3266. ReportEvent (hEventLog,
  3267. EVENTLOG_WARNING_TYPE,
  3268. 0,
  3269. SMLOG_UNABLE_CREATE_RECONFIG_EVENT,
  3270. NULL,
  3271. 1,
  3272. sizeof(DWORD),
  3273. szStringArray,
  3274. (LPVOID)&dwStatus);
  3275. FreeQueryData( pQuery );
  3276. }
  3277. } else {
  3278. // Unable to create exit event.
  3279. dwStatus = GetLastError();
  3280. szStringArray[0] = szQueryNameBuffer;
  3281. ReportEvent (hEventLog,
  3282. EVENTLOG_WARNING_TYPE,
  3283. 0,
  3284. SMLOG_UNABLE_CREATE_EXIT_EVENT,
  3285. NULL,
  3286. 1,
  3287. sizeof(DWORD),
  3288. szStringArray,
  3289. (LPVOID)&dwStatus);
  3290. FreeQueryData( pQuery );
  3291. }
  3292. } else {
  3293. szStringArray[0] = szQueryNameBuffer;
  3294. ReportEvent (hEventLog,
  3295. EVENTLOG_WARNING_TYPE,
  3296. 0,
  3297. SMLOG_MAXIMUM_QUERY_LIMIT,
  3298. NULL,
  3299. 1,
  3300. 0,
  3301. szStringArray,
  3302. NULL);
  3303. dwStatus = HandleMaxQueriesExceeded ( pQuery );
  3304. FreeQueryData ( pQuery );
  3305. }
  3306. UnlockQueryData();
  3307. } else {
  3308. // Wait time is -1, or config load error.
  3309. FreeQueryData( pQuery );
  3310. }
  3311. } else {
  3312. // Memory allocation error.
  3313. dwStatus = GetLastError();
  3314. szStringArray[0] = szQueryNameBuffer;
  3315. ReportEvent (hEventLog,
  3316. EVENTLOG_WARNING_TYPE,
  3317. 0,
  3318. SMLOG_UNABLE_ALLOCATE_DATABLOCK,
  3319. NULL,
  3320. 1,
  3321. sizeof(DWORD),
  3322. szStringArray,
  3323. (LPVOID)&dwStatus);
  3324. }
  3325. }
  3326. return dwStatus;
  3327. }
  3328. DWORD
  3329. DoLogCommandFile (
  3330. IN PLOG_QUERY_DATA pArg,
  3331. IN LPTSTR szLogFileName,
  3332. IN BOOL bStillRunning
  3333. )
  3334. {
  3335. DWORD dwStatus;
  3336. BOOL bStatus = FALSE;
  3337. const INT ciExtraChars = 3;
  3338. INT iBufLen = 0;
  3339. INT iStrLen = 0;
  3340. LPTSTR szCommandString = NULL;
  3341. LPTSTR szTempBuffer = NULL;
  3342. LONG lErrorMode;
  3343. LPWSTR szStringArray[3];
  3344. STARTUPINFO si;
  3345. PROCESS_INFORMATION pi;
  3346. DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS;
  3347. if ( NULL != pArg && NULL != szLogFileName ) {
  3348. if ( NULL != pArg->szCmdFileName ) {
  3349. dwStatus = pArg->dwCmdFileFailure;
  3350. if ( ERROR_SUCCESS == dwStatus ) {
  3351. iStrLen = lstrlen ( szLogFileName );
  3352. iBufLen = iStrLen + ciExtraChars + 1; // 1 is for NULL
  3353. szCommandString = (LPTSTR)G_ALLOC(iBufLen * sizeof(TCHAR));
  3354. iBufLen += lstrlen ( pArg->szCmdFileName ) + 1; // 1 is for space char,
  3355. // NULL already counted.
  3356. szTempBuffer = (LPTSTR)G_ALLOC(iBufLen * sizeof(TCHAR));
  3357. if ( NULL != szCommandString && NULL != szTempBuffer ) {
  3358. // build command line arguments
  3359. szCommandString[0] = _T('\"');
  3360. lstrcpy (&szCommandString[1], szLogFileName );
  3361. lstrcpy (&szCommandString[iStrLen+1], (LPCTSTR)(LPCTSTR)TEXT("\" "));
  3362. lstrcpy (&szCommandString[iStrLen+2],
  3363. (bStillRunning ? (LPCTSTR)(LPCTSTR)TEXT("1") : (LPCTSTR)TEXT("0")));
  3364. // initialize Startup Info block
  3365. memset (&si, 0, sizeof(si));
  3366. si.cb = sizeof(si);
  3367. si.dwFlags = STARTF_USESHOWWINDOW ;
  3368. si.wShowWindow = SW_SHOWNOACTIVATE ;
  3369. //si.lpDesktop = L"WinSta0\\Default";
  3370. memset (&pi, 0, sizeof(pi));
  3371. // supress pop-ups in the detached process
  3372. lErrorMode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  3373. lstrcpy (szTempBuffer, pArg->szCmdFileName) ;
  3374. // see if this is a CMD or a BAT file
  3375. // if it is then create a process with a console window, otherwise
  3376. // assume it's an executable file that will create it's own window
  3377. // or console if necessary
  3378. //
  3379. _tcslwr (szTempBuffer);
  3380. if ((_tcsstr(szTempBuffer, (LPCTSTR)TEXT(".bat")) != NULL)
  3381. || (_tcsstr(szTempBuffer, (LPCTSTR)TEXT(".cmd")) != NULL))
  3382. {
  3383. dwCreationFlags |= CREATE_NEW_CONSOLE;
  3384. } else {
  3385. dwCreationFlags |= DETACHED_PROCESS;
  3386. }
  3387. // recopy the image name to the temp buffer since it was modified
  3388. // (i.e. lowercased) for the previous comparison.
  3389. lstrcpy (szTempBuffer, pArg->szCmdFileName) ;
  3390. iStrLen = lstrlen (szTempBuffer) ;
  3391. // now add on the alert text preceded with a space char
  3392. szTempBuffer [iStrLen] = TEXT(' ') ;
  3393. iStrLen++ ;
  3394. lstrcpy (&szTempBuffer[iStrLen], szCommandString) ;
  3395. if( pArg->hUserToken != NULL ){
  3396. bStatus = CreateProcessAsUser (
  3397. pArg->hUserToken,
  3398. NULL,
  3399. szTempBuffer,
  3400. NULL, NULL, FALSE,
  3401. dwCreationFlags,
  3402. NULL,
  3403. NULL,
  3404. &si,
  3405. &pi);
  3406. } else {
  3407. bStatus = CreateProcess (
  3408. NULL,
  3409. szTempBuffer,
  3410. NULL, NULL, FALSE,
  3411. dwCreationFlags,
  3412. NULL,
  3413. NULL,
  3414. &si,
  3415. &pi);
  3416. }
  3417. SetErrorMode(lErrorMode);
  3418. if (bStatus) {
  3419. dwStatus = ERROR_SUCCESS;
  3420. if ( NULL != pi.hThread && INVALID_HANDLE_VALUE != pi.hThread ) {
  3421. CloseHandle(pi.hThread);
  3422. pi.hThread = NULL;
  3423. }
  3424. if ( NULL != pi.hProcess && INVALID_HANDLE_VALUE != pi.hProcess ) {
  3425. CloseHandle(pi.hProcess);
  3426. pi.hProcess = NULL;
  3427. }
  3428. } else {
  3429. dwStatus = GetLastError();
  3430. }
  3431. } else {
  3432. dwStatus = ERROR_OUTOFMEMORY;
  3433. }
  3434. if ( ERROR_SUCCESS != dwStatus ) {
  3435. szStringArray[0] = szTempBuffer;
  3436. szStringArray[1] = pArg->szQueryName;
  3437. szStringArray[2] = FormatEventLogMessage(dwStatus);
  3438. ReportEvent (hEventLog,
  3439. EVENTLOG_WARNING_TYPE,
  3440. 0,
  3441. SMLOG_LOG_CMD_FAIL,
  3442. NULL,
  3443. 3,
  3444. sizeof(DWORD),
  3445. szStringArray,
  3446. (LPVOID)&dwStatus );
  3447. pArg->dwCmdFileFailure = dwStatus;
  3448. }
  3449. if (szCommandString != NULL) G_FREE(szCommandString);
  3450. if (szTempBuffer != NULL) G_FREE(szTempBuffer);
  3451. }
  3452. } else {
  3453. dwStatus = ERROR_INVALID_PARAMETER;
  3454. }
  3455. } else {
  3456. dwStatus = ERROR_INVALID_PARAMETER;
  3457. }
  3458. return dwStatus;
  3459. }
  3460. DWORD
  3461. GetQueryKeyName (
  3462. IN LPCTSTR szQueryName,
  3463. OUT LPTSTR szQueryKeyName,
  3464. IN DWORD dwQueryKeyNameLen )
  3465. {
  3466. DWORD dwStatus = ERROR_SUCCESS;
  3467. HKEY hKeyLogQueries = NULL;
  3468. HKEY hKeyThisLogQuery = NULL;
  3469. DWORD dwQueryIndex;
  3470. TCHAR szQueryNameBuffer[MAX_PATH+1];
  3471. DWORD dwQueryNameBufferSize;
  3472. TCHAR szQueryKeyNameBuffer[MAX_PATH+1];
  3473. TCHAR szQueryClassBuffer[MAX_PATH+1];
  3474. DWORD dwQueryClassBufferSize;
  3475. LPTSTR szCollectionName = NULL;
  3476. UINT uiCollectionNameLen = 0;
  3477. LPTSTR szStringArray[2];
  3478. assert ( 0 < lstrlen ( szQueryName ) );
  3479. if ( NULL != szQueryName
  3480. && NULL != szQueryKeyName ) {
  3481. if ( 0 < lstrlen ( szQueryName )
  3482. && 0 < dwQueryKeyNameLen ) {
  3483. // Note: This method does not reallocate buffer or return
  3484. // actual buffer size required.
  3485. memset ( szQueryKeyName, 0, dwQueryKeyNameLen * sizeof (TCHAR) );
  3486. dwStatus = OpenLogQueriesKey (
  3487. KEY_READ,
  3488. (PHKEY)&hKeyLogQueries);
  3489. if (dwStatus != ERROR_SUCCESS) {
  3490. // unable to read the log query information from the registry
  3491. dwStatus = GetLastError();
  3492. ReportEvent (hEventLog,
  3493. EVENTLOG_ERROR_TYPE,
  3494. 0,
  3495. SMLOG_UNABLE_OPEN_LOG_QUERY,
  3496. NULL,
  3497. 0,
  3498. 0,
  3499. NULL,
  3500. NULL);
  3501. } else {
  3502. // Enumerate the queries in the registry.
  3503. dwQueryIndex = 0;
  3504. *szQueryNameBuffer = 0;
  3505. dwQueryNameBufferSize = MAX_PATH+1;
  3506. *szQueryClassBuffer = 0;
  3507. dwQueryClassBufferSize = MAX_PATH+1;
  3508. while ((dwStatus = RegEnumKeyEx (
  3509. hKeyLogQueries,
  3510. dwQueryIndex,
  3511. szQueryNameBuffer,
  3512. &dwQueryNameBufferSize,
  3513. NULL,
  3514. szQueryClassBuffer,
  3515. &dwQueryClassBufferSize,
  3516. NULL)) != ERROR_NO_MORE_ITEMS)
  3517. {
  3518. // open this key
  3519. dwStatus = RegOpenKeyEx (
  3520. hKeyLogQueries,
  3521. szQueryNameBuffer,
  3522. 0L,
  3523. KEY_READ,
  3524. (PHKEY)&hKeyThisLogQuery);
  3525. if (dwStatus == ERROR_SUCCESS) {
  3526. if ( 0 == lstrcmpi ( szQueryNameBuffer, szQueryName ) ) {
  3527. if ( dwQueryKeyNameLen > (DWORD)lstrlen ( szQueryName ) ) {
  3528. lstrcpyn ( szQueryKeyName, szQueryName, min (MAX_PATH, lstrlen (szQueryName) + 1 ) );
  3529. break;
  3530. }
  3531. } else {
  3532. dwStatus = SmReadRegistryIndirectStringValue (
  3533. hKeyThisLogQuery,
  3534. L"Collection Name",
  3535. NULL,
  3536. &szCollectionName,
  3537. &uiCollectionNameLen );
  3538. if ( NULL != szCollectionName ) {
  3539. if ( 0 < lstrlen(szCollectionName) ) {
  3540. if ( 0 == lstrcmpi ( szCollectionName, szQueryName ) ) {
  3541. if ( dwQueryKeyNameLen > (DWORD)lstrlen ( szQueryNameBuffer ) ) {
  3542. lstrcpyn ( szQueryKeyName, szQueryNameBuffer, min (MAX_PATH, lstrlen (szQueryNameBuffer) + 1 ) );
  3543. break;
  3544. }
  3545. }
  3546. }
  3547. G_FREE ( szCollectionName );
  3548. szCollectionName = NULL;
  3549. uiCollectionNameLen = 0;
  3550. }
  3551. }
  3552. }
  3553. if ( NULL != hKeyThisLogQuery ) {
  3554. RegCloseKey ( hKeyThisLogQuery );
  3555. hKeyThisLogQuery = NULL;
  3556. }
  3557. // prepare for next loop
  3558. dwStatus = ERROR_SUCCESS;
  3559. dwQueryIndex++;
  3560. *szQueryNameBuffer = 0;
  3561. dwQueryNameBufferSize = MAX_PATH;
  3562. *szQueryClassBuffer = 0;
  3563. dwQueryClassBufferSize = MAX_PATH;
  3564. } // end enumeration of log queries
  3565. }
  3566. if ( ERROR_NO_MORE_ITEMS == dwStatus ) {
  3567. dwStatus = ERROR_SUCCESS;
  3568. }
  3569. } else {
  3570. dwStatus = ERROR_INVALID_PARAMETER;
  3571. }
  3572. } else {
  3573. dwStatus = ERROR_INVALID_PARAMETER;
  3574. }
  3575. if ( NULL != hKeyLogQueries ) {
  3576. RegCloseKey (hKeyLogQueries );
  3577. }
  3578. return dwStatus;
  3579. }
  3580. DWORD
  3581. Configure ( void )
  3582. {
  3583. DWORD dwStatus;
  3584. HKEY hKeyLogQueries = NULL;
  3585. HKEY hKeyThisLogQuery = NULL;
  3586. DWORD dwQueryIndex;
  3587. TCHAR szQueryNameBuffer[MAX_PATH+1];
  3588. DWORD dwQueryNameBufferSize;
  3589. TCHAR szQueryKeyNameBuffer[MAX_PATH+1];
  3590. TCHAR szQueryClassBuffer[MAX_PATH+1];
  3591. DWORD dwQueryClassBufferSize;
  3592. LPTSTR szCollectionName = NULL;
  3593. UINT uiCollectionNameLen = 0;
  3594. LPTSTR szStringArray[2];
  3595. __try {
  3596. // Open each query in the registry
  3597. dwStatus = OpenLogQueriesKey (
  3598. KEY_READ,
  3599. (PHKEY)&hKeyLogQueries);
  3600. if (dwStatus != ERROR_SUCCESS) {
  3601. if (dwStatus == ERROR_FILE_NOT_FOUND) {
  3602. // no logs nor alerts settings, bail out quietly
  3603. //
  3604. dwStatus = ERROR_SUCCESS;
  3605. }
  3606. else {
  3607. // unable to read the log query information from the registry
  3608. dwStatus = GetLastError();
  3609. ReportEvent (hEventLog,
  3610. EVENTLOG_ERROR_TYPE,
  3611. 0,
  3612. SMLOG_UNABLE_OPEN_LOG_QUERY,
  3613. NULL,
  3614. 0,
  3615. 0,
  3616. NULL,
  3617. NULL);
  3618. }
  3619. } else {
  3620. // enumerate and restart or start the queries in the registry
  3621. dwQueryIndex = 0;
  3622. *szQueryNameBuffer = 0;
  3623. dwQueryNameBufferSize = MAX_PATH+1;
  3624. *szQueryClassBuffer = 0;
  3625. dwQueryClassBufferSize = MAX_PATH+1;
  3626. while ((dwStatus = RegEnumKeyEx (
  3627. hKeyLogQueries,
  3628. dwQueryIndex,
  3629. szQueryNameBuffer,
  3630. &dwQueryNameBufferSize,
  3631. NULL,
  3632. szQueryClassBuffer,
  3633. &dwQueryClassBufferSize,
  3634. NULL)) != ERROR_NO_MORE_ITEMS) {
  3635. // open this key
  3636. dwStatus = RegOpenKeyEx (
  3637. hKeyLogQueries,
  3638. szQueryNameBuffer,
  3639. 0L,
  3640. KEY_READ | KEY_WRITE,
  3641. (PHKEY)&hKeyThisLogQuery);
  3642. if (dwStatus == ERROR_SUCCESS) {
  3643. // update the service status
  3644. ssSmLogStatus.dwCheckPoint++;
  3645. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  3646. if ( 0 < lstrlen(szQueryNameBuffer) ) {
  3647. lstrcpyn (
  3648. szQueryKeyNameBuffer,
  3649. szQueryNameBuffer,
  3650. min(MAX_PATH, lstrlen(szQueryNameBuffer)+1 ) );
  3651. }
  3652. dwStatus = SmReadRegistryIndirectStringValue (
  3653. hKeyThisLogQuery,
  3654. L"Collection Name",
  3655. NULL,
  3656. &szCollectionName,
  3657. &uiCollectionNameLen );
  3658. if ( NULL != szCollectionName ) {
  3659. if ( 0 < lstrlen(szCollectionName) ) {
  3660. lstrcpyn (
  3661. szQueryNameBuffer,
  3662. szCollectionName,
  3663. min(MAX_PATH, lstrlen(szCollectionName)+1 ) );
  3664. }
  3665. G_FREE ( szCollectionName );
  3666. szCollectionName = NULL;
  3667. uiCollectionNameLen = 0;
  3668. }
  3669. dwStatus = ConfigureQuery (
  3670. hKeyThisLogQuery,
  3671. szQueryKeyNameBuffer,
  3672. szQueryNameBuffer );
  3673. // hKeyThisLogQuery is stored in the Query data structure.
  3674. } else {
  3675. szStringArray[0] = szQueryNameBuffer;
  3676. ReportEvent (hEventLog,
  3677. EVENTLOG_WARNING_TYPE,
  3678. 0,
  3679. SMLOG_UNABLE_READ_LOG_QUERY,
  3680. NULL,
  3681. 1,
  3682. sizeof(DWORD),
  3683. szStringArray,
  3684. (LPVOID)&dwStatus);
  3685. }
  3686. // prepare for next loop
  3687. dwStatus = ERROR_SUCCESS;
  3688. dwQueryIndex++;
  3689. *szQueryNameBuffer = 0;
  3690. dwQueryNameBufferSize = MAX_PATH;
  3691. *szQueryClassBuffer = 0;
  3692. dwQueryClassBufferSize = MAX_PATH;
  3693. } // end enumeration of log queries
  3694. }
  3695. if ( ERROR_NO_MORE_ITEMS == dwStatus ) {
  3696. dwStatus = ERROR_SUCCESS;
  3697. }
  3698. } __except ( EXCEPTION_EXECUTE_HANDLER ) {
  3699. dwStatus = SMLOG_THREAD_FAILED;
  3700. }
  3701. if ( NULL != hKeyLogQueries ) {
  3702. RegCloseKey (hKeyLogQueries );
  3703. }
  3704. return dwStatus;
  3705. }
  3706. void SysmonLogServiceControlHandler(
  3707. IN DWORD dwControl
  3708. )
  3709. {
  3710. PLOG_QUERY_DATA pQuery;
  3711. DWORD dwStatus;
  3712. switch (dwControl) {
  3713. case SERVICE_CONTROL_SYNCHRONIZE:
  3714. EnterConfigure();
  3715. dwStatus = Configure ();
  3716. ExitConfigure();
  3717. if ( ERROR_SUCCESS == dwStatus )
  3718. break;
  3719. // If not successful, fall through to shutdown.
  3720. // Errors already logged.
  3721. case SERVICE_CONTROL_SHUTDOWN:
  3722. case SERVICE_CONTROL_STOP:
  3723. // stop logging & close queries and files
  3724. // set stop event for all running thread
  3725. LockQueryData();
  3726. ssSmLogStatus.dwCurrentState = SERVICE_STOP_PENDING;
  3727. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  3728. pQuery = pFirstQuery;
  3729. while (pQuery != NULL) {
  3730. SetEvent (pQuery->hExitEvent);
  3731. pQuery = pQuery->next;
  3732. }
  3733. UnlockQueryData();
  3734. break;
  3735. case SERVICE_CONTROL_PAUSE:
  3736. // stop logging, close queries and files
  3737. // not supported, yet
  3738. break;
  3739. case SERVICE_CONTROL_CONTINUE:
  3740. // reload ration and restart logging
  3741. // not supported, yet
  3742. break;
  3743. case SERVICE_CONTROL_INTERROGATE:
  3744. // update current status
  3745. default:
  3746. // report to event log that an unrecognized control
  3747. // request was received.
  3748. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  3749. }
  3750. }
  3751. void
  3752. SysmonLogServiceStart (
  3753. IN DWORD argc,
  3754. IN LPTSTR *argv
  3755. )
  3756. {
  3757. DWORD dwStatus = ERROR_SUCCESS;
  3758. DWORD dwQueryIndex;
  3759. BOOL bInteractive = FALSE;
  3760. BOOL bLogQueriesKeyExists = TRUE;
  3761. if ((argc == 1) && (*argv[0] == 'I')) bInteractive = TRUE;
  3762. #if _DEBUG_OUTPUT
  3763. if ( NULL != hEventLog ) {
  3764. ReportEvent (hEventLog,
  3765. EVENTLOG_INFORMATION_TYPE,
  3766. 0,
  3767. SMLOG_DEBUG_STARTING_SERVICE,
  3768. NULL,
  3769. 0,
  3770. 0,
  3771. NULL,
  3772. NULL);
  3773. }
  3774. #endif
  3775. if (!bInteractive) {
  3776. ssSmLogStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  3777. ssSmLogStatus.dwCurrentState = SERVICE_START_PENDING;
  3778. ssSmLogStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  3779. // SERVICE_ACCEPT_PAUSE_CONTINUE |
  3780. SERVICE_ACCEPT_SHUTDOWN;
  3781. ssSmLogStatus.dwWin32ExitCode = 0;
  3782. ssSmLogStatus.dwServiceSpecificExitCode = 0;
  3783. ssSmLogStatus.dwCheckPoint = 0;
  3784. ssSmLogStatus.dwWaitHint = 1000;
  3785. hSmLogStatus = RegisterServiceCtrlHandler (
  3786. (LPCTSTR)TEXT("SysmonLog"), SysmonLogServiceControlHandler);
  3787. if (hSmLogStatus == (SERVICE_STATUS_HANDLE)0) {
  3788. dwStatus = GetLastError();
  3789. ReportEvent (hEventLog,
  3790. EVENTLOG_ERROR_TYPE,
  3791. 0,
  3792. SMLOG_UNABLE_REGISTER_HANDLER,
  3793. NULL,
  3794. 0,
  3795. sizeof(DWORD),
  3796. NULL,
  3797. (LPVOID)&dwStatus);
  3798. // this is fatal so bail out
  3799. }
  3800. #if _DEBUG_OUTPUT
  3801. else {
  3802. if ( NULL != hEventLog ) {
  3803. ReportEvent (hEventLog,
  3804. EVENTLOG_INFORMATION_TYPE,
  3805. 0,
  3806. SMLOG_DEBUG_HANDLER_REGISTERED,
  3807. NULL,
  3808. 0,
  3809. 0,
  3810. NULL,
  3811. NULL);
  3812. }
  3813. }
  3814. #endif
  3815. }
  3816. if ( ERROR_SUCCESS == dwStatus ) {
  3817. InitializeCriticalSection ( &QueryDataLock );
  3818. InitializeCriticalSection ( &ConfigurationLock );
  3819. #if _DEBUG_OUTPUT
  3820. ssSmLogStatus.dwCurrentState = SERVICE_RUNNING;
  3821. ssSmLogStatus.dwCheckPoint++;
  3822. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  3823. #endif
  3824. dwStatus = ClearQueryRunStates();
  3825. #if _DEBUG_OUTPUT
  3826. if ( NULL != hEventLog ) {
  3827. ReportEvent (hEventLog,
  3828. EVENTLOG_INFORMATION_TYPE,
  3829. 0,
  3830. SMLOG_DEBUG_CLEAR_RUN_STATES,
  3831. NULL,
  3832. sizeof(DWORD),
  3833. 0,
  3834. NULL,
  3835. (LPVOID)&dwStatus);
  3836. }
  3837. #endif
  3838. // Continue even if query run state error, unless
  3839. // the Log Queries key is missing or not accessible.
  3840. if ( SMLOG_UNABLE_OPEN_LOG_QUERY == dwStatus ) {
  3841. bLogQueriesKeyExists = FALSE;
  3842. // Sleep long enough for event to be written to event log.
  3843. Sleep(500);
  3844. if (!bInteractive) {
  3845. ssSmLogStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
  3846. // Use status mask so that error matches the code in the application log.
  3847. ssSmLogStatus.dwServiceSpecificExitCode = (SMLOG_UNABLE_OPEN_LOG_QUERY & STATUS_MASK);
  3848. }
  3849. } else {
  3850. dwStatus = ERROR_SUCCESS;
  3851. // Continue on error.
  3852. LoadDefaultLogFileFolder();
  3853. // Ignore PDH errors. The only possible error is that the default
  3854. // data source has already been set for this process.
  3855. // Set the default for the service to DATA_SOURCE_REGISTRY
  3856. dwStatus = PdhSetDefaultRealTimeDataSource ( DATA_SOURCE_REGISTRY );
  3857. #if _DEBUG_OUTPUT
  3858. if ( NULL != hEventLog ) {
  3859. ReportEvent (hEventLog,
  3860. EVENTLOG_INFORMATION_TYPE,
  3861. 0,
  3862. SMLOG_DEBUG_DEFAULT_FOLDER_LOADED,
  3863. NULL,
  3864. 0,
  3865. 0,
  3866. NULL,
  3867. NULL);
  3868. }
  3869. #endif
  3870. // Continue on error.
  3871. LoadPdhLogUpdateSuccess();
  3872. hNewQueryEvent = CreateEvent ( NULL, TRUE, FALSE, NULL );
  3873. if ( NULL == hNewQueryEvent ) {
  3874. // Unable to create new query configuration event.
  3875. dwStatus = GetLastError();
  3876. ReportEvent (hEventLog,
  3877. EVENTLOG_WARNING_TYPE,
  3878. 0,
  3879. SMLOG_UNABLE_CREATE_CONFIG_EVENT,
  3880. NULL,
  3881. 0,
  3882. sizeof(DWORD),
  3883. NULL,
  3884. (LPVOID)&dwStatus);
  3885. // this is fatal so bail out
  3886. if (!bInteractive) {
  3887. // Sleep long enough for event to be written to event log.
  3888. Sleep(500);
  3889. ssSmLogStatus.dwWin32ExitCode = dwStatus;
  3890. }
  3891. }
  3892. #if _DEBUG_OUTPUT
  3893. else {
  3894. if ( NULL != hEventLog ) {
  3895. ReportEvent (hEventLog,
  3896. EVENTLOG_INFORMATION_TYPE,
  3897. 0,
  3898. SMLOG_DEBUG_CONFIG_EVENT_CREATED,
  3899. NULL,
  3900. 0,
  3901. 0,
  3902. NULL,
  3903. 0);
  3904. }
  3905. }
  3906. #endif
  3907. if ( ( ERROR_SUCCESS == dwStatus ) && !bInteractive) {
  3908. // Thread synchronization mechanisms now created,
  3909. // so set status to Running.
  3910. ssSmLogStatus.dwCurrentState = SERVICE_RUNNING;
  3911. ssSmLogStatus.dwCheckPoint = 0;
  3912. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  3913. }
  3914. #if _IMPLEMENT_WMI
  3915. if ( ERROR_SUCCESS == dwStatus ) {
  3916. // Disable 64-bit warning
  3917. #if _MSC_VER >= 1200
  3918. #pragma warning(push)
  3919. #endif
  3920. #pragma warning ( disable : 4152 )
  3921. dwStatus = WmiNotificationRegistration(
  3922. (const LPGUID) & TraceErrorGuid,
  3923. TRUE,
  3924. TraceNotificationCallback,
  3925. 0,
  3926. NOTIFICATION_CALLBACK_DIRECT);
  3927. #if _MSC_VER >= 1200
  3928. #pragma warning(pop)
  3929. #endif
  3930. }
  3931. #endif
  3932. // Set up the queries and start threads.
  3933. if ( ERROR_SUCCESS == dwStatus && bLogQueriesKeyExists) {
  3934. EnterConfigure();
  3935. dwStatus = Configure ();
  3936. ExitConfigure();
  3937. }
  3938. if ( NULL == pFirstQuery ) {
  3939. // Nothing to do. Stop the service.
  3940. if (!bInteractive) {
  3941. ssSmLogStatus.dwCurrentState = SERVICE_STOP_PENDING;
  3942. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  3943. }
  3944. } else if ( ERROR_SUCCESS == dwStatus ) {
  3945. // Loop in WaitForMultipleObjects. When any
  3946. // query is signaled, deallocate that query data block
  3947. // and close its handles.
  3948. while ( TRUE ) {
  3949. BOOL bStatus;
  3950. LockQueryData();
  3951. // About to reconfigure the Wait array, so clear the event.
  3952. bStatus = ResetEvent ( hNewQueryEvent );
  3953. if ( NULL == pFirstQuery ) {
  3954. if (!bInteractive) {
  3955. ssSmLogStatus.dwCurrentState = SERVICE_STOP_PENDING;
  3956. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  3957. }
  3958. UnlockQueryData();
  3959. break;
  3960. } else {
  3961. DWORD dwIndex = 0;
  3962. DWORD dwWaitStatus;
  3963. PLOG_QUERY_DATA pQuery;
  3964. assert ( 0 < dwActiveSessionCount );
  3965. G_ZERO( arrSessionHandle, sizeof( HANDLE ) * ( dwActiveSessionCount + 1) );
  3966. // The first element is the global hNewQueryEvent to signal new sessions.
  3967. arrSessionHandle[dwIndex] = hNewQueryEvent;
  3968. dwIndex++;
  3969. for ( pQuery = pFirstQuery;
  3970. NULL != pQuery;
  3971. pQuery = pQuery->next ) {
  3972. assert ( NULL != pQuery->hThread );
  3973. if ( NULL != pQuery->hExitEvent && NULL != pQuery->hThread ) {
  3974. arrSessionHandle[dwIndex] = pQuery->hThread;
  3975. dwIndex++;
  3976. assert ( dwIndex <= dwActiveSessionCount + 1 );
  3977. }
  3978. }
  3979. UnlockQueryData();
  3980. // xxx handle error
  3981. dwWaitStatus = WaitForMultipleObjects (
  3982. dwIndex,
  3983. arrSessionHandle,
  3984. FALSE,
  3985. INFINITE );
  3986. // when here, either a new query has been started, or
  3987. // at least one logging thread or has terminated so the
  3988. // memory can be released.
  3989. dwQueryIndex = dwWaitStatus - WAIT_OBJECT_0;
  3990. // release the dynamic memory if the wait object is not the StartQuery event.
  3991. if ( 0 < dwQueryIndex && dwQueryIndex < dwIndex ) {
  3992. SetStoppedStatus( GetQueryDataPtr( arrSessionHandle[dwQueryIndex] ) );
  3993. RemoveAndFreeQueryData( arrSessionHandle[dwQueryIndex] );
  3994. }
  3995. }
  3996. } // End while
  3997. }
  3998. #if _IMPLEMENT_WMI
  3999. // Disable 64-bit warning
  4000. #if _MSC_VER >= 1200
  4001. #pragma warning(push)
  4002. #endif
  4003. #pragma warning ( disable : 4152 )
  4004. WmiNotificationRegistration(
  4005. (const LPGUID) & TraceErrorGuid,
  4006. FALSE,
  4007. TraceNotificationCallback,
  4008. 0,
  4009. NOTIFICATION_CALLBACK_DIRECT);
  4010. #if _MSC_VER >= 1200
  4011. #pragma warning(pop)
  4012. #endif
  4013. #endif
  4014. if ( NULL != hNewQueryEvent ) {
  4015. CloseHandle ( hNewQueryEvent );
  4016. hNewQueryEvent = NULL;
  4017. }
  4018. }
  4019. DeleteCriticalSection ( &QueryDataLock );
  4020. DeleteCriticalSection ( &ConfigurationLock );
  4021. }
  4022. if (!bInteractive) {
  4023. // Update the service status
  4024. ssSmLogStatus.dwCurrentState = SERVICE_STOPPED;
  4025. SetServiceStatus (hSmLogStatus, &ssSmLogStatus);
  4026. }
  4027. if ( NULL != arrPdhDataCollectSuccess ) {
  4028. G_FREE ( arrPdhDataCollectSuccess );
  4029. arrPdhDataCollectSuccess = NULL;
  4030. iPdhDataCollectSuccessCount = 0;
  4031. }
  4032. if (hEventLog != NULL) {
  4033. DeregisterEventSource ( hEventLog );
  4034. hEventLog = NULL;
  4035. }
  4036. return;
  4037. }
  4038. int
  4039. __cdecl main (
  4040. int argc,
  4041. char *argv[])
  4042. /*++
  4043. main
  4044. Arguments
  4045. ReturnValue
  4046. 0 (ERROR_SUCCESS) if command was processed
  4047. Non-Zero if command error was detected.
  4048. --*/
  4049. {
  4050. DWORD dwStatus = ERROR_SUCCESS;
  4051. BOOL bInteractive = FALSE;
  4052. SERVICE_TABLE_ENTRY DispatchTable[] = {
  4053. {(LPTSTR)TEXT("SysmonLog"), SysmonLogServiceStart },
  4054. {NULL, NULL }
  4055. };
  4056. hEventLog = RegisterEventSource (NULL, (LPCTSTR)TEXT("SysmonLog"));
  4057. #if _DEBUG_OUTPUT
  4058. if ( NULL != hEventLog ) {
  4059. ReportEvent (hEventLog,
  4060. EVENTLOG_INFORMATION_TYPE,
  4061. 0,
  4062. SMLOG_DEBUG_EVENT_SOURCE_REGISTERED,
  4063. NULL,
  4064. 0,
  4065. 0,
  4066. NULL,
  4067. NULL);
  4068. }
  4069. #endif
  4070. hModule = (HINSTANCE) GetModuleHandle(NULL);
  4071. if (argc > 1) {
  4072. if ((argv[1][0] == '-') || (argv[1][0] == '/')) {
  4073. if ((argv[1][1] == 'i') || (argv[1][1] == 'I')) {
  4074. bInteractive = TRUE;
  4075. }
  4076. }
  4077. }
  4078. if (bInteractive) {
  4079. DWORD dwArgs = 1;
  4080. LPTSTR szArgs[1];
  4081. szArgs[0] = (LPTSTR)TEXT("I");
  4082. SysmonLogServiceStart (dwArgs, szArgs);
  4083. } else {
  4084. if (!StartServiceCtrlDispatcher (DispatchTable)) {
  4085. dwStatus = GetLastError();
  4086. // log failure to event log
  4087. ReportEvent (hEventLog,
  4088. EVENTLOG_ERROR_TYPE,
  4089. 0,
  4090. SMLOG_UNABLE_START_DISPATCHER,
  4091. NULL,
  4092. 0,
  4093. sizeof(DWORD),
  4094. NULL,
  4095. (LPVOID)&dwStatus);
  4096. }
  4097. #if _DEBUG_OUTPUT
  4098. else {
  4099. ReportEvent (hEventLog,
  4100. EVENTLOG_INFORMATION_TYPE,
  4101. 0,
  4102. SMLOG_DEBUG_SERVICE_CTRL_DISP_STARTED,
  4103. NULL,
  4104. 0,
  4105. 0,
  4106. NULL,
  4107. NULL);
  4108. }
  4109. #endif
  4110. }
  4111. return dwStatus;
  4112. }