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

1772 lines
54 KiB

  1. /*++
  2. Copyright (C) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. smlogs.cpp
  5. Abstract:
  6. Implementation of the base class representing the
  7. Performance Logs and Alerts service.
  8. --*/
  9. #include "Stdafx.h"
  10. // Define the following to use the minimum of shlwapip.h
  11. #ifndef NO_SHLWAPI_PATH
  12. #define NO_SHLWAPI_PATH
  13. #endif
  14. #ifndef NO_SHLWAPI_REG
  15. #define NO_SHLWAPI_REG
  16. #endif
  17. #ifndef NO_SHLWAPI_UALSTR
  18. #define NO_SHLWAPI_UALSTR
  19. #endif
  20. #ifndef NO_SHLWAPI_STREAM
  21. #define NO_SHLWAPI_STREAM
  22. #endif
  23. #ifndef NO_SHLWAPI_HTTP
  24. #define NO_SHLWAPI_HTTP
  25. #endif
  26. #ifndef NO_SHLWAPI_INTERNAL
  27. #define NO_SHLWAPI_INTERNAL
  28. #endif
  29. #ifndef NO_SHLWAPI_GDI
  30. #define NO_SHLWAPI_GDI
  31. #endif
  32. #ifndef NO_SHLWAPI_UNITHUNK
  33. #define NO_SHLWAPI_UNITHUNK
  34. #endif
  35. #ifndef NO_SHLWAPI_TPS
  36. #define NO_SHLWAPI_TPS
  37. #endif
  38. #ifndef NO_SHLWAPI_MLUI
  39. #define NO_SHLWAPI_MLUI
  40. #endif
  41. #include <shlwapi.h> // For SHLoadIndirectString
  42. #include <shlwapip.h> // For SHLoadIndirectString
  43. #include <pdh.h> // For MIN_TIME_VALUE, MAX_TIME_VALUE
  44. #include <pdhp.h> // For pdhi methods
  45. #include <wbemidl.h>
  46. #include "smlogres.h"
  47. #include "smcfgmsg.h"
  48. #include "smalrtq.h"
  49. #include "smctrqry.h"
  50. #include "smtraceq.h"
  51. #include "smlogs.h"
  52. #include "strnoloc.h"
  53. USE_HANDLE_MACROS("SMLOGCFG(smlogs.cpp)");
  54. #define DEFAULT_LOG_FILE_FOLDER L"%SystemDrive%\\PerfLogs"
  55. //
  56. // Constructor
  57. CSmLogService::CSmLogService()
  58. : m_hKeyMachine ( NULL ),
  59. m_hKeyLogService ( NULL ),
  60. m_hKeyLogServiceRoot ( NULL ),
  61. m_bIsOpen ( FALSE ),
  62. m_bReadOnly ( FALSE )
  63. {
  64. // String allocation errors are thrown, to be
  65. // captured by rootnode alloc exception handler
  66. m_QueryList.RemoveAll(); // initialize the list
  67. ZeroMemory(&m_OSVersion, sizeof(m_OSVersion));
  68. return;
  69. }
  70. //
  71. // Destructor
  72. CSmLogService::~CSmLogService()
  73. {
  74. // make sure Close method was called first!
  75. ASSERT ( NULL == m_QueryList.GetHeadPosition() );
  76. ASSERT ( NULL == m_hKeyMachine );
  77. ASSERT ( NULL == m_hKeyLogService );
  78. ASSERT ( NULL == m_hKeyLogServiceRoot );
  79. return;
  80. }
  81. PSLQUERY
  82. CSmLogService::CreateTypedQuery (
  83. const CString& rstrName,
  84. DWORD dwLogType )
  85. {
  86. HKEY hKeyQuery;
  87. PSLQUERY pNewLogQuery = NULL;
  88. DWORD dwStatus = ERROR_SUCCESS;
  89. DWORD dwDisposition;
  90. DWORD dwRegValue;
  91. UUID uuidNew;
  92. RPC_STATUS rpcStat = RPC_S_OK;
  93. LPTSTR pszUuid = NULL;
  94. INT iBufLen = rstrName.GetLength()+1;
  95. LPTSTR pszName = NULL;
  96. LPTSTR pStat = NULL;
  97. BOOL bDupFound = FALSE;
  98. CString strNewQueryName;
  99. CString strCollectionName;
  100. if (m_bReadOnly) {
  101. SetLastError (SMCFG_NO_MODIFY_ACCESS);
  102. return NULL; // unable to create without WRITE access
  103. } else {
  104. // Initialize to success status.
  105. SetLastError( dwStatus );
  106. }
  107. if ( !IsWindows2000Server() ) {
  108. // For servers later than Windows2000, use a GUID as the key name for a query.
  109. rpcStat = UuidCreate( &uuidNew );
  110. if ( RPC_S_OK != rpcStat && RPC_S_UUID_LOCAL_ONLY != rpcStat ) {
  111. rpcStat = UuidCreateSequential ( &uuidNew );
  112. }
  113. if ( RPC_S_OK == rpcStat || RPC_S_UUID_LOCAL_ONLY == rpcStat ) {
  114. rpcStat = UuidToString ( &uuidNew, &pszUuid );
  115. if ( RPC_S_OK == rpcStat ) {
  116. ASSERT ( NULL != pszUuid );
  117. MFC_TRY
  118. strNewQueryName.Format ( L"{%s}", pszUuid );
  119. MFC_CATCH_DWSTATUS
  120. RpcStringFree ( &pszUuid );
  121. } else {
  122. dwStatus = rpcStat;
  123. }
  124. }
  125. // RPC_STATUS values in rpcnterr.h correspond to appropriate values.
  126. dwStatus = rpcStat;
  127. } else {
  128. // For Windows 2000, use query name as registry key name.
  129. MFC_TRY
  130. strNewQueryName = rstrName;
  131. MFC_CATCH_DWSTATUS
  132. }
  133. if ( ERROR_SUCCESS == dwStatus ) {
  134. // Query key name created
  135. // Create the query specified, checking for duplicate query by key name.
  136. dwStatus = RegCreateKeyExW (
  137. m_hKeyLogService,
  138. strNewQueryName,
  139. 0,
  140. NULL, 0,
  141. KEY_READ | KEY_WRITE,
  142. NULL,
  143. &hKeyQuery,
  144. &dwDisposition);
  145. if ( REG_OPENED_EXISTING_KEY == dwDisposition ) {
  146. dwStatus = SMCFG_DUP_QUERY_NAME;
  147. }
  148. }
  149. if ( ERROR_SUCCESS == dwStatus ) {
  150. // Initialize the current state value. After it is
  151. // initialized, it is only modified when:
  152. // 1) Set to Stopped or Started by the service
  153. // 2) Set to Start Pending by the config snapin.
  154. dwRegValue = SLQ_QUERY_STOPPED;
  155. dwStatus = RegSetValueEx (
  156. hKeyQuery,
  157. L"Current State",
  158. 0L,
  159. REG_DWORD,
  160. (CONST BYTE *)&dwRegValue,
  161. sizeof(DWORD));
  162. if ( ERROR_SUCCESS == dwStatus ) {
  163. // Initialize the log type to "new" to indicate partially created logs
  164. dwRegValue = SLQ_NEW_LOG;
  165. dwStatus = RegSetValueEx (
  166. hKeyQuery,
  167. L"Log Type",
  168. 0L,
  169. REG_DWORD,
  170. (CONST BYTE *)&dwRegValue,
  171. sizeof(DWORD));
  172. }
  173. if ( ERROR_SUCCESS == dwStatus && !IsWindows2000Server() ) {
  174. // Initialize the collection name for post Windows 2000 systems
  175. MFC_TRY
  176. strCollectionName = rstrName;
  177. MFC_CATCH_DWSTATUS
  178. if ( ERROR_SUCCESS == dwStatus ) {
  179. dwStatus = RegSetValueEx (
  180. hKeyQuery,
  181. L"Collection Name",
  182. 0L,
  183. REG_SZ,
  184. (CONST BYTE *)strCollectionName.GetBufferSetLength( strCollectionName.GetLength() ),
  185. strCollectionName.GetLength()*sizeof(TCHAR) );
  186. strCollectionName.ReleaseBuffer();
  187. }
  188. // For post Windows 2000 counters, search for duplicate by collection name.
  189. if ( ERROR_SUCCESS == dwStatus ) {
  190. dwStatus = FindDuplicateQuery ( rstrName, bDupFound );
  191. }
  192. }
  193. if ( ERROR_SUCCESS == dwStatus && !bDupFound ) {
  194. // create a new object and add it to the query list
  195. dwStatus = LoadSingleQuery (
  196. &pNewLogQuery,
  197. dwLogType,
  198. rstrName,
  199. strNewQueryName,
  200. hKeyQuery,
  201. TRUE );
  202. } else {
  203. if ( bDupFound ) {
  204. dwStatus = SMCFG_DUP_QUERY_NAME;
  205. }
  206. }
  207. }
  208. if ( ERROR_SUCCESS != dwStatus ) {
  209. // Delete also closes the registry key hKeyQuery.
  210. if ( !strNewQueryName.IsEmpty() ) {
  211. RegDeleteKeyW ( m_hKeyLogService, strNewQueryName );
  212. SetLastError ( dwStatus );
  213. }
  214. }
  215. return pNewLogQuery;
  216. }
  217. DWORD
  218. CSmLogService::UnloadSingleQuery (PSLQUERY pQuery)
  219. {
  220. DWORD dwStatus = ERROR_SUCCESS;
  221. PSLQUERY pLogQuery = NULL;
  222. POSITION listPos = NULL;
  223. BOOL bFoundEntry = FALSE;
  224. // find matching entry
  225. if (!m_QueryList.IsEmpty()) {
  226. listPos = m_QueryList.Find (pQuery, NULL);
  227. if ( NULL != listPos ) {
  228. pLogQuery = m_QueryList.GetAt(listPos);
  229. bFoundEntry = TRUE;
  230. }
  231. }
  232. if (bFoundEntry) {
  233. ASSERT ( NULL != listPos );
  234. // remove from list
  235. m_QueryList.RemoveAt (listPos);
  236. pLogQuery->Close();
  237. delete pLogQuery;
  238. } else {
  239. // not found
  240. dwStatus = ERROR_FILE_NOT_FOUND;
  241. }
  242. return dwStatus;
  243. }
  244. DWORD
  245. CSmLogService::DeleteQuery ( PSLQUERY pQuery )
  246. {
  247. PSLQUERY pLogQuery = NULL;
  248. DWORD dwStatus = ERROR_SUCCESS;
  249. POSITION listPos = NULL;
  250. BOOL bFoundEntry = FALSE;
  251. CString strLogKeyName;
  252. if (m_bReadOnly) {
  253. dwStatus = ERROR_ACCESS_DENIED;
  254. } else {
  255. // find matching entry
  256. if (!m_QueryList.IsEmpty()) {
  257. listPos = m_QueryList.Find (pQuery, NULL);
  258. if (listPos != NULL) {
  259. pLogQuery = m_QueryList.GetAt(listPos);
  260. bFoundEntry = TRUE;
  261. }
  262. }
  263. if (bFoundEntry) {
  264. ASSERT (listPos != NULL);
  265. MFC_TRY
  266. pLogQuery->GetLogKeyName( strLogKeyName );
  267. MFC_CATCH_DWSTATUS;
  268. if ( ERROR_SUCCESS == dwStatus ) {
  269. // remove from list
  270. m_QueryList.RemoveAt (listPos);
  271. pLogQuery->Close();
  272. // Delete in the registry
  273. RegDeleteKeyW ( m_hKeyLogService, strLogKeyName );
  274. delete pLogQuery;
  275. }
  276. } else {
  277. // not found
  278. dwStatus = ERROR_FILE_NOT_FOUND;
  279. }
  280. }
  281. return dwStatus;
  282. }
  283. DWORD
  284. CSmLogService::DeleteQuery ( const CString& rstrName )
  285. {
  286. PSLQUERY pLogQuery = NULL;
  287. DWORD dwStatus = ERROR_SUCCESS;
  288. POSITION listPos;
  289. BOOL bFoundEntry = FALSE;
  290. if (m_bReadOnly) {
  291. dwStatus = ERROR_ACCESS_DENIED;
  292. } else {
  293. // find matching entry
  294. if (!m_QueryList.IsEmpty()) {
  295. listPos = m_QueryList.GetHeadPosition();
  296. while (listPos != NULL) {
  297. pLogQuery = m_QueryList.GetNext(listPos);
  298. if ( 0 == rstrName.CompareNoCase ( pLogQuery->GetLogName() ) ) {
  299. // match found so bail here
  300. bFoundEntry = TRUE;
  301. break;
  302. }
  303. }
  304. }
  305. if (bFoundEntry) {
  306. dwStatus = DeleteQuery ( pLogQuery );
  307. } else {
  308. // not found
  309. dwStatus = ERROR_FILE_NOT_FOUND;
  310. }
  311. }
  312. return dwStatus;
  313. }
  314. DWORD
  315. CSmLogService::LoadDefaultLogFileFolder ( void )
  316. {
  317. DWORD dwStatus = ERROR_SUCCESS;
  318. LPWSTR szLocalPath = NULL;
  319. LPWSTR szExpanded = NULL;
  320. INT cchLen;
  321. INT cchExpandedLen;
  322. DWORD dwBufferSize = MAX_PATH + 1;
  323. m_strDefaultLogFileFolder.Empty();
  324. MFC_TRY
  325. szLocalPath = new WCHAR [ dwBufferSize ];
  326. dwBufferSize *= sizeof(WCHAR);
  327. if ( NULL != m_hKeyLogServiceRoot ) {
  328. dwStatus = RegQueryValueExW (
  329. m_hKeyLogServiceRoot,
  330. (LPCTSTR)L"DefaultLogFileFolder",
  331. NULL,
  332. 0L,
  333. (LPBYTE)szLocalPath,
  334. &dwBufferSize);
  335. //
  336. // No message on error. If error, just load the default.
  337. //
  338. if ( sizeof(WCHAR) < dwBufferSize ) {
  339. if ( IsLocalMachine() ) {
  340. cchLen = 0;
  341. cchExpandedLen = 0;
  342. cchLen = ExpandEnvironmentStrings ( szLocalPath, NULL, 0 );
  343. if ( 0 < cchLen ) {
  344. szExpanded = new WCHAR[cchLen];
  345. cchExpandedLen = ExpandEnvironmentStrings (
  346. szLocalPath,
  347. szExpanded,
  348. cchLen );
  349. if ( 0 < cchExpandedLen && MAX_PATH > cchExpandedLen ) {
  350. m_strDefaultLogFileFolder = szExpanded;
  351. } else {
  352. dwStatus = GetLastError();
  353. m_strDefaultLogFileFolder.Empty();
  354. }
  355. } else {
  356. dwStatus = GetLastError();
  357. }
  358. } else {
  359. m_strDefaultLogFileFolder = szLocalPath;
  360. }
  361. }
  362. if ( sizeof(WCHAR) >= dwBufferSize || m_strDefaultLogFileFolder.IsEmpty() ) {
  363. ResourceStateManager rsm;
  364. CString strFolderName;
  365. strFolderName.LoadString ( IDS_DEFAULT_LOG_FILE_FOLDER );
  366. if ( dwBufferSize > (MAX_PATH + 1)*sizeof(WCHAR) ) {
  367. if ( NULL != szLocalPath ) {
  368. delete [] szLocalPath;
  369. szLocalPath = NULL;
  370. }
  371. szLocalPath = new WCHAR [strFolderName.GetLength() + 1];
  372. }
  373. lstrcpy ( szLocalPath, strFolderName );
  374. //
  375. // Exact copy of code for processing the registry setting.
  376. //
  377. if ( IsLocalMachine() ) {
  378. cchLen = 0;
  379. cchExpandedLen = 0;
  380. cchLen = ExpandEnvironmentStrings ( szLocalPath, NULL, 0 );
  381. if ( 0 < cchLen ) {
  382. szExpanded = new WCHAR[cchLen];
  383. cchExpandedLen = ExpandEnvironmentStrings (
  384. szLocalPath,
  385. szExpanded,
  386. cchLen );
  387. if ( 0 < cchExpandedLen && MAX_PATH > cchExpandedLen ) {
  388. m_strDefaultLogFileFolder = szExpanded;
  389. } else {
  390. dwStatus = GetLastError();
  391. m_strDefaultLogFileFolder.Empty();
  392. }
  393. } else {
  394. dwStatus = GetLastError();
  395. }
  396. } else {
  397. m_strDefaultLogFileFolder = szLocalPath;
  398. }
  399. }
  400. }
  401. MFC_CATCH_DWSTATUS
  402. if ( NULL != szLocalPath ) {
  403. delete [] szLocalPath;
  404. }
  405. if ( NULL != szExpanded ) {
  406. delete [] szExpanded;
  407. }
  408. return dwStatus;
  409. }
  410. DWORD
  411. CSmLogService::LoadSingleQuery (
  412. PSLQUERY* ppQuery,
  413. DWORD dwLogType,
  414. const CString& rstrName,
  415. const CString& rstrLogKeyName,
  416. HKEY hKeyQuery,
  417. BOOL bNew )
  418. {
  419. DWORD dwStatus = ERROR_SUCCESS;
  420. PSLQUERY pNewQuery = NULL;
  421. if ( NULL != ppQuery ) {
  422. *ppQuery = NULL;
  423. // create a new query object and add it to the query list
  424. MFC_TRY
  425. if ( SLQ_COUNTER_LOG == dwLogType ) {
  426. pNewQuery = new SLCTRQUERY ( this );
  427. } else if ( SLQ_TRACE_LOG == dwLogType ) {
  428. pNewQuery = new SLTRACEQUERY ( this );
  429. } else if ( SLQ_ALERT == dwLogType ) {
  430. pNewQuery = new SLALERTQUERY ( this );
  431. }
  432. MFC_CATCH_DWSTATUS
  433. if ( ERROR_SUCCESS == dwStatus && NULL != pNewQuery ) {
  434. pNewQuery->SetNew ( bNew );
  435. dwStatus = pNewQuery->Open(
  436. rstrName,
  437. hKeyQuery,
  438. m_bReadOnly );
  439. if ( ERROR_SUCCESS == dwStatus ) {
  440. dwStatus = pNewQuery->SetLogKeyName ( rstrLogKeyName );
  441. }
  442. if ( ERROR_SUCCESS == dwStatus ) {
  443. // then add it to the list
  444. MFC_TRY
  445. m_QueryList.AddHead ( pNewQuery );
  446. MFC_CATCH_DWSTATUS
  447. if ( ERROR_SUCCESS != dwStatus ) {
  448. // close this query object
  449. pNewQuery->Close();
  450. }
  451. }
  452. if ( ERROR_SUCCESS != dwStatus ) {
  453. // delete this query object
  454. delete pNewQuery;
  455. }
  456. }
  457. if ( ERROR_SUCCESS == dwStatus ) {
  458. *ppQuery = pNewQuery;
  459. }
  460. } else {
  461. dwStatus = ERROR_INVALID_PARAMETER;
  462. }
  463. return dwStatus;
  464. }
  465. DWORD
  466. CSmLogService::LoadQueries ( DWORD dwLogType )
  467. {
  468. DWORD dwStatus = ERROR_SUCCESS;
  469. DWORD dwQueryIndex = 0;
  470. LONG lEnumStatus = ERROR_SUCCESS;
  471. WCHAR szQueryKeyName[MAX_PATH + 1];
  472. DWORD dwQueryKeyNameLen;
  473. LPWSTR szCollectionName = NULL;
  474. UINT uiCollectionNameLen = 0;
  475. FILETIME ftLastWritten;
  476. HKEY hKeyQuery;
  477. PSLQUERY pNewLogQuery = NULL;
  478. DWORD dwType = 0;
  479. DWORD dwBufferSize = sizeof(DWORD);
  480. DWORD dwRegValue;
  481. CString strQueryName;
  482. // Load all queries for the specified registry key.
  483. // Enumerate the log names and create a new log object
  484. // for each one found.
  485. dwQueryKeyNameLen = sizeof ( szQueryKeyName ) / sizeof ( WCHAR );
  486. memset (szQueryKeyName, 0, sizeof (szQueryKeyName));
  487. while ( ERROR_SUCCESS == ( lEnumStatus = RegEnumKeyExW (
  488. m_hKeyLogService,
  489. dwQueryIndex,
  490. szQueryKeyName,
  491. &dwQueryKeyNameLen,
  492. NULL,
  493. NULL,
  494. NULL,
  495. &ftLastWritten ) ) ) {
  496. // open the query specified
  497. dwStatus = RegOpenKeyExW (
  498. m_hKeyLogService,
  499. szQueryKeyName,
  500. 0,
  501. (m_bReadOnly ? KEY_READ : KEY_READ | KEY_WRITE),
  502. &hKeyQuery);
  503. if ( ERROR_SUCCESS == dwStatus ) {
  504. // create a new object and add it to the query list
  505. // Determine the log type.
  506. dwType = 0;
  507. dwStatus = RegQueryValueExW (
  508. hKeyQuery,
  509. L"Log Type",
  510. NULL,
  511. &dwType,
  512. (LPBYTE)&dwRegValue,
  513. &dwBufferSize );
  514. if ( ( ERROR_SUCCESS == dwStatus )
  515. && ( dwLogType == dwRegValue ) ) {
  516. dwStatus = SmReadRegistryIndirectStringValue (
  517. hKeyQuery,
  518. L"Collection Name",
  519. NULL,
  520. &szCollectionName,
  521. &uiCollectionNameLen );
  522. MFC_TRY
  523. if ( ERROR_SUCCESS == dwStatus
  524. && NULL != szCollectionName ) {
  525. if ( 0 < lstrlen ( szCollectionName ) ) {
  526. strQueryName = szCollectionName;
  527. } else {
  528. strQueryName = szQueryKeyName;
  529. dwStatus = ERROR_SUCCESS;
  530. }
  531. } else {
  532. strQueryName = szQueryKeyName;
  533. dwStatus = ERROR_SUCCESS;
  534. }
  535. MFC_CATCH_DWSTATUS;
  536. if ( NULL != szCollectionName ) {
  537. G_FREE ( szCollectionName );
  538. szCollectionName = NULL;
  539. uiCollectionNameLen = 0;
  540. }
  541. if ( ERROR_SUCCESS == dwStatus ) {
  542. dwStatus = LoadSingleQuery (
  543. &pNewLogQuery,
  544. dwRegValue,
  545. strQueryName,
  546. szQueryKeyName,
  547. hKeyQuery,
  548. FALSE );
  549. if ( ERROR_SUCCESS != dwStatus ) {
  550. // Todo: Error message
  551. dwStatus = ERROR_SUCCESS;
  552. }
  553. }
  554. } else {
  555. // Try the next item in the list
  556. RegCloseKey (hKeyQuery);
  557. dwStatus = ERROR_SUCCESS;
  558. }
  559. }
  560. // set up for the next item in the list
  561. dwQueryKeyNameLen = sizeof (szQueryKeyName) / sizeof (szQueryKeyName[0]);
  562. memset (szQueryKeyName, 0, sizeof (szQueryKeyName));
  563. dwQueryIndex++;
  564. }
  565. return dwStatus;
  566. }
  567. //
  568. // Open function. Opens all existing log query entries.
  569. //
  570. DWORD
  571. CSmLogService::Open ( const CString& rstrMachineName)
  572. {
  573. DWORD dwStatus = ERROR_SUCCESS;
  574. // Initialize strings
  575. SetMachineName ( rstrMachineName );
  576. SetDisplayName ( m_strBaseName );
  577. if ( rstrMachineName.IsEmpty() ) {
  578. m_hKeyMachine = HKEY_LOCAL_MACHINE;
  579. } else {
  580. dwStatus = RegConnectRegistryW (
  581. rstrMachineName,
  582. HKEY_LOCAL_MACHINE,
  583. &m_hKeyMachine);
  584. }
  585. if (dwStatus == ERROR_SUCCESS) {
  586. // open a read-only key to the registry root key for this service, to obtain
  587. // root-level values.
  588. dwStatus = RegOpenKeyExW (
  589. m_hKeyMachine,
  590. (LPCWSTR)L"SYSTEM\\CurrentControlSet\\Services\\SysmonLog",
  591. 0,
  592. KEY_READ,
  593. &m_hKeyLogServiceRoot);
  594. // No message on failure. Currently only affects default log file folder name.
  595. // open a key to the registry log queries key for this service
  596. dwStatus = RegOpenKeyExW (
  597. m_hKeyMachine,
  598. (LPCWSTR)L"SYSTEM\\CurrentControlSet\\Services\\SysmonLog\\Log Queries",
  599. 0,
  600. KEY_READ | KEY_WRITE,
  601. &m_hKeyLogService);
  602. if (dwStatus != ERROR_SUCCESS) {
  603. // unable to access the key for write access, so try read only
  604. dwStatus = RegOpenKeyExW (
  605. m_hKeyMachine,
  606. (LPCWSTR)L"SYSTEM\\CurrentControlSet\\Services\\SysmonLog\\Log Queries",
  607. 0,
  608. KEY_READ,
  609. &m_hKeyLogService);
  610. if (dwStatus != ERROR_SUCCESS) {
  611. // unable to open the key for read access so bail out
  612. // assume the service has not been installed
  613. // (though we should probably check first to make sure)
  614. m_hKeyLogService = NULL;
  615. if ( ERROR_ACCESS_DENIED == dwStatus ) {
  616. dwStatus = SMCFG_NO_READ_ACCESS;
  617. }
  618. } else {
  619. // opened for read access so set the flag
  620. m_bReadOnly = TRUE;
  621. }
  622. }
  623. }
  624. // Install the service if necessary.
  625. if ( ( dwStatus != SMCFG_NO_READ_ACCESS ) ) {
  626. dwStatus = Install( rstrMachineName );
  627. }
  628. // Load all queries
  629. if ( ( dwStatus == ERROR_SUCCESS ) && ( NULL != m_hKeyLogService ) ) {
  630. dwStatus = LoadQueries();
  631. }
  632. if ( ERROR_SUCCESS == dwStatus ) {
  633. SetOpen ( TRUE );
  634. }
  635. return dwStatus;
  636. }
  637. DWORD
  638. CSmLogService::UnloadQueries ()
  639. {
  640. DWORD dwStatus = ERROR_SUCCESS;
  641. PSLQUERY pQuery = NULL;
  642. POSITION Pos = m_QueryList.GetHeadPosition();
  643. // Ensure that all property dialogs are closed before unloading queries.
  644. while ( Pos != NULL) {
  645. pQuery = m_QueryList.GetNext( Pos );
  646. if ( NULL != pQuery->GetActivePropertySheet() ) {
  647. // Todo: Server Beta 3 - Need specific error code
  648. dwStatus = IDS_ERRMSG_DELETE_OPEN_QUERY;
  649. break;
  650. }
  651. }
  652. if ( ERROR_SUCCESS == dwStatus ) {
  653. Pos = m_QueryList.GetHeadPosition();
  654. // Update each query in this service by walking down the list.
  655. while ( Pos != NULL) {
  656. pQuery = m_QueryList.GetNext( Pos );
  657. pQuery->Close();
  658. delete (pQuery);
  659. }
  660. // Empty the list now that everything has been closed;
  661. m_QueryList.RemoveAll();
  662. }
  663. return dwStatus;
  664. }
  665. //
  666. // Close Function
  667. // closes registry handles and frees allocated memory
  668. //
  669. DWORD
  670. CSmLogService::Close ()
  671. {
  672. LOCALTRACE (L"Closing SysmonLog Service Object\n");
  673. UnloadQueries();
  674. // close any open registry keys
  675. if (m_hKeyMachine != NULL) {
  676. RegCloseKey (m_hKeyMachine);
  677. m_hKeyMachine = NULL;
  678. }
  679. if (m_hKeyLogService != NULL) {
  680. RegCloseKey (m_hKeyLogService);
  681. m_hKeyLogService = NULL;
  682. }
  683. if (m_hKeyLogServiceRoot!= NULL) {
  684. RegCloseKey (m_hKeyLogServiceRoot);
  685. m_hKeyLogServiceRoot = NULL;
  686. }
  687. SetOpen ( FALSE );
  688. return ERROR_SUCCESS;
  689. }
  690. DWORD
  691. CSmLogService::UpdateConfig()
  692. {
  693. // If any queries are (newly) set to auto start, then set the
  694. // service to auto start. Otherwise, set to manual start.
  695. // When setting to auto start, also set failure mode to restart
  696. DWORD dwStatus = ERROR_SUCCESS;
  697. BOOL bStatus = 0;
  698. POSITION listPos;
  699. PSLQUERY pLogQuery = NULL;
  700. SC_HANDLE hSC = NULL;
  701. SC_HANDLE hService = NULL;
  702. BOOL bAutoStart = FALSE;
  703. DWORD pqsConfigBuff[128];
  704. QUERY_SERVICE_CONFIG* pqsConfig;
  705. SC_ACTION* parrSingleFailAction = NULL;
  706. SERVICE_FAILURE_ACTIONS structFailActions;
  707. DWORD dwMoreBytes = 0;
  708. BOOL bUpdate = FALSE;
  709. // check for duplicate entry
  710. if (!m_QueryList.IsEmpty()) {
  711. listPos = m_QueryList.GetHeadPosition();
  712. while (listPos != NULL) {
  713. pLogQuery = m_QueryList.GetNext(listPos);
  714. if ( pLogQuery->IsAutoStart() ) {
  715. bAutoStart = TRUE;
  716. break;
  717. }
  718. }
  719. }
  720. // open SC database
  721. hSC = OpenSCManager ( GetMachineName(), NULL, GENERIC_READ );
  722. if (hSC != NULL) {
  723. // open service
  724. hService = OpenService (
  725. hSC,
  726. TEXT("SysmonLog"),
  727. SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG | SERVICE_START );
  728. if (hService != NULL) {
  729. // get current config
  730. memset (pqsConfigBuff, 0, sizeof(pqsConfigBuff));
  731. pqsConfig = (QUERY_SERVICE_CONFIG*)pqsConfigBuff;
  732. if ( QueryServiceConfig (
  733. hService,
  734. pqsConfig,
  735. sizeof(pqsConfigBuff),
  736. &dwMoreBytes)) {
  737. // See if the current status is different
  738. // from the selection. If it is, then change
  739. // the current mode.
  740. if ( bAutoStart ) {
  741. if ( SERVICE_DEMAND_START == pqsConfig->dwStartType ) {
  742. bUpdate = TRUE;
  743. }
  744. } else {
  745. // Manual start selected
  746. if ( SERVICE_AUTO_START == pqsConfig->dwStartType ) {
  747. bUpdate = TRUE;
  748. }
  749. }
  750. } else {
  751. // else unable to read the current status so update anyway
  752. bUpdate = TRUE;
  753. }
  754. if ( bUpdate ) {
  755. MFC_TRY
  756. parrSingleFailAction = new SC_ACTION[3];
  757. MFC_CATCH_DWSTATUS;
  758. if ( NULL != parrSingleFailAction ) {
  759. parrSingleFailAction[0].Delay = eRestartDelayMilliseconds;
  760. parrSingleFailAction[1].Delay = eRestartDelayMilliseconds;
  761. parrSingleFailAction[2].Delay = eRestartDelayMilliseconds;
  762. if ( bAutoStart ) {
  763. parrSingleFailAction[0].Type = SC_ACTION_RESTART;
  764. parrSingleFailAction[1].Type = SC_ACTION_RESTART;
  765. parrSingleFailAction[2].Type = SC_ACTION_RESTART;
  766. } else {
  767. parrSingleFailAction[0].Type = SC_ACTION_NONE;
  768. parrSingleFailAction[1].Type = SC_ACTION_NONE;
  769. parrSingleFailAction[2].Type = SC_ACTION_NONE;
  770. }
  771. structFailActions.dwResetPeriod = eResetDelaySeconds;
  772. structFailActions.lpRebootMsg = NULL;
  773. structFailActions.lpCommand = NULL;
  774. structFailActions.cActions = 3;
  775. structFailActions.lpsaActions = parrSingleFailAction;
  776. bStatus = ChangeServiceConfig (
  777. hService,
  778. SERVICE_NO_CHANGE,
  779. (bAutoStart ? SERVICE_AUTO_START : SERVICE_DEMAND_START),
  780. SERVICE_NO_CHANGE,
  781. NULL,
  782. NULL,
  783. NULL,
  784. NULL,
  785. NULL,
  786. NULL,
  787. NULL );
  788. if ( 0 == bStatus ) {
  789. dwStatus = GetLastError();
  790. } else {
  791. bStatus = ChangeServiceConfig2 (
  792. hService,
  793. SERVICE_CONFIG_FAILURE_ACTIONS,
  794. &structFailActions );
  795. if ( 0 == bStatus ) {
  796. dwStatus = GetLastError();
  797. }
  798. }
  799. delete parrSingleFailAction;
  800. } else {
  801. dwStatus = ERROR_OUTOFMEMORY;
  802. }
  803. }
  804. CloseServiceHandle (hService);
  805. } else {
  806. dwStatus = GetLastError();
  807. ASSERT (dwStatus != 0);
  808. }
  809. CloseServiceHandle (hSC);
  810. } else {
  811. dwStatus = GetLastError();
  812. } // OpenSCManager
  813. return dwStatus;
  814. }
  815. //
  816. // SyncWithRegistry()
  817. // reads the current values for all queries from the registry
  818. // and reloads the internal values to match
  819. //
  820. DWORD CSmLogService::SyncWithRegistry ( void )
  821. {
  822. DWORD dwStatus = ERROR_SUCCESS;
  823. CString strDesc;
  824. ResourceStateManager rsm;
  825. // Unload queries and reload, to capture new queries.
  826. // This is necessary for monitoring remote systems,
  827. // and if multiple users are active on the same system.
  828. dwStatus = UnloadQueries ();
  829. if ( ERROR_SUCCESS == dwStatus ) {
  830. dwStatus = LoadQueries ();
  831. }
  832. return dwStatus;
  833. }
  834. DWORD
  835. CSmLogService::GetState( void )
  836. {
  837. // Check the status of the log service via the service controller.
  838. // 0 returned in case of error.
  839. LONG dwStatus = ERROR_SUCCESS;
  840. DWORD dwState = 0; // Error by default.
  841. SERVICE_STATUS ssData;
  842. SC_HANDLE hSC;
  843. SC_HANDLE hLogService;
  844. // open SC database
  845. hSC = OpenSCManager ( GetMachineName(), NULL, SC_MANAGER_CONNECT);
  846. if (hSC != NULL) {
  847. // open service
  848. hLogService = OpenService (
  849. hSC,
  850. TEXT("SysmonLog"),
  851. SERVICE_INTERROGATE );
  852. if (hLogService != NULL) {
  853. if ( ControlService (
  854. hLogService,
  855. SERVICE_CONTROL_INTERROGATE,
  856. &ssData)) {
  857. dwState = ssData.dwCurrentState;
  858. } else {
  859. dwStatus = GetLastError();
  860. dwState = SERVICE_STOPPED;
  861. }
  862. CloseServiceHandle (hLogService);
  863. } else {
  864. dwStatus = GetLastError();
  865. }
  866. CloseServiceHandle (hSC);
  867. } else {
  868. dwStatus = GetLastError();
  869. } // OpenSCManager
  870. return dwState;
  871. }
  872. BOOL
  873. CSmLogService::IsRunning( void )
  874. {
  875. DWORD dwState = GetState();
  876. BOOL bRunning = FALSE;
  877. if ( 0 != dwState
  878. && SERVICE_STOPPED != dwState
  879. && SERVICE_STOP_PENDING != dwState ) {
  880. bRunning = TRUE;
  881. }
  882. return bRunning;
  883. }
  884. DWORD
  885. CSmLogService::CreateDefaultLogQueries( void )
  886. {
  887. DWORD dwStatus = ERROR_SUCCESS;
  888. PSLQUERY pQuery = NULL;
  889. CString strTemp;
  890. CString strModuleName;
  891. BOOL bRegistryUpdated;
  892. BOOL bDupFound = FALSE;
  893. ResourceStateManager rsm;
  894. // Creates default "System Overview" counter log query
  895. MFC_TRY
  896. strTemp.LoadString ( IDS_DEFAULT_CTRLOG_QUERY_NAME );
  897. MFC_CATCH_DWSTATUS;
  898. if ( ERROR_SUCCESS == dwStatus ) {
  899. pQuery = CreateTypedQuery ( strTemp, SLQ_COUNTER_LOG );
  900. if ( NULL != pQuery && !IsWindows2000Server() ) {
  901. // Default query collection name is stored as MUI indirect string after Windows 2000
  902. MFC_TRY
  903. ::GetModuleFileName(
  904. AfxGetInstanceHandle(),
  905. strModuleName.GetBufferSetLength(MAX_PATH),
  906. MAX_PATH );
  907. strTemp.Format (_T("@%s,-%d"), strModuleName, IDS_DEFAULT_CTRLOG_QUERY_NAME );
  908. strModuleName.ReleaseBuffer();
  909. MFC_CATCH_DWSTATUS;
  910. if ( ERROR_SUCCESS == dwStatus ) {
  911. dwStatus = RegSetValueEx (
  912. pQuery->GetQueryKey(),
  913. L"Collection Name Indirect",
  914. 0L,
  915. REG_SZ,
  916. (CONST BYTE *)strTemp.GetBufferSetLength( strTemp.GetLength() ),
  917. strTemp.GetLength()*sizeof(WCHAR) );
  918. strTemp.ReleaseBuffer();
  919. }
  920. // CreateTypedQuery checks for the existence of the default query
  921. // using the the query name.
  922. // Check for the existence of the default query under the MUI indirect
  923. // name as well.
  924. if ( NULL != pQuery ) {
  925. if ( ERROR_SUCCESS == dwStatus ) {
  926. FindDuplicateQuery ( strTemp, bDupFound );
  927. if ( bDupFound ) {
  928. DeleteQuery ( pQuery );
  929. pQuery = NULL;
  930. dwStatus = ERROR_SUCCESS;
  931. }
  932. }
  933. }
  934. }
  935. if ( NULL != pQuery ) {
  936. SLQ_TIME_INFO slqTime;
  937. PSLCTRQUERY pCtrQuery = NULL;
  938. MFC_TRY
  939. pCtrQuery = pQuery->CastToCounterLogQuery();
  940. pCtrQuery->SetFileNameAutoFormat ( SLF_NAME_NONE );
  941. pCtrQuery->SetLogFileType ( SLF_BIN_FILE );
  942. pCtrQuery->SetDataStoreAppendMode ( SLF_DATA_STORE_OVERWRITE );
  943. strTemp.LoadString ( IDS_DEFAULT_CTRLOG_COMMENT );
  944. pCtrQuery->SetLogComment ( strTemp );
  945. if ( !IsWindows2000Server() ) {
  946. strTemp.Format (_T("@%s,-%d"), strModuleName, IDS_DEFAULT_CTRLOG_COMMENT );
  947. pCtrQuery->SetLogCommentIndirect ( strTemp );
  948. }
  949. strTemp.LoadString ( IDS_DEFAULT_CTRLOG_FILE_NAME );
  950. pCtrQuery->SetLogFileName ( strTemp );
  951. if ( !IsWindows2000Server() ) {
  952. strTemp.Format (_T("@%s,-%d"), strModuleName, IDS_DEFAULT_CTRLOG_FILE_NAME );
  953. pCtrQuery->SetLogFileNameIndirect ( strTemp );
  954. }
  955. pCtrQuery->AddCounter ( CGlobalString::m_cszDefaultCtrLogCpuPath );
  956. pCtrQuery->AddCounter ( CGlobalString::m_cszDefaultCtrLogMemoryPath );
  957. pCtrQuery->AddCounter ( CGlobalString::m_cszDefaultCtrLogDiskPath );
  958. // Start mode and time
  959. memset (&slqTime, 0, sizeof(slqTime));
  960. slqTime.wTimeType = SLQ_TT_TTYPE_START;
  961. slqTime.wDataType = SLQ_TT_DTYPE_DATETIME;
  962. slqTime.dwAutoMode = SLQ_AUTO_MODE_NONE;
  963. slqTime.llDateTime = MAX_TIME_VALUE;
  964. pCtrQuery->SetLogTime (&slqTime, (DWORD)slqTime.wTimeType);
  965. // Stop mode and time
  966. slqTime.wTimeType = SLQ_TT_TTYPE_STOP;
  967. slqTime.llDateTime = MIN_TIME_VALUE;
  968. pCtrQuery->SetLogTime (&slqTime, (DWORD)slqTime.wTimeType);
  969. pCtrQuery->UpdateService( bRegistryUpdated );
  970. // Set the default log to Execute Only.
  971. dwStatus = pCtrQuery->UpdateExecuteOnly ();
  972. MFC_CATCH_DWSTATUS
  973. if ( ERROR_SUCCESS == dwStatus && NULL != pCtrQuery ) {
  974. VERIFY ( ERROR_SUCCESS == UnloadSingleQuery ( pCtrQuery ) );
  975. } else if ( NULL != pCtrQuery ) {
  976. DeleteQuery ( pCtrQuery );
  977. }
  978. } else {
  979. dwStatus = GetLastError();
  980. if ( SMCFG_DUP_QUERY_NAME == dwStatus ) {
  981. dwStatus = ERROR_SUCCESS;
  982. }
  983. }
  984. }
  985. return dwStatus;
  986. }
  987. DWORD
  988. CSmLogService::Install (
  989. const CString& rstrMachineName )
  990. {
  991. DWORD dwStatus = ERROR_SUCCESS;
  992. DWORD dwDisposition = 0;
  993. HKEY hKeyPerfLog = NULL;
  994. CString strValueName;
  995. DWORD dwType;
  996. DWORD dwRegValue;
  997. DWORD dwBufferSize;
  998. BOOL bReadOnlyPerfLogKey = FALSE;
  999. BOOL bReadOnlyLogQueriesKey = FALSE;
  1000. ResourceStateManager rsm;
  1001. //
  1002. // Get machine OS version
  1003. //
  1004. PdhiPlaGetVersion( rstrMachineName, &m_OSVersion );
  1005. if ( NULL == m_hKeyMachine ) {
  1006. if ( rstrMachineName.IsEmpty() ) {
  1007. m_hKeyMachine = HKEY_LOCAL_MACHINE;
  1008. } else {
  1009. dwStatus = RegConnectRegistryW (
  1010. rstrMachineName,
  1011. HKEY_LOCAL_MACHINE,
  1012. &m_hKeyMachine);
  1013. }
  1014. }
  1015. if ( ERROR_SUCCESS == dwStatus ) {
  1016. dwStatus = RegOpenKeyEx (
  1017. m_hKeyMachine,
  1018. TEXT("System\\CurrentControlSet\\Services\\SysmonLog"),
  1019. 0,
  1020. KEY_READ | KEY_WRITE,
  1021. &hKeyPerfLog);
  1022. if (dwStatus != ERROR_SUCCESS) {
  1023. // unable to access the key for write access, so try read only
  1024. dwStatus = RegOpenKeyEx (
  1025. m_hKeyMachine,
  1026. TEXT("System\\CurrentControlSet\\Services\\SysmonLog"),
  1027. 0,
  1028. KEY_READ,
  1029. &hKeyPerfLog);
  1030. if ( ERROR_SUCCESS == dwStatus ) {
  1031. bReadOnlyPerfLogKey = TRUE;
  1032. }
  1033. }
  1034. }
  1035. EnterCriticalSection ( &g_critsectInstallDefaultQueries );
  1036. // In Windows 2000, the Log Queries key is created by the snapin.
  1037. // After Windows 2000, the Log Queries key is created by system setup,
  1038. // along with a "Default Installed" registry flag.
  1039. if ( ERROR_SUCCESS == dwStatus && NULL == m_hKeyLogService ) {
  1040. if ( !bReadOnlyPerfLogKey ) {
  1041. // add registry subkey for Log Queries
  1042. dwStatus = RegCreateKeyEx (
  1043. hKeyPerfLog,
  1044. TEXT("Log Queries"),
  1045. 0,
  1046. NULL,
  1047. REG_OPTION_NON_VOLATILE,
  1048. KEY_READ | KEY_WRITE,
  1049. NULL,
  1050. &m_hKeyLogService,
  1051. &dwDisposition);
  1052. } else {
  1053. // ReadOnly SysmonLog key. Still possible to succeed if Log Queries
  1054. // exists with read/write access.
  1055. dwStatus = RegOpenKeyEx (
  1056. m_hKeyMachine,
  1057. TEXT("System\\CurrentControlSet\\Services\\SysmonLog\\Log Queries"),
  1058. 0,
  1059. KEY_READ | KEY_WRITE,
  1060. &m_hKeyLogService);
  1061. if (dwStatus == ERROR_SUCCESS) {
  1062. bReadOnlyLogQueriesKey = FALSE;
  1063. } else {
  1064. // unable to access the key for write access, so try read only
  1065. dwStatus = RegOpenKeyExW (
  1066. m_hKeyMachine,
  1067. (LPCWSTR)L"SYSTEM\\CurrentControlSet\\Services\\SysmonLog\\Log Queries",
  1068. 0,
  1069. KEY_READ,
  1070. &m_hKeyLogService);
  1071. if ( ERROR_SUCCESS == dwStatus ) {
  1072. bReadOnlyLogQueriesKey = TRUE;
  1073. }
  1074. }
  1075. }
  1076. } else if ( m_bReadOnly ) {
  1077. bReadOnlyLogQueriesKey = TRUE;
  1078. }
  1079. if ( ERROR_SUCCESS == dwStatus ) {
  1080. // Log queries key now exists.
  1081. strValueName = CGlobalString::m_cszDefaultsInstalled;
  1082. dwType = REG_DWORD;
  1083. dwRegValue = 0;
  1084. dwBufferSize = sizeof(DWORD);
  1085. dwStatus = RegQueryValueExW (
  1086. m_hKeyLogService,
  1087. strValueName,
  1088. NULL,
  1089. &dwType,
  1090. (LPBYTE)&dwRegValue,
  1091. &dwBufferSize );
  1092. if ( ERROR_SUCCESS != dwStatus
  1093. || 0 == dwRegValue )
  1094. {
  1095. if ( !bReadOnlyLogQueriesKey ) {
  1096. // Create default counter log query.
  1097. // Todo: Message on error.
  1098. dwStatus = CreateDefaultLogQueries();
  1099. if ( ERROR_SUCCESS == dwStatus ) {
  1100. dwRegValue = SLQ_DEFAULT_SYS_QUERY;
  1101. dwStatus = RegSetValueEx (
  1102. m_hKeyLogService,
  1103. strValueName,
  1104. 0L,
  1105. REG_DWORD,
  1106. (CONST BYTE *)&dwRegValue,
  1107. dwBufferSize);
  1108. }
  1109. } else {
  1110. dwStatus = SMCFG_NO_INSTALL_ACCESS;
  1111. }
  1112. }
  1113. }
  1114. if ( ERROR_SUCCESS == dwStatus ) {
  1115. RegFlushKey ( m_hKeyLogService );
  1116. // Ignore status.
  1117. }
  1118. LeaveCriticalSection ( &g_critsectInstallDefaultQueries );
  1119. if (NULL != hKeyPerfLog ) {
  1120. RegCloseKey (hKeyPerfLog);
  1121. }
  1122. if ( ERROR_ACCESS_DENIED == dwStatus ) {
  1123. dwStatus = SMCFG_NO_INSTALL_ACCESS;
  1124. }
  1125. return dwStatus;
  1126. }
  1127. DWORD
  1128. CSmLogService::Synchronize( void )
  1129. {
  1130. // If the service is running, tell it to synchronize itself,
  1131. // Check the state afterwards to see if it got the message.
  1132. // If stop pending or stopped, wait until the service is
  1133. // stopped and then attempt to start it. The service
  1134. // synchronizes itself from the registry when it is started.
  1135. // Return 0 for success, other for failure.
  1136. SC_HANDLE hSC = NULL;
  1137. SC_HANDLE hService = NULL;
  1138. SERVICE_STATUS ssData;
  1139. DWORD dwCurrentState;
  1140. DWORD dwTimeout = 50;
  1141. LONG dwStatus = ERROR_SUCCESS;
  1142. BOOL bServiceStarted = FALSE;
  1143. dwCurrentState = GetState();
  1144. if ( 0 == dwCurrentState ) {
  1145. dwStatus = 1;
  1146. } else {
  1147. // open SC database
  1148. hSC = OpenSCManager ( GetMachineName(), NULL, GENERIC_READ);
  1149. if ( NULL != hSC ) {
  1150. // open service
  1151. hService = OpenService (
  1152. hSC,
  1153. TEXT("SysmonLog"),
  1154. SERVICE_USER_DEFINED_CONTROL
  1155. | SERVICE_START );
  1156. if ( NULL != hService ) {
  1157. if ( ( SERVICE_STOPPED != dwCurrentState )
  1158. && ( SERVICE_STOP_PENDING != dwCurrentState ) ) {
  1159. // Wait 100 milliseconds before synchronizing service,
  1160. // to ensure that registry values are written.
  1161. Sleep ( 100 );
  1162. ControlService (
  1163. hService,
  1164. SERVICE_CONTROL_SYNCHRONIZE,
  1165. &ssData);
  1166. dwCurrentState = ssData.dwCurrentState;
  1167. }
  1168. // Make sure that the ControlService call reached the service
  1169. // while it was in run state.
  1170. if ( ( SERVICE_STOPPED == dwCurrentState )
  1171. || ( SERVICE_STOP_PENDING == dwCurrentState ) ) {
  1172. if ( SERVICE_STOP_PENDING == dwCurrentState ) {
  1173. // wait for the service to stop before starting it.
  1174. while (--dwTimeout) {
  1175. dwCurrentState = GetState();
  1176. if ( SERVICE_STOP_PENDING == dwCurrentState ) {
  1177. Sleep(200);
  1178. } else {
  1179. break;
  1180. }
  1181. }
  1182. }
  1183. dwTimeout = 50;
  1184. if ( SERVICE_STOPPED == dwCurrentState ) {
  1185. bServiceStarted = StartService (hService, 0, NULL);
  1186. if ( !bServiceStarted ) {
  1187. dwStatus = GetLastError();
  1188. if ( ERROR_SERVICE_ALREADY_RUNNING == dwStatus ) {
  1189. // Okay if started during the time window since
  1190. // the last GetState() call.
  1191. dwStatus = ERROR_SUCCESS;
  1192. bServiceStarted = TRUE;
  1193. } // else error
  1194. }
  1195. if ( bServiceStarted ) {
  1196. // wait for the service to start or stop
  1197. // before returning
  1198. while (--dwTimeout) {
  1199. dwCurrentState = GetState();
  1200. if ( SERVICE_START_PENDING == dwCurrentState ) {
  1201. Sleep(200);
  1202. } else {
  1203. break;
  1204. }
  1205. }
  1206. }
  1207. }
  1208. }
  1209. CloseServiceHandle (hService);
  1210. } else {
  1211. dwStatus = GetLastError();
  1212. }
  1213. CloseServiceHandle (hSC);
  1214. } else {
  1215. dwStatus = GetLastError();
  1216. }
  1217. }
  1218. // Update the Auto Start service config.
  1219. if ( ERROR_SUCCESS == dwStatus ) {
  1220. // Ignore errors
  1221. UpdateConfig();
  1222. }
  1223. return dwStatus;
  1224. }
  1225. void
  1226. CSmLogService::SetBaseName( const CString& rstrName )
  1227. {
  1228. // This method is only called within the service constructor,
  1229. // so throw any errors
  1230. m_strBaseName = rstrName;
  1231. return;
  1232. }
  1233. const CString&
  1234. CSmLogService::GetDefaultLogFileFolder()
  1235. {
  1236. if ( m_strDefaultLogFileFolder.IsEmpty() ) {
  1237. LoadDefaultLogFileFolder();
  1238. }
  1239. return m_strDefaultLogFileFolder;
  1240. }
  1241. INT
  1242. CSmLogService::GetQueryCount()
  1243. {
  1244. INT iQueryCount = -1;
  1245. // The query count is only valid if the service is open.
  1246. if ( IsOpen() ) {
  1247. iQueryCount = (int) m_QueryList.GetCount();
  1248. } else {
  1249. ASSERT ( FALSE );
  1250. }
  1251. return iQueryCount;
  1252. }
  1253. DWORD
  1254. CSmLogService::FindDuplicateQuery (
  1255. const CString cstrName,
  1256. BOOL& rbFound )
  1257. {
  1258. DWORD dwStatus = ERROR_SUCCESS;
  1259. HRESULT hrLocal = NOERROR;
  1260. DWORD dwQueryIndex = 0;
  1261. LONG lEnumStatus = ERROR_SUCCESS;
  1262. WCHAR szQueryKeyName[MAX_PATH + 1];
  1263. DWORD dwQueryKeyNameLen;
  1264. LPTSTR szCollectionName = NULL;
  1265. UINT uiCollectionNameLen = 0;
  1266. FILETIME ftLastWritten;
  1267. HKEY hKeyQuery = NULL;
  1268. BOOL bFoundFirst = FALSE;
  1269. CString strDirectName;
  1270. CString strLocalName;
  1271. ASSERT ( !cstrName.IsEmpty() );
  1272. rbFound = FALSE;
  1273. if ( !cstrName.IsEmpty() ) {
  1274. MFC_TRY
  1275. strLocalName = cstrName;
  1276. MFC_CATCH_DWSTATUS;
  1277. if ( ERROR_SUCCESS == dwStatus ) {
  1278. // Translate new query name if necessary
  1279. hrLocal = SHLoadIndirectString(
  1280. strLocalName.GetBufferSetLength ( strLocalName.GetLength() ),
  1281. strDirectName.GetBufferSetLength ( MAX_PATH ),
  1282. MAX_PATH,
  1283. NULL );
  1284. strLocalName.ReleaseBuffer();
  1285. strDirectName.ReleaseBuffer();
  1286. if ( FAILED ( hrLocal ) ) {
  1287. // Query name is not an indirect string
  1288. dwStatus = ERROR_SUCCESS;
  1289. MFC_TRY
  1290. strDirectName = strLocalName;
  1291. MFC_CATCH_DWSTATUS;
  1292. }
  1293. }
  1294. }
  1295. if ( ERROR_SUCCESS == dwStatus ) {
  1296. // Search all queries for the specified query.
  1297. dwQueryKeyNameLen = sizeof ( szQueryKeyName ) / sizeof ( WCHAR );
  1298. memset (szQueryKeyName, 0, sizeof (szQueryKeyName));
  1299. while ( ERROR_SUCCESS == ( lEnumStatus = RegEnumKeyExW (
  1300. m_hKeyLogService,
  1301. dwQueryIndex,
  1302. szQueryKeyName,
  1303. &dwQueryKeyNameLen,
  1304. NULL,
  1305. NULL,
  1306. NULL,
  1307. &ftLastWritten ) ) ) {
  1308. // open the query specified
  1309. dwStatus = RegOpenKeyExW (
  1310. m_hKeyLogService,
  1311. szQueryKeyName,
  1312. 0,
  1313. KEY_READ,
  1314. &hKeyQuery);
  1315. if ( ERROR_SUCCESS == dwStatus ) {
  1316. // Query key is Guid if written by post Win2000 snapin.
  1317. // Query key is name if written by Win2000 snapin.
  1318. if ( 0 == strDirectName.CompareNoCase ( szQueryKeyName ) ) {
  1319. if ( TRUE == bFoundFirst ) {
  1320. rbFound = TRUE;
  1321. break;
  1322. } else {
  1323. bFoundFirst = TRUE;
  1324. }
  1325. } else {
  1326. dwStatus = SmReadRegistryIndirectStringValue (
  1327. hKeyQuery,
  1328. L"Collection Name",
  1329. NULL,
  1330. &szCollectionName,
  1331. &uiCollectionNameLen );
  1332. ASSERT ( MAX_PATH >= uiCollectionNameLen );
  1333. if ( ERROR_SUCCESS == dwStatus ) {
  1334. if ( MAX_PATH >= uiCollectionNameLen ) {
  1335. if ( NULL != szCollectionName ) {
  1336. if ( L'\0' == *szCollectionName ) {
  1337. G_FREE ( szCollectionName );
  1338. szCollectionName = NULL;
  1339. }
  1340. }
  1341. if ( NULL == szCollectionName ) {
  1342. MFC_TRY
  1343. szCollectionName = (LPWSTR)G_ALLOC ( (lstrlen(szQueryKeyName)+1)*sizeof(WCHAR));
  1344. MFC_CATCH_DWSTATUS;
  1345. if ( ERROR_SUCCESS == dwStatus ) {
  1346. lstrcpyn ( szCollectionName, szQueryKeyName, lstrlen(szQueryKeyName)+1 );
  1347. }
  1348. }
  1349. if ( NULL != szCollectionName ) {
  1350. // Compare found name to input name.
  1351. if ( 0 == strDirectName.CompareNoCase ( szCollectionName ) ) {
  1352. if ( TRUE == bFoundFirst ) {
  1353. rbFound = TRUE;
  1354. break;
  1355. } else {
  1356. bFoundFirst = TRUE;
  1357. }
  1358. }
  1359. } // Todo: else report message?
  1360. }
  1361. } // Todo: else report message?
  1362. } // Todo: else report message?
  1363. }
  1364. // set up for the next item in the list
  1365. dwQueryKeyNameLen = sizeof (szQueryKeyName) / sizeof (szQueryKeyName[0]);
  1366. memset (szQueryKeyName, 0, sizeof (szQueryKeyName));
  1367. if ( NULL != hKeyQuery ) {
  1368. RegCloseKey( hKeyQuery );
  1369. hKeyQuery = NULL;
  1370. }
  1371. if ( NULL != szCollectionName ) {
  1372. G_FREE ( szCollectionName );
  1373. szCollectionName = NULL;
  1374. uiCollectionNameLen = 0;
  1375. }
  1376. dwQueryIndex++;
  1377. }
  1378. } else {
  1379. dwStatus = ERROR_INVALID_PARAMETER;
  1380. }
  1381. if ( NULL != szCollectionName ) {
  1382. G_FREE ( szCollectionName );
  1383. szCollectionName = NULL;
  1384. uiCollectionNameLen = 0;
  1385. }
  1386. if ( NULL != hKeyQuery ) {
  1387. RegCloseKey( hKeyQuery );
  1388. hKeyQuery = NULL;
  1389. }
  1390. return dwStatus;
  1391. }
  1392. BOOL
  1393. CSmLogService::IsWindows2000Server ( void )
  1394. {
  1395. if ( 5 == m_OSVersion.dwMajorVersion && 2195 == m_OSVersion.dwBuild ) {
  1396. return TRUE;
  1397. }
  1398. return FALSE;
  1399. }
  1400. BOOL
  1401. CSmLogService::CanAccessWbemRemote()
  1402. {
  1403. HRESULT hr;
  1404. IWbemLocator *pLocator = NULL;
  1405. IWbemServices* pWbemServices = NULL;
  1406. LPCWSTR szRoot[2] = { L"root\\perfmon",
  1407. L"root\\wmi"
  1408. };
  1409. LPCWSTR szMask = L"\\\\%s\\%s";
  1410. BSTR bszClass = SysAllocString(L"SysmonLog");
  1411. BSTR bszNamespace = NULL;
  1412. LPWSTR buffer = NULL;
  1413. DWORD dwBufLen;
  1414. hr = CoCreateInstance(
  1415. CLSID_WbemLocator,
  1416. 0,
  1417. CLSCTX_INPROC_SERVER,
  1418. IID_IWbemLocator,
  1419. (LPVOID*)&pLocator );
  1420. if (!SUCCEEDED(hr)) {
  1421. goto Cleanup;
  1422. }
  1423. if ( !GetMachineName().IsEmpty()) {
  1424. dwBufLen = max(wcslen(szRoot[0]), wcslen(szRoot[1])) +
  1425. GetMachineName().GetLength() +
  1426. wcslen( szMask );
  1427. buffer = new WCHAR[dwBufLen];
  1428. if ( buffer == NULL ){
  1429. hr = ERROR_OUTOFMEMORY;
  1430. goto Cleanup;
  1431. }
  1432. }
  1433. for (int i = 0; i < 2; i++) {
  1434. if (bszNamespace) {
  1435. SysFreeString(bszNamespace);
  1436. bszNamespace = NULL;
  1437. }
  1438. if (buffer) {
  1439. swprintf( buffer, szMask, GetMachineName(), szRoot[i] );
  1440. bszNamespace = SysAllocString( buffer );
  1441. }
  1442. else {
  1443. bszNamespace = SysAllocString(szRoot[i]);
  1444. }
  1445. hr = pLocator->ConnectServer(
  1446. bszNamespace,
  1447. NULL,
  1448. NULL,
  1449. NULL,
  1450. 0,
  1451. NULL,
  1452. NULL,
  1453. &pWbemServices);
  1454. if (SUCCEEDED(hr)) {
  1455. break;
  1456. }
  1457. }
  1458. Cleanup:
  1459. if (buffer) {
  1460. delete [] buffer;
  1461. }
  1462. if (bszNamespace) {
  1463. SysFreeString(bszNamespace);
  1464. }
  1465. if (pLocator) {
  1466. pLocator->Release();
  1467. }
  1468. if (pWbemServices) {
  1469. pWbemServices->Release();
  1470. }
  1471. m_hWbemAccessStatus = hr;
  1472. if (SUCCEEDED(hr)) {
  1473. return TRUE;
  1474. }
  1475. else {
  1476. return FALSE;
  1477. }
  1478. }