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.

1433 lines
41 KiB

  1. // SvcProp.cpp
  2. //
  3. // Data object used to display service properties.
  4. //
  5. // HISTORY
  6. // 10-Oct-96 t-danmo Creation.
  7. //
  8. #include "stdafx.h"
  9. #include "DynamLnk.h" // DynamicDLL
  10. #include "cmponent.h" // FILEMGMTPROPERTYCHANGE
  11. extern "C"
  12. {
  13. #define NTSTATUS LONG
  14. #define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
  15. #define SE_SHUTDOWN_PRIVILEGE (19L)
  16. }
  17. #ifdef _DEBUG
  18. #define new DEBUG_NEW
  19. #undef THIS_FILE
  20. static char THIS_FILE[] = __FILE__;
  21. #endif
  22. /*
  23. Create an instance of this class to expand your token privileges
  24. to the maximum possible. Your privileges will return to normal
  25. when this object is destroyed. I don't think that you can have
  26. more than one of these at a time. There is no error handling,
  27. this class fails silently.
  28. jonn
  29. */
  30. class Impersonator
  31. {
  32. public:
  33. Impersonator();
  34. ~Impersonator();
  35. void ClaimPrivilege(DWORD dwPrivilege);
  36. void ReleasePrivilege();
  37. private:
  38. BOOL m_fImpersonating;
  39. };
  40. /////////////////////////////////////////////////////////////////////
  41. // ReportCfgMgrError()
  42. //
  43. // Display a message box reporting the error encountered
  44. // by the Configuration Manager.
  45. //
  46. // The error strings are included from \nt\private\windows\pnp\msg\cmapi.rc
  47. // and IDS_CFGMGR32_BASE may be defined to any number not conflicting with
  48. // the resources.
  49. //
  50. void ReportCfgMgrError(CONFIGRET cr)
  51. {
  52. if (cr > NUM_CR_RESULTS)
  53. {
  54. TRACE2("INFO: ReportCfgMgrError() - Error code 0x%X (%u) out of range.\n", cr, cr);
  55. // ASSERT(FALSE && "ReportCfgMgrError() - Error code out of range");
  56. cr = CR_FAILURE;
  57. }
  58. UINT ids = IDS_CFGMGR32_BASE + cr;
  59. DWORD dwErr = 0;
  60. if (cr == CR_OUT_OF_MEMORY)
  61. {
  62. ids = 0;
  63. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  64. }
  65. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr, ids);
  66. }
  67. /////////////////////////////////////////////////////////////////////
  68. typedef enum _AdvApiIndex
  69. {
  70. QUERY_SERVICE_CONFIG_2 = 0,
  71. CHANGE_SERVICE_CONFIG_2
  72. };
  73. // not subject to localization
  74. static LPCSTR g_apchFunctionNames[] = {
  75. "QueryServiceConfig2W",
  76. "ChangeServiceConfig2W",
  77. NULL
  78. };
  79. // not subject to localization
  80. DynamicDLL g_AdvApi32DLL( _T("ADVAPI32.DLL"), g_apchFunctionNames );
  81. typedef DWORD (*CHANGESERVICECONFIG2PROC) (SC_HANDLE,DWORD,LPVOID);
  82. typedef DWORD (*QUERYSERVICECONFIG2PROC) (SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD);
  83. /////////////////////////////////////////////////////////////////////
  84. /////////////////////////////////////////////////////////////////////
  85. // Constructor for CServicePropertyData object
  86. CServicePropertyData::CServicePropertyData()
  87. {
  88. // m_spDataObject is a smartpointer
  89. m_hMachine = NULL;
  90. m_hScManager = NULL;
  91. m_paQSC = NULL;
  92. m_paSFA = NULL;
  93. m_paHardwareProfileEntryList = NULL;
  94. m_fAllSfaTakeNoAction = FALSE;
  95. m_fQueryServiceConfig2 = g_AdvApi32DLL.LoadFunctionPointers();
  96. ::ZeroMemory(&m_rgSA, sizeof(m_rgSA));
  97. m_pPageGeneral = new CServicePageGeneral;
  98. m_pPageGeneral->m_pData = this;
  99. m_pPageHwProfile = new CServicePageHwProfile;
  100. m_pPageHwProfile->m_pData = this;
  101. m_pPageRecovery = new CServicePageRecovery;
  102. m_pPageRecovery->m_pData = this;
  103. m_pPageRecovery2 = new CServicePageRecovery2; // JonN 4/20/01 348163
  104. m_pPageRecovery2->m_pData = this; // JonN 4/20/01 348163
  105. } // CServicePropertyData::CServicePropertyData()
  106. /////////////////////////////////////////////////////////////////////
  107. CServicePropertyData::~CServicePropertyData()
  108. {
  109. // m_spDataObject is a smartpointer
  110. // Close the machine handle opened by CM_Connect_Machine()
  111. if (m_hMachine != NULL)
  112. {
  113. (void)::CM_Disconnect_Machine(m_hMachine);
  114. }
  115. // Close the service control manager database
  116. if (m_hScManager != NULL)
  117. {
  118. (void)::CloseServiceHandle(m_hScManager);
  119. }
  120. // Free the allocated pointers
  121. delete m_paQSC;
  122. delete m_paSFA;
  123. FlushHardwareProfileEntries();
  124. delete m_pPageGeneral;
  125. delete m_pPageHwProfile; // 77831: deletion now in place
  126. delete m_pPageRecovery;
  127. delete m_pPageRecovery2; // JonN 4/20/01 348163
  128. // Decrement the reference count of the parent object
  129. MMCFreeNotifyHandle(m_lNotifyHandle);
  130. } // CServicePropertyData::~CServicePropertyData()
  131. /////////////////////////////////////////////////////////////////////
  132. // FInit()
  133. //
  134. // Initialize the object by connecting to the target machine and
  135. // openning its service control manager database.
  136. //
  137. // RETURN VALUES
  138. // Return TRUE if successful, otherwise FALSE.
  139. //
  140. // ERRORS
  141. // - Unable to open service control manager.
  142. // - Unable to connect to remote machine.
  143. // - Unable to open service.
  144. // - Unable to query service data.
  145. //
  146. BOOL
  147. CServicePropertyData::FInit(
  148. LPDATAOBJECT lpDataObject,
  149. CONST TCHAR pszMachineName[], // IN: Machine name
  150. CONST TCHAR pszServiceName[], // IN: Service name
  151. CONST TCHAR pszServiceDisplayName[], // IN: Service display name (for UI purpose)
  152. LONG_PTR lNotifyHandle) // IN: Handle to notify parent
  153. {
  154. Assert(lpDataObject != NULL);
  155. Endorse(pszMachineName == NULL); // NULL => Local Machine
  156. Assert(pszServiceName != NULL);
  157. Assert(pszServiceDisplayName != NULL);
  158. m_spDataObject = lpDataObject; // m_pDataObject is a smartpointer
  159. m_strMachineName = pszMachineName; // Make a copy of the computer name
  160. m_strServiceName = pszServiceName; // Make a copy of the service name
  161. m_pszServiceName = m_strServiceName; // Cast a pointer to the service name
  162. m_strServiceDisplayName = pszServiceDisplayName;
  163. m_lNotifyHandle = lNotifyHandle;
  164. m_strUiMachineName = m_strMachineName.IsEmpty() ? g_strLocalMachine : m_strMachineName;
  165. Assert(m_hScManager == NULL);
  166. Assert(m_hMachine == NULL);
  167. return FQueryServiceInfo();
  168. } // CServicePropertyData::FInit()
  169. /////////////////////////////////////////////////////////////////////
  170. // FOpenScManager()
  171. //
  172. // Open the service control manager database (if not already opened).
  173. // The idea for such a function is to recover from a broken connection.
  174. //
  175. // Return TRUE if the service control database was opened successfully,
  176. // othersise false.
  177. //
  178. BOOL
  179. CServicePropertyData::FOpenScManager()
  180. {
  181. if (m_hScManager == NULL)
  182. {
  183. m_hScManager = ::OpenSCManager(
  184. m_strMachineName,
  185. NULL,
  186. SC_MANAGER_CONNECT);
  187. }
  188. if (m_hScManager == NULL)
  189. {
  190. DoServicesErrMsgBox(
  191. ::GetActiveWindow(),
  192. MB_OK | MB_ICONEXCLAMATION,
  193. ::GetLastError(),
  194. IDS_MSG_s_UNABLE_TO_OPEN_SERVICE_DATABASE,
  195. (LPCTSTR)m_strUiMachineName);
  196. return FALSE;
  197. }
  198. // JonN 2/14/01 315244
  199. // CM_Connect_Machine depends on Remote Registry Service which is
  200. // not present on Personal. NULL is OK for local focus, so skip this for
  201. // local focus.
  202. if (m_hMachine == NULL && !m_strMachineName.IsEmpty())
  203. {
  204. //
  205. // JonN 02/08/99: CM_Connect_Machine insists on whackwhack in machine names
  206. // per 288294.
  207. //
  208. CString strConnect;
  209. if ( m_strMachineName[0] != L'\\'
  210. && m_strMachineName[1] != L'\\' )
  211. {
  212. strConnect = L"\\\\";
  213. }
  214. strConnect += m_strMachineName;
  215. CONFIGRET cr;
  216. cr = ::CM_Connect_Machine((LPCTSTR)strConnect, OUT &m_hMachine);
  217. if (cr != CR_SUCCESS)
  218. {
  219. Assert(m_hMachine == NULL);
  220. // This might happen e.g. if PNP is stopped
  221. ReportCfgMgrError(cr);
  222. }
  223. }
  224. return TRUE;
  225. } // CServicePropertyData::FOpenScManager()
  226. /////////////////////////////////////////////////////////////////////
  227. // Create property pages of the service
  228. //
  229. BOOL
  230. CServicePropertyData::CreatePropertyPages(
  231. LPPROPERTYSHEETCALLBACK pCallback) // OUT: Object to append property pages
  232. {
  233. ASSERT(pCallback != NULL);
  234. HPROPSHEETPAGE hPage;
  235. MMCPropPageCallback(INOUT &m_pPageGeneral->m_psp);
  236. hPage = MyCreatePropertySheetPage(IN &m_pPageGeneral->m_psp);
  237. Report(hPage != NULL);
  238. if (hPage != NULL)
  239. pCallback->AddPage(hPage);
  240. MMCPropPageCallback(INOUT &m_pPageHwProfile->m_psp);
  241. hPage = MyCreatePropertySheetPage(IN &m_pPageHwProfile->m_psp);
  242. Report(hPage != NULL);
  243. if (hPage != NULL)
  244. pCallback->AddPage(hPage);
  245. if (m_uFlags & mskfValidSFA)
  246. {
  247. // Add the last page only if we were able to successfully
  248. // load the service failure action data structures.
  249. Assert(m_fQueryServiceConfig2);
  250. if (!(m_uFlags & mskfSystemProcess)) // JonN 4/20/01 348163
  251. {
  252. MMCPropPageCallback(INOUT &m_pPageRecovery->m_psp);
  253. hPage = MyCreatePropertySheetPage(IN &m_pPageRecovery->m_psp);
  254. }
  255. else
  256. {
  257. MMCPropPageCallback(INOUT &m_pPageRecovery2->m_psp);
  258. hPage = MyCreatePropertySheetPage(IN &m_pPageRecovery2->m_psp);
  259. }
  260. Report(hPage != NULL);
  261. if (hPage != NULL)
  262. pCallback->AddPage(hPage);
  263. }
  264. return TRUE;
  265. } // CServicePropertyData::CreatePropertyPages()
  266. /////////////////////////////////////////////////////////////////////
  267. // Query the service for its latest information.
  268. //
  269. // Return TRUE if ALL the service info could be successfully read.
  270. // Otherwise return FALSE if any error occured (such as not able to
  271. // or not able to query a specific key).
  272. //
  273. BOOL
  274. CServicePropertyData::FQueryServiceInfo()
  275. {
  276. SC_HANDLE hService = NULL;
  277. DWORD cbBytesNeeded = 0;
  278. BOOL fSuccess = TRUE;
  279. BOOL f;
  280. DWORD dwErr = 0;
  281. m_uFlags = mskzValidNone;
  282. if (!FOpenScManager())
  283. {
  284. // Unable to open service control database
  285. return FALSE;
  286. }
  287. TRACE1("INFO: Collecting data for service %s...\n", (LPCTSTR)m_strServiceDisplayName);
  288. (void)FQueryHardwareProfileEntries();
  289. /*
  290. ** Open service with querying access-control
  291. */
  292. hService = ::OpenService(
  293. m_hScManager,
  294. m_pszServiceName,
  295. SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG);
  296. if (hService == NULL)
  297. {
  298. DoServicesErrMsgBox(
  299. ::GetActiveWindow(),
  300. MB_OK | MB_ICONEXCLAMATION,
  301. ::GetLastError(),
  302. IDS_MSG_ss_UNABLE_TO_OPEN_READ_SERVICE,
  303. (LPCTSTR)m_strServiceDisplayName,
  304. (LPCTSTR)m_strUiMachineName);
  305. return FALSE;
  306. }
  307. /*
  308. ** Query the service status
  309. ** JonN 4/20/01 348163
  310. ** Try to determine whether this service runs in the system process
  311. */
  312. TRACE1("# QueryServiceStatusEx(%s)...\n", m_pszServiceName);
  313. f = ::QueryServiceStatusEx(
  314. hService,
  315. SC_STATUS_PROCESS_INFO,
  316. (LPBYTE)&m_SS,
  317. sizeof(m_SS),
  318. &cbBytesNeeded);
  319. if (f)
  320. {
  321. if (m_SS.dwServiceFlags & SERVICE_RUNS_IN_SYSTEM_PROCESS)
  322. m_uFlags |= mskfSystemProcess;
  323. }
  324. else // QueryServiceStatusEx failed
  325. {
  326. TRACE1("# QueryServiceStatus(%s)...\n", m_pszServiceName);
  327. f = ::QueryServiceStatus(
  328. hService,
  329. (LPSERVICE_STATUS)&m_SS);
  330. }
  331. if (f)
  332. {
  333. m_uFlags |= mskfValidSS;
  334. }
  335. else
  336. {
  337. DoErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, ::GetLastError());
  338. fSuccess = FALSE;
  339. }
  340. /*
  341. ** Query the service config
  342. */
  343. TRACE1("# QueryServiceConfig(%s)...\n", m_pszServiceName);
  344. f = ::QueryServiceConfig(
  345. hService,
  346. NULL,
  347. 0,
  348. OUT &cbBytesNeeded); // Compute how many bytes we need to allocate
  349. Report((f == FALSE) && "Query should fail on first attempt");
  350. Report(cbBytesNeeded > 0);
  351. cbBytesNeeded += 100; // Add extra bytes (just in case)
  352. delete m_paQSC; // Free previously allocated memory (if any)
  353. m_paQSC = (QUERY_SERVICE_CONFIG *) new BYTE[cbBytesNeeded];
  354. f = ::QueryServiceConfig(
  355. hService,
  356. OUT m_paQSC,
  357. cbBytesNeeded,
  358. OUT IGNORED &cbBytesNeeded);
  359. if (f)
  360. {
  361. m_uFlags |= mskfValidQSC;
  362. m_strServiceDisplayName = m_paQSC->lpDisplayName;
  363. m_strLogOnAccountName = m_paQSC->lpServiceStartName;
  364. }
  365. else
  366. {
  367. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, ::GetLastError());
  368. fSuccess = FALSE;
  369. }
  370. /*
  371. ** Query service description
  372. */
  373. if (m_fQueryServiceConfig2)
  374. {
  375. TRACE1("# QueryServiceConfig2(%s, SERVICE_CONFIG_DESCRIPTION)...\n", m_pszServiceName);
  376. union
  377. {
  378. // Service description
  379. SERVICE_DESCRIPTION sd;
  380. BYTE rgbBufferSd[SERVICE_cchDescriptionMax * sizeof(TCHAR) + 16];
  381. };
  382. f = ((QUERYSERVICECONFIG2PROC)g_AdvApi32DLL[QUERY_SERVICE_CONFIG_2])(
  383. hService,
  384. SERVICE_CONFIG_DESCRIPTION,
  385. OUT rgbBufferSd, // Description of service
  386. sizeof(rgbBufferSd),
  387. OUT IGNORED &cbBytesNeeded);
  388. if (f)
  389. {
  390. m_uFlags |= mskfValidDescr;
  391. Assert(cbBytesNeeded <= sizeof(rgbBufferSd));
  392. m_strDescription = sd.lpDescription;
  393. }
  394. else
  395. {
  396. Assert(m_strDescription.IsEmpty());
  397. m_fQueryServiceConfig2 = FALSE;
  398. }
  399. } // if
  400. /*
  401. ** Query service failure actions
  402. */
  403. Assert((m_uFlags & mskfValidSFA) == 0);
  404. if (m_fQueryServiceConfig2)
  405. {
  406. TRACE1("# QueryServiceConfig2(%s, SERVICE_CONFIG_FAILURE_ACTIONS)...\n", m_pszServiceName);
  407. cbBytesNeeded = sizeof(SERVICE_FAILURE_ACTIONS);
  408. delete m_paSFA; // Free previously allocated memory (if any)
  409. m_paSFA = (SERVICE_FAILURE_ACTIONS *) new BYTE[cbBytesNeeded];
  410. f = ((QUERYSERVICECONFIG2PROC)g_AdvApi32DLL[QUERY_SERVICE_CONFIG_2])(
  411. hService,
  412. SERVICE_CONFIG_FAILURE_ACTIONS,
  413. OUT (BYTE *)m_paSFA,
  414. cbBytesNeeded,
  415. OUT &cbBytesNeeded); // Compute how many bytes we need to allocate
  416. if (!f)
  417. {
  418. // API failed, probably because buffer was too small
  419. dwErr = ::GetLastError();
  420. if (dwErr == ERROR_INSUFFICIENT_BUFFER)
  421. {
  422. Assert(cbBytesNeeded > sizeof(SERVICE_FAILURE_ACTIONS));
  423. cbBytesNeeded += 100; // Add extra bytes (just in case)
  424. delete m_paSFA; // Free previously allocated memory
  425. m_paSFA = (SERVICE_FAILURE_ACTIONS *) new BYTE[cbBytesNeeded];
  426. // Call the API again
  427. TRACE2("# QueryServiceConfig2(%s, SERVICE_CONFIG_FAILURE_ACTIONS) [cbBytesNeeded=%u]...\n",
  428. m_pszServiceName, cbBytesNeeded);
  429. f = ((QUERYSERVICECONFIG2PROC)g_AdvApi32DLL[QUERY_SERVICE_CONFIG_2])(
  430. hService,
  431. SERVICE_CONFIG_FAILURE_ACTIONS,
  432. OUT (BYTE *)m_paSFA, // Get the actual failure/action data
  433. cbBytesNeeded,
  434. OUT IGNORED &cbBytesNeeded);
  435. if (!f)
  436. {
  437. dwErr = ::GetLastError();
  438. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr);
  439. }
  440. }
  441. } // if
  442. if (f)
  443. {
  444. m_uFlags |= mskfValidSFA;
  445. // Make a copy of the data
  446. memcpy(OUT &m_SFA, m_paSFA, sizeof(m_SFA));
  447. }
  448. else
  449. {
  450. Assert(dwErr != ERROR_SUCCESS);
  451. TRACE2("Unable to get SERVICE_CONFIG_FAILURE_ACTIONS (err=%u).\n ->Therefore Service Failure Actoin property page won't be added.\n",
  452. dwErr, m_pszServiceName);
  453. if (dwErr != 0)
  454. {
  455. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr);
  456. }
  457. ::ZeroMemory(OUT &m_SFA, sizeof(m_SFA));
  458. }
  459. // Extra processing to avoid nasty bugs
  460. if (m_SFA.lpsaActions == NULL || m_SFA.cActions < cActionsMax)
  461. {
  462. if (m_SFA.cActions >= 1 && m_SFA.lpsaActions != NULL)
  463. {
  464. // 384647: We need to fill in something for the latter actions
  465. // make them the same as the last real action
  466. memcpy(OUT &(m_rgSA[0]),
  467. m_SFA.lpsaActions,
  468. m_SFA.cActions*sizeof(SC_ACTION));
  469. for (int i = m_SFA.cActions; i < cActionsMax; i++)
  470. {
  471. memcpy(OUT &(m_rgSA[i]),
  472. &(m_SFA.lpsaActions[m_SFA.cActions-1]),
  473. sizeof(SC_ACTION) );
  474. }
  475. }
  476. m_SFA.lpsaActions = m_rgSA; // Use an alternative failure/action array
  477. m_SFA.cActions = cActionsMax;
  478. }
  479. m_strRunFileCommand = m_SFA.lpCommand;
  480. m_strRebootMessage = m_SFA.lpRebootMsg;
  481. // Convert time units for the UI
  482. m_secOriginalAbendCount = m_SFA.dwResetPeriod;
  483. m_daysOriginalAbendCount = CvtSecondsIntoDays(m_secOriginalAbendCount);
  484. m_daysDisplayAbendCount = m_daysOriginalAbendCount;
  485. m_msecOriginalRestartService =
  486. GetDelayForActionType(SC_ACTION_RESTART, OUT &f);
  487. if (!f) // 1 minute default
  488. m_msecOriginalRestartService = CvtMinutesIntoMilliseconds(1);
  489. m_minOriginalRestartService = CvtMillisecondsIntoMinutes(m_msecOriginalRestartService);
  490. m_minDisplayRestartService = m_minOriginalRestartService;
  491. m_msecOriginalRebootComputer =
  492. GetDelayForActionType(SC_ACTION_REBOOT, OUT &f);
  493. if (!f) // 1 minute default
  494. m_msecOriginalRebootComputer = CvtMinutesIntoMilliseconds(1);
  495. m_minOriginalRebootComputer = CvtMillisecondsIntoMinutes(m_msecOriginalRebootComputer);
  496. m_minDisplayRebootComputer = m_minOriginalRebootComputer;
  497. // Check wherever all action type are "None"
  498. m_fAllSfaTakeNoAction = FAllSfaTakeNoAction();
  499. } // if (m_fQueryServiceConfig2)
  500. VERIFY(::CloseServiceHandle(hService));
  501. return fSuccess;
  502. } // CServicePropertyData::FQueryServiceInfo()
  503. /////////////////////////////////////////////////////////////////////
  504. // FUpdateServiceInfo()
  505. //
  506. // Return TRUE if ALL the modified data were successfully written.
  507. // Return FALSE if any error occured.
  508. //
  509. BOOL
  510. CServicePropertyData::FUpdateServiceInfo()
  511. {
  512. SC_HANDLE hService = NULL;
  513. BOOL fSuccess = TRUE;
  514. BOOL f;
  515. BOOL fSkipPrivEnable = FALSE;
  516. TRACE1("INFO: Updating data for service %s...\n", (LPCTSTR)m_strServiceDisplayName);
  517. // Re-open service control manager (in case it was closed)
  518. if (!FOpenScManager())
  519. {
  520. return FALSE;
  521. }
  522. BOOL fRebootAction = FALSE;
  523. BOOL fRestartAction = FALSE;
  524. BOOL fChangedLogonAccountMessage = FALSE;
  525. if (m_uFlags & mskfValidSFA)
  526. {
  527. fRebootAction = !!QueryUsesActionType(SC_ACTION_REBOOT);
  528. fRestartAction = !!QueryUsesActionType(SC_ACTION_RESTART);
  529. }
  530. /*
  531. ** Open service with write access
  532. **
  533. ** CODEWORK Could provide a more specific error message
  534. ** if SERVICE_CHANGE_CONFIG is available but not SERVICE_START
  535. */
  536. hService = ::OpenService(
  537. m_hScManager,
  538. m_pszServiceName,
  539. SERVICE_CHANGE_CONFIG |
  540. SERVICE_QUERY_STATUS |
  541. ((fRestartAction)?SERVICE_START:0) );
  542. if (hService == NULL)
  543. {
  544. DoServicesErrMsgBox(
  545. ::GetActiveWindow(),
  546. MB_OK | MB_ICONEXCLAMATION,
  547. ::GetLastError(),
  548. IDS_MSG_ss_UNABLE_TO_OPEN_WRITE_SERVICE,
  549. (LPCTSTR)m_strServiceName,
  550. (LPCTSTR)m_strUiMachineName);
  551. return FALSE;
  552. }
  553. if (m_uFlags & (
  554. #ifdef EDIT_DISPLAY_NAME_373025
  555. mskfDirtyDisplayName |
  556. #endif // EDIT_DISPLAY_NAME_373025
  557. mskfDirtyStartupType |
  558. mskfDirtyAccountName |
  559. mskfDirtyPassword |
  560. mskfDirtySvcType))
  561. {
  562. TRACE1("# ChangeServiceConfig(%s)...\n", m_pszServiceName);
  563. Assert(m_paQSC != NULL);
  564. f = ::ChangeServiceConfig(
  565. hService, // Handle to service
  566. (m_uFlags & mskfDirtySvcType) ? m_paQSC->dwServiceType : SERVICE_NO_CHANGE, // Type of service
  567. (m_uFlags & mskfDirtyStartupType) ? m_paQSC->dwStartType : SERVICE_NO_CHANGE, // When/How to start service
  568. SERVICE_NO_CHANGE, // dwErrorControl - severity if service fails to start
  569. NULL, // Pointer to service binary file name
  570. NULL, // lpLoadOrderGroup - pointer to load ordering group name
  571. NULL, // lpdwTagId - pointer to variable to get tag identifier
  572. NULL, // lpDependencies - pointer to array of dependency names
  573. (m_uFlags & mskfDirtyAccountName) ? (LPCTSTR)m_strLogOnAccountName : NULL, // Pointer to account name of service
  574. (m_uFlags & mskfDirtyPassword) ? (LPCTSTR)m_strPassword : NULL, // Pointer to password for service account
  575. m_strServiceDisplayName);
  576. if (!f)
  577. {
  578. DWORD dwErr = ::GetLastError();
  579. Assert(dwErr != ERROR_SUCCESS);
  580. TRACE2("ERR: ChangeServiceConfig(%s) failed. err=%u.\n",
  581. m_pszServiceName, dwErr);
  582. if ( ERROR_INVALID_SERVICE_ACCOUNT == dwErr &&
  583. (m_paQSC->dwServiceType & SERVICE_WIN32_SHARE_PROCESS))
  584. {
  585. DoServicesErrMsgBox(
  586. ::GetActiveWindow(),
  587. MB_OK | MB_ICONEXCLAMATION,
  588. dwErr,
  589. IDS_MSG_s_UNABLE_TO_OPEN_WRITE_ACCT_INFO_DOWNLEVEL,
  590. (LPCTSTR)m_strServiceName,
  591. (LPCTSTR)m_strLogOnAccountName,
  592. (LPCTSTR)m_strUiMachineName);
  593. }
  594. else
  595. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, dwErr);
  596. fSkipPrivEnable = TRUE;
  597. fSuccess = FALSE;
  598. }
  599. else if (m_uFlags & mskfDirtyAccountName)
  600. {
  601. fChangedLogonAccountMessage = TRUE;
  602. }
  603. } // if
  604. #ifdef EDIT_DISPLAY_NAME_373025
  605. if ( (m_uFlags & mskfDirtyDescription)
  606. && m_fQueryServiceConfig2) // // JonN 03/07/00: PREFIX 56276
  607. {
  608. /*
  609. ** Write the service description
  610. */
  611. TRACE1("# ChangeServiceConfig2(%s, SERVICE_CONFIG_DESCRIPTION)...\n", m_pszServiceName);
  612. SERVICE_DESCRIPTION sd;
  613. sd.lpDescription = const_cast<LPTSTR>((LPCTSTR)m_strDescription);
  614. f = ((CHANGESERVICECONFIG2PROC)g_AdvApi32DLL[CHANGE_SERVICE_CONFIG_2])(
  615. hService,
  616. SERVICE_CONFIG_DESCRIPTION,
  617. IN &sd);
  618. if (!f)
  619. {
  620. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, ::GetLastError());
  621. fSuccess = FALSE;
  622. } // if
  623. } // if
  624. #endif // EDIT_DISPLAY_NAME_373025
  625. if (m_uFlags & mskfDirtyActionType)
  626. {
  627. // The idea here is to find out if any of the action type has
  628. // been modified by the user. For instance, the user may
  629. // change the action type to a specific action and then set
  630. // it back to where it was originally.
  631. if (m_fAllSfaTakeNoAction && FAllSfaTakeNoAction())
  632. {
  633. TRACE0("# No changes detected in Recovery Action Type");
  634. // Turn off the mskfDirtyActionType flag
  635. m_uFlags &= ~mskfDirtyActionType;
  636. }
  637. } // if
  638. if ((m_uFlags & (mskfDirtySFA | mskfDirtyRunFile | mskfDirtyRebootMessage | mskfDirtyActionType))
  639. && m_fQueryServiceConfig2) // JonN 03/07/00: PREFIX 56276
  640. {
  641. /*
  642. ** Write the service failure actions
  643. */
  644. /*
  645. AnirudhS 1/24/97
  646. Sure, [zero is] a reasonable default delay time to display
  647. [for SC_ACTION_RUN_COMMAND].
  648. Or, you could make it something like 5 seconds or whatever.
  649. The point of the delay time is to reduce the CPU impact
  650. of a service that continuously crashes and gets restarted.
  651. This makes the most sense for SC_ACTION_RESTART.
  652. For SC_ACTION_RUN_COMMAND the admin could have the command
  653. itself introduce its own delay.
  654. */
  655. TRACE1("# ChangeServiceConfig2(%s, SERVICE_CONFIG_FAILURE_ACTIONS)...\n", m_pszServiceName);
  656. Assert(m_fQueryServiceConfig2);
  657. Assert(m_uFlags & mskfValidSFA);
  658. UINT secNewAbendCount = m_secOriginalAbendCount;
  659. if (m_daysDisplayAbendCount != m_daysOriginalAbendCount)
  660. secNewAbendCount = CvtDaysIntoSeconds(m_daysDisplayAbendCount);
  661. UINT msecNewRestartService = m_msecOriginalRestartService;
  662. if (m_minDisplayRestartService != m_minOriginalRestartService)
  663. msecNewRestartService = CvtMinutesIntoMilliseconds(m_minDisplayRestartService);
  664. UINT msecNewRebootComputer = m_msecOriginalRebootComputer;
  665. if (m_minDisplayRebootComputer != m_minOriginalRebootComputer)
  666. msecNewRebootComputer = CvtMinutesIntoMilliseconds(m_minDisplayRebootComputer);
  667. m_SFA.dwResetPeriod = secNewAbendCount;
  668. SetDelayForActionType(SC_ACTION_RESTART, msecNewRestartService);
  669. SetDelayForActionType(SC_ACTION_RUN_COMMAND, 0);
  670. SetDelayForActionType(SC_ACTION_REBOOT, msecNewRebootComputer);
  671. m_SFA.lpCommand = (m_uFlags & mskfDirtyRunFile) ? (LPTSTR)(LPCTSTR)m_strRunFileCommand : NULL;
  672. m_SFA.lpRebootMsg = (m_uFlags & mskfDirtyRebootMessage) ? (LPTSTR)(LPCTSTR)m_strRebootMessage : NULL;
  673. //
  674. // The Service Controller will not permit us to set any
  675. // service failure action to Reboot unless our process token
  676. // has SE_SHUTDOWN_PRIVILEGE.
  677. //
  678. Impersonator priv;
  679. if (fRebootAction)
  680. priv.ClaimPrivilege(SE_SHUTDOWN_PRIVILEGE);
  681. f = ((CHANGESERVICECONFIG2PROC)g_AdvApi32DLL[CHANGE_SERVICE_CONFIG_2])(
  682. hService,
  683. SERVICE_CONFIG_FAILURE_ACTIONS,
  684. IN (void *)&m_SFA);
  685. if (!f)
  686. {
  687. DoServicesErrMsgBox(::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION, ::GetLastError());
  688. fSuccess = FALSE;
  689. } // if
  690. else
  691. {
  692. // We have successfully written the data, so refresh flag m_fAllSfaTakeNoAction
  693. m_secOriginalAbendCount = secNewAbendCount;
  694. m_daysOriginalAbendCount = m_daysDisplayAbendCount;
  695. m_msecOriginalRestartService = msecNewRestartService;
  696. m_minOriginalRestartService = m_minDisplayRestartService;
  697. m_msecOriginalRebootComputer = msecNewRebootComputer;
  698. m_minOriginalRebootComputer = m_minDisplayRebootComputer;
  699. m_fAllSfaTakeNoAction = FAllSfaTakeNoAction();
  700. }
  701. } // if
  702. if (!fSkipPrivEnable && (m_uFlags & mskfDirtyAccountName) &&
  703. (0 != lstrcmpi(m_strLogOnAccountName,_T("LocalSystem"))) ) // CODEWORK 317039
  704. {
  705. /*
  706. ** Make sure there is an LSA account with POLICY_MODE_SERVICE privilege
  707. ** This function reports its own errors, failure is only advisory
  708. */
  709. FCheckLSAAccount();
  710. } // if
  711. if (fChangedLogonAccountMessage && hService)
  712. {
  713. // check whether the service is running
  714. SERVICE_STATUS ss;
  715. if (!::QueryServiceStatus(hService, OUT &ss))
  716. {
  717. TRACE3("QueryServiceStatus(%s [hService=%p]) failed. err=%u.\n",
  718. m_pszServiceName, hService, GetLastError());
  719. }
  720. else if (SERVICE_STOPPED == ss.dwCurrentState)
  721. {
  722. // the service is stopped so there is no need for this message
  723. // when in doubt (SERVICE_anythingelse), go ahead and display the message
  724. fChangedLogonAccountMessage = FALSE;
  725. }
  726. }
  727. VERIFY(::CloseServiceHandle(hService));
  728. NotifySnapInParent();
  729. if (fChangedLogonAccountMessage)
  730. {
  731. DoServicesErrMsgBox(
  732. ::GetActiveWindow(), MB_OK | MB_ICONEXCLAMATION,
  733. 0, IDS_CHANGED_LOGON_NAME);
  734. }
  735. return fSuccess;
  736. } // FUpdateServiceInfo()
  737. /////////////////////////////////////////////////////////////////////
  738. // FOnApply()
  739. //
  740. // Return FALSE if some data could not be written.
  741. // Otherwise return TRUE.
  742. //
  743. BOOL CServicePropertyData::FOnApply()
  744. {
  745. BOOL fSuccess = TRUE;
  746. if (!FChangeHardwareProfileEntries())
  747. {
  748. // Error writing the modified hardware profile(s)
  749. fSuccess = FALSE;
  750. }
  751. if ((m_uFlags & mskmDirtyAll) == 0)
  752. {
  753. // Nothing has been modified, so we are done
  754. return fSuccess;
  755. }
  756. if (!FUpdateServiceInfo())
  757. {
  758. fSuccess = FALSE;
  759. }
  760. if (fSuccess)
  761. {
  762. (void)FQueryServiceInfo();
  763. }
  764. return fSuccess;
  765. } // FOnApply()
  766. /////////////////////////////////////////////////////////////////////
  767. // NotifySnapInParent()
  768. //
  769. // This function is used to notify the parent the properties has
  770. // been modified. The parent will then refresh the list.
  771. //
  772. // This notifcation is asynchronous. The recipient of this
  773. // notification required to release the data object.
  774. //
  775. void
  776. CServicePropertyData::NotifySnapInParent()
  777. {
  778. /*
  779. FILEMGMTPROPERTYCHANGE propchange;
  780. ::ZeroMemory( &propchange, sizeof(propchange) );
  781. propchange.fServiceChange = TRUE;
  782. propchange.lpcszMachineName = (LPCTSTR)m_strMachineName;
  783. // Tell all views to clear contents
  784. propchange.fClear = TRUE;
  785. MMCPropertyChangeNotify(
  786. m_lNotifyHandle,
  787. reinterpret_cast<long>(&propchange) );
  788. // Tell all views to reload contents
  789. propchange.fClear = FALSE;
  790. MMCPropertyChangeNotify(
  791. m_lNotifyHandle,
  792. reinterpret_cast<long>(&propchange) );
  793. */
  794. Assert(m_spDataObject != NULL);
  795. (void) m_spDataObject->AddRef();
  796. MMCPropertyChangeNotify(
  797. m_lNotifyHandle,
  798. reinterpret_cast<LPARAM>((LPDATAOBJECT)m_spDataObject) );
  799. }
  800. /////////////////////////////////////////////////////////////////////
  801. void
  802. CServicePropertyData::FlushHardwareProfileEntries()
  803. {
  804. delete m_paHardwareProfileEntryList; // Recursively delete hardware profile entries
  805. m_paHardwareProfileEntryList = NULL;
  806. }
  807. /////////////////////////////////////////////////////////////////////
  808. // FQueryHardwareProfileEntries()
  809. //
  810. // Read the available hardware profiles and device instances
  811. // used to fill in the listbox.
  812. //
  813. // Return FALSE if an error occured, otherwise TRUE.
  814. // If no hardware profiles are available return TRUE.
  815. //
  816. BOOL
  817. CServicePropertyData::FQueryHardwareProfileEntries()
  818. {
  819. Endorse(m_hMachine == NULL); // This might happen e.g. if PNP is stopped
  820. FlushHardwareProfileEntries();
  821. Assert(m_paHardwareProfileEntryList == NULL);
  822. if (m_hMachine == NULL && !m_strMachineName.IsEmpty()) // JonN 2/14/01 315244
  823. {
  824. // Cannot enumerate hw profiles
  825. return FALSE;
  826. }
  827. BOOL fSuccess = FALSE;
  828. CONFIGRET cr;
  829. ULONG cchDeviceList = 0; // Number of characters required to store a list of all device identifiers
  830. TCHAR * pagrszDeviceNameList = NULL; // Pointer to allocated group of strings
  831. LPTSTR * pargzpszDeviceName = NULL; // Pointer to allocated array of strings
  832. CString * pargstrDeviceNameFriendly = NULL; // Pointer to allocated array of CString
  833. DEVNODE hDevNodeInst; // Handle to a device node instance
  834. INT iDevNodeInst; // Index of the device node instance
  835. INT cDevNodeInst = 0; // Number of device node instances
  836. INT iHwProfile;
  837. // Get the size, in characters, of a list of device identifiers
  838. // necessary for a call to CM_Get_Device_ID_List()
  839. cr = ::CM_Get_Device_ID_List_Size_Ex(
  840. OUT &cchDeviceList,
  841. IN m_pszServiceName,
  842. IN CM_GETIDLIST_FILTER_SERVICE,
  843. IN m_hMachine);
  844. if (cr != CR_SUCCESS)
  845. {
  846. if (cr == CR_NO_SUCH_VALUE)
  847. {
  848. // This service cannot be disabled for hardware profiles
  849. Assert(m_paHardwareProfileEntryList == NULL); // No hardware profiles in the list
  850. return TRUE;
  851. }
  852. else
  853. {
  854. ReportCfgMgrError(cr);
  855. }
  856. return FALSE;
  857. } // if
  858. // Allocate memory for the device list
  859. cchDeviceList += 100; // Just in case
  860. // "pagrsz" == "p" + "a" + "gr" + "sz" == pointer to allocated group of string zero terminated
  861. pagrszDeviceNameList = new TCHAR[cchDeviceList];
  862. // Get the list of devices in its grsz format
  863. cr = ::CM_Get_Device_ID_List_Ex(
  864. IN m_pszServiceName,
  865. OUT pagrszDeviceNameList,
  866. IN cchDeviceList,
  867. CM_GETIDLIST_FILTER_SERVICE,
  868. m_hMachine);
  869. if (cr != CR_SUCCESS)
  870. {
  871. ReportCfgMgrError(cr);
  872. goto DoCleanup;
  873. }
  874. // Parse the group of strings int an array of strings
  875. pargzpszDeviceName = PargzpszFromPgrsz(pagrszDeviceNameList, OUT &cDevNodeInst);
  876. Assert(cDevNodeInst > 0);
  877. // Now allocate an array of CStrings for the friendly names
  878. pargstrDeviceNameFriendly = new CString[cDevNodeInst];
  879. // We only show the hw profile instance if there are more than one node instance
  880. m_fShowHwProfileInstances = (cDevNodeInst > 1);
  881. // m_fShowHwProfileInstances = TRUE;
  882. m_iSubItemHwProfileStatus = 1 + m_fShowHwProfileInstances;
  883. for (iDevNodeInst = 0; iDevNodeInst < cDevNodeInst; iDevNodeInst++)
  884. {
  885. Assert(pargzpszDeviceName[iDevNodeInst] != NULL); // Little consistency check
  886. TCHAR szFriendlyNameT[2048]; // Temporary buffer to hold friendly name
  887. ULONG cbBufferLen = sizeof(szFriendlyNameT);
  888. // Get the handle of the device instance that corresponds
  889. // to the specified device identifier.
  890. cr = ::CM_Locate_DevNode_Ex(
  891. OUT &hDevNodeInst,
  892. IN pargzpszDeviceName[iDevNodeInst],
  893. CM_LOCATE_DEVNODE_PHANTOM,
  894. m_hMachine);
  895. if (cr != CR_SUCCESS)
  896. {
  897. ReportCfgMgrError(cr);
  898. goto DoCleanup;
  899. }
  900. szFriendlyNameT[0] = '\0';
  901. // Get the friendly name of the device node
  902. cr = ::CM_Get_DevNode_Registry_Property_Ex(
  903. hDevNodeInst,
  904. CM_DRP_FRIENDLYNAME,
  905. NULL,
  906. OUT szFriendlyNameT,
  907. INOUT &cbBufferLen,
  908. 0,
  909. m_hMachine);
  910. Report(cr != CR_BUFFER_SMALL);
  911. if (cr == CR_NO_SUCH_VALUE || cr == CR_INVALID_PROPERTY)
  912. {
  913. // No friendly name for device node, so try to get the description instead
  914. cbBufferLen = sizeof(szFriendlyNameT);
  915. cr = ::CM_Get_DevNode_Registry_Property_Ex(
  916. hDevNodeInst,
  917. CM_DRP_DEVICEDESC,
  918. NULL,
  919. OUT szFriendlyNameT,
  920. INOUT &cbBufferLen,
  921. 0,
  922. m_hMachine);
  923. Report(cr != CR_BUFFER_SMALL);
  924. Report(!(cr == CR_NO_SUCH_VALUE || cr == CR_INVALID_PROPERTY) && "Device node should have a description");
  925. if (cr != CR_SUCCESS)
  926. {
  927. ReportCfgMgrError(cr);
  928. goto DoCleanup;
  929. }
  930. } // if
  931. if (szFriendlyNameT[0] == '\0')
  932. {
  933. Report(FALSE && "Device node should have a friendly name");
  934. // Make a 'friendly' name ourselves
  935. lstrcpy(OUT szFriendlyNameT, pargzpszDeviceName[iDevNodeInst]);
  936. }
  937. // Make a copy of the friendly name
  938. pargstrDeviceNameFriendly[iDevNodeInst] = szFriendlyNameT;
  939. } // for
  940. #define MAX_HW_PROFILES 10000000 // Just in case of an infinite loop
  941. for (iHwProfile = 0; iHwProfile < MAX_HW_PROFILES; iHwProfile++)
  942. {
  943. HWPROFILEINFO hpi;
  944. cr = ::CM_Get_Hardware_Profile_Info_Ex(
  945. iHwProfile,
  946. OUT &hpi,
  947. 0,
  948. m_hMachine);
  949. if (cr == CR_NO_MORE_HW_PROFILES)
  950. break;
  951. if (cr != CR_SUCCESS)
  952. {
  953. if (cr == 0xBAADF00D)
  954. {
  955. TRACE0("INFO: CM_Get_Hardware_Profile_Info_Ex() returned error 0xBAADF00D.\n");
  956. // This is a workaround for bug #69142: CM_Get_Hardware_Profile_Info_Ex() returns error 0xBAADF00D.
  957. Assert((m_uFlags & mskfErrorBAADF00D) == 0);
  958. m_uFlags |= mskfErrorBAADF00D;
  959. }
  960. else
  961. {
  962. ReportCfgMgrError(cr);
  963. }
  964. goto DoCleanup;
  965. }
  966. for (iDevNodeInst = 0; iDevNodeInst < cDevNodeInst; iDevNodeInst++)
  967. {
  968. Assert(pargzpszDeviceName[iDevNodeInst] != NULL); // Little consistency check
  969. ULONG uHwFlags = 0;
  970. // Get the hardware profile flags for the given device instance
  971. cr = ::CM_Get_HW_Prof_Flags_Ex(
  972. IN pargzpszDeviceName[iDevNodeInst],
  973. IN hpi.HWPI_ulHWProfile,
  974. OUT &uHwFlags,
  975. 0,
  976. m_hMachine);
  977. if (cr != CR_SUCCESS)
  978. {
  979. ReportCfgMgrError(cr);
  980. goto DoCleanup;
  981. }
  982. // If this profile/devinst is marked as 'removed'
  983. // then don't display it into the UI.
  984. if (uHwFlags & CSCONFIGFLAG_DO_NOT_CREATE)
  985. continue;
  986. CHardwareProfileEntry * pHPE = new CHardwareProfileEntry(
  987. &hpi,
  988. uHwFlags,
  989. pargzpszDeviceName[iDevNodeInst],
  990. &pargstrDeviceNameFriendly[iDevNodeInst]);
  991. pHPE->m_pNext = m_paHardwareProfileEntryList;
  992. m_paHardwareProfileEntryList = pHPE;
  993. } // for (each device instance)
  994. } // for (each hardware profile
  995. Assert(fSuccess == FALSE);
  996. fSuccess = TRUE;
  997. DoCleanup:
  998. // Free memory allocated by routine
  999. delete pagrszDeviceNameList;
  1000. delete pargzpszDeviceName;
  1001. delete []pargstrDeviceNameFriendly;
  1002. return fSuccess;
  1003. } // FQueryHardwareProfileEntries()
  1004. /////////////////////////////////////////////////////////////////////
  1005. // Write the modified hardware profile(s) back into
  1006. // the registry.
  1007. BOOL
  1008. CServicePropertyData::FChangeHardwareProfileEntries()
  1009. {
  1010. CHardwareProfileEntry * pHPE;
  1011. BOOL fSuccess = TRUE;
  1012. for (pHPE = m_paHardwareProfileEntryList; pHPE != NULL; pHPE = pHPE->m_pNext)
  1013. {
  1014. if (!pHPE->FWriteHardwareProfile(m_hMachine))
  1015. {
  1016. // Unable to write the given hw profile
  1017. fSuccess = FALSE;
  1018. }
  1019. } // for
  1020. return fSuccess;
  1021. } // FChangeHardwareProfileEntries()
  1022. /////////////////////////////////////////////////////////////////////
  1023. // Find the delay (in milliseconds) unit for a given action type
  1024. //
  1025. // Return the delay of the first matching actiontype,
  1026. // Otherwise return 0 and set content of pfFound to FALSE.
  1027. //
  1028. UINT
  1029. CServicePropertyData::GetDelayForActionType(
  1030. SC_ACTION_TYPE actionType,
  1031. BOOL * pfDelayFound) // OUT: OPTIONAL: TRUE => If delay was found in one actiontype
  1032. {
  1033. for (UINT iAction = 0; iAction < m_SFA.cActions; iAction++)
  1034. {
  1035. Assert(m_SFA.lpsaActions != NULL);
  1036. if (m_SFA.lpsaActions[iAction].Type == actionType)
  1037. {
  1038. if (pfDelayFound != NULL)
  1039. *pfDelayFound = TRUE;
  1040. return m_SFA.lpsaActions[iAction].Delay;
  1041. }
  1042. } // for
  1043. // Delay not found
  1044. if (pfDelayFound != NULL)
  1045. *pfDelayFound = FALSE;
  1046. return 0;
  1047. } // CServicePropertyData::GetDelayForActionType()
  1048. /////////////////////////////////////////////////////////////////////
  1049. // Set the delay for every matching actiontype.
  1050. //
  1051. void CServicePropertyData::SetDelayForActionType(SC_ACTION_TYPE actionType, UINT uDelay)
  1052. {
  1053. for (UINT iAction = 0; iAction < m_SFA.cActions; iAction++)
  1054. {
  1055. Assert(m_SFA.lpsaActions != NULL);
  1056. if (m_SFA.lpsaActions[iAction].Type == actionType)
  1057. m_SFA.lpsaActions[iAction].Delay = uDelay;
  1058. } // for
  1059. } // CServicePropertyData::SetDelayForActionType()
  1060. /////////////////////////////////////////////////////////////////////
  1061. // Count the number of actiontype used in the SFA structure.
  1062. //
  1063. // Return zero if the actiontype is not in use.
  1064. //
  1065. UINT CServicePropertyData::QueryUsesActionType(SC_ACTION_TYPE actionType)
  1066. {
  1067. UINT cActionType = 0; // Number
  1068. for (UINT iAction = 0; iAction < m_SFA.cActions; iAction++)
  1069. {
  1070. Assert(m_SFA.lpsaActions != NULL);
  1071. if (m_SFA.lpsaActions[iAction].Type == actionType)
  1072. cActionType++;
  1073. } // for
  1074. return cActionType;
  1075. } // CServicePropertyData::QueryUsesActionType()
  1076. /////////////////////////////////////////////////////////////////////
  1077. // FAllSfaTakeNoAction()
  1078. //
  1079. // Return TRUE if all the Service Faillure Actions are SC_ACTION_NONE.
  1080. // If any of the SFA is other than SC_ACTION_NONE, return TRUE.
  1081. //
  1082. BOOL
  1083. CServicePropertyData::FAllSfaTakeNoAction()
  1084. {
  1085. Report(QueryUsesActionType(SC_ACTION_NONE) <= cActionsMax &&
  1086. "UNSUAL: Unsupported number of action types");
  1087. return QueryUsesActionType(SC_ACTION_NONE) == cActionsMax;
  1088. } // CServicePropertyData::FAllSfaTakeNoAction()
  1089. /////////////////////////////////////////////////////////////////////
  1090. // Update the caption of the property sheet to reflect changes
  1091. // in the service display name.
  1092. void CServicePropertyData::UpdateCaption()
  1093. {
  1094. Assert(IsWindow(m_hwndPropertySheet));
  1095. ::SetWindowTextPrintf(
  1096. m_hwndPropertySheet,
  1097. IDS_ss_PROPERTIES_ON,
  1098. (LPCTSTR)m_strServiceDisplayName,
  1099. (LPCTSTR)m_strUiMachineName);
  1100. }
  1101. /////////////////////////////////////////////////////////////////////
  1102. /////////////////////////////////////////////////////////////////////
  1103. CHardwareProfileEntry::CHardwareProfileEntry(
  1104. IN CONST HWPROFILEINFO * phpi,
  1105. IN ULONG uHwFlags,
  1106. TCHAR * pszDeviceName,
  1107. CString * pstrDeviceNameFriendly)
  1108. {
  1109. Assert(phpi != NULL);
  1110. Assert(pszDeviceName != NULL);
  1111. Assert(pstrDeviceNameFriendly != NULL);
  1112. memcpy(OUT &m_hpi, phpi, sizeof(m_hpi));
  1113. m_uHwFlags = uHwFlags;
  1114. m_strDeviceName = pszDeviceName;
  1115. m_strDeviceNameFriendly = *pstrDeviceNameFriendly;
  1116. Assert(!m_strDeviceName.IsEmpty());
  1117. m_fReadOnly = FALSE;
  1118. m_fEnabled = !(uHwFlags & CSCONFIGFLAG_DISABLED);
  1119. } // CHardwareProfileEntry()
  1120. /////////////////////////////////////////////////////////////////////
  1121. CHardwareProfileEntry::~CHardwareProfileEntry()
  1122. {
  1123. // Recursively delete the siblings
  1124. delete m_pNext;
  1125. }
  1126. /////////////////////////////////////////////////////////////////////
  1127. // FWriteHardwareProfile()
  1128. //
  1129. // Write the current hardware profile back into the
  1130. // registry.
  1131. //
  1132. // Return FALSE if an error occured, otherwise TRUE
  1133. //
  1134. BOOL
  1135. CHardwareProfileEntry::FWriteHardwareProfile(HMACHINE hMachine)
  1136. {
  1137. Endorse(hMachine == NULL); // JonN 2/14/01 315244
  1138. CONFIGRET cr;
  1139. ULONG uHwFlags;
  1140. BOOL fSuccess = TRUE;
  1141. uHwFlags = m_uHwFlags | CSCONFIGFLAG_DISABLED;
  1142. if (m_fEnabled)
  1143. uHwFlags &= ~CSCONFIGFLAG_DISABLED;
  1144. if (m_uHwFlags == uHwFlags)
  1145. {
  1146. // Flags have not been modified, nothing to do
  1147. return TRUE;
  1148. }
  1149. m_uHwFlags = uHwFlags;
  1150. // Write the hardware profile flag
  1151. cr = ::CM_Set_HW_Prof_Flags_Ex(
  1152. IN const_cast<LPTSTR>((LPCTSTR)m_strDeviceName),
  1153. IN m_hpi.HWPI_ulHWProfile,
  1154. IN uHwFlags,
  1155. IN 0,
  1156. IN hMachine);
  1157. if (cr != CR_SUCCESS && cr != CR_NEED_RESTART)
  1158. {
  1159. ReportCfgMgrError(cr);
  1160. fSuccess = FALSE;
  1161. }
  1162. // Read it back (just in case of an error
  1163. cr = ::CM_Get_HW_Prof_Flags_Ex(
  1164. IN const_cast<LPTSTR>((LPCTSTR)m_strDeviceName),
  1165. IN m_hpi.HWPI_ulHWProfile,
  1166. OUT &uHwFlags,
  1167. IN 0,
  1168. IN hMachine);
  1169. if (cr != CR_SUCCESS)
  1170. {
  1171. ReportCfgMgrError(cr);
  1172. fSuccess = FALSE;
  1173. }
  1174. if (uHwFlags != m_uHwFlags)
  1175. {
  1176. Report(FALSE && "Inconsistent hardware profile flags from registry");
  1177. }
  1178. m_fEnabled = !(uHwFlags & CSCONFIGFLAG_DISABLED);
  1179. return fSuccess;
  1180. } // FWriteHardwareProfile()
  1181. /////////////////////////////////////////////////////////////////////
  1182. /////////////////////////////////////////////////////////////////////
  1183. BOOL MyChangeServiceConfig2(
  1184. BOOL* pfDllPresentLocally, // will set to FALSE if new ADVAPI32 not present
  1185. SC_HANDLE hService, // handle to service
  1186. DWORD dwInfoLevel, // which configuration information to change
  1187. LPVOID lpInfo // pointer to configuration information
  1188. )
  1189. {
  1190. *pfDllPresentLocally = g_AdvApi32DLL.LoadFunctionPointers();
  1191. if ( *pfDllPresentLocally )
  1192. {
  1193. return ((CHANGESERVICECONFIG2PROC)g_AdvApi32DLL[CHANGE_SERVICE_CONFIG_2])(
  1194. hService,
  1195. dwInfoLevel,
  1196. lpInfo );
  1197. }
  1198. return FALSE;
  1199. }
  1200. BOOL MyQueryServiceConfig2(
  1201. BOOL* pfDllPresentLocally, // will set to FALSE if new ADVAPI32 not present
  1202. SC_HANDLE hService, // handle of service
  1203. DWORD dwInfoLevel, // which configuration data is requested
  1204. LPBYTE lpBuffer, // pointer to service configuration buffer
  1205. DWORD cbBufSize, // size of service configuration buffer
  1206. LPDWORD pcbBytesNeeded // address of variable for bytes needed
  1207. )
  1208. {
  1209. *pfDllPresentLocally = g_AdvApi32DLL.LoadFunctionPointers();
  1210. if ( *pfDllPresentLocally )
  1211. {
  1212. return ((QUERYSERVICECONFIG2PROC)g_AdvApi32DLL[QUERY_SERVICE_CONFIG_2])(
  1213. hService,
  1214. dwInfoLevel,
  1215. lpBuffer,
  1216. cbBufSize,
  1217. pcbBytesNeeded );
  1218. }
  1219. return FALSE;
  1220. }
  1221. // core code taken from \nt\private\windows\base\advapi\logon32.c
  1222. typedef enum _NtRtlIndex
  1223. {
  1224. RTL_IMPERSONATE_SELF = 0,
  1225. RTL_ADJUST_PRIVILEGE
  1226. };
  1227. // not subject to localization
  1228. static LPCSTR g_apchNtRtlFunctionNames[] = {
  1229. "RtlImpersonateSelf",
  1230. "RtlAdjustPrivilege",
  1231. NULL
  1232. };
  1233. // not subject to localization
  1234. DynamicDLL g_NtRtlDLL( _T("NTDLL.DLL"), g_apchNtRtlFunctionNames );
  1235. /*
  1236. NTSYSAPI
  1237. NTSTATUS
  1238. NTAPI
  1239. RtlImpersonateSelf(
  1240. IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
  1241. );
  1242. NTSYSAPI
  1243. NTSTATUS
  1244. NTAPI
  1245. RtlAdjustPrivilege(
  1246. ULONG Privilege,
  1247. BOOLEAN Enable,
  1248. BOOLEAN Client,
  1249. PBOOLEAN WasEnabled
  1250. );
  1251. */
  1252. typedef DWORD (*RTLIMPERSONATESELFPROC) (SECURITY_IMPERSONATION_LEVEL);
  1253. typedef DWORD (*RTLADJUSTPRIVILEGEPROC) (ULONG,BOOLEAN,BOOLEAN,PBOOLEAN);
  1254. Impersonator::Impersonator()
  1255. : m_fImpersonating( FALSE )
  1256. {
  1257. }
  1258. void Impersonator::ClaimPrivilege(DWORD dwPrivilege)
  1259. {
  1260. if ( !g_NtRtlDLL.LoadFunctionPointers() )
  1261. {
  1262. ASSERT(FALSE); // NTDLL not present?
  1263. return;
  1264. }
  1265. NTSTATUS Status = S_OK;
  1266. if (!m_fImpersonating)
  1267. {
  1268. Status = ((RTLIMPERSONATESELFPROC)g_NtRtlDLL[RTL_IMPERSONATE_SELF])(
  1269. SecurityImpersonation );
  1270. if ( !NT_SUCCESS(Status) )
  1271. {
  1272. ASSERT(FALSE); // probably stacked impersonations
  1273. return;
  1274. }
  1275. m_fImpersonating = TRUE;
  1276. }
  1277. BOOLEAN fWasEnabled = FALSE;
  1278. Status = ((RTLADJUSTPRIVILEGEPROC)g_NtRtlDLL[RTL_ADJUST_PRIVILEGE])(
  1279. dwPrivilege,TRUE,TRUE,&fWasEnabled );
  1280. if ( !NT_SUCCESS(Status) )
  1281. {
  1282. // don't assert
  1283. }
  1284. }
  1285. void Impersonator::ReleasePrivilege()
  1286. {
  1287. if (m_fImpersonating)
  1288. {
  1289. VERIFY( ::RevertToSelf() );
  1290. m_fImpersonating = FALSE;
  1291. }
  1292. }
  1293. Impersonator::~Impersonator()
  1294. {
  1295. ReleasePrivilege();
  1296. }