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

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