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

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