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.

699 lines
17 KiB

  1. // SCEAgent.cpp : Implementation of CSCEAgent
  2. #include "stdafx.h"
  3. #include "SSRTE.h"
  4. #include "SCEAgent.h"
  5. #include "ntsecapi.h"
  6. #include "secedit.h"
  7. /////////////////////////////////////////////////////////////////////////////
  8. // CSCEAgent
  9. static LPCWSTR g_pwszTempDBName = L"5ac90887-f869-4cb6-ae96-892e939a90ad.sdb";
  10. void CSCEAgent::Cleanup()
  11. /*++
  12. Routine Description:
  13. Name:
  14. CSCEAgent::Cleanup
  15. Functionality:
  16. Private helper to reduce duplicate code.
  17. Cleanup any resources that we might hold on.
  18. Virtual:
  19. None.
  20. Arguments:
  21. None
  22. Return Value:
  23. None.
  24. Notes:
  25. --*/
  26. {
  27. if (m_headServiceList != NULL)
  28. {
  29. PSERVICE_NODE tempNode = m_headServiceList;
  30. PSERVICE_NODE tempNodeNext = NULL;
  31. do
  32. {
  33. tempNodeNext = tempNode->Next;
  34. if (tempNode->Name)
  35. {
  36. LocalFree(tempNode->Name);
  37. }
  38. LocalFree(tempNode);
  39. tempNode = tempNodeNext;
  40. } while ( tempNode != NULL );
  41. m_headServiceList = NULL;
  42. }
  43. }
  44. STDMETHODIMP
  45. CSCEAgent::Configure (
  46. IN BSTR bstrTemplate,
  47. IN LONG lAreaMask,
  48. IN BSTR OPTIONAL bstrLogFile
  49. )
  50. /*++
  51. Routine Description:
  52. Name:
  53. CSCEAgent::Configure
  54. Functionality:
  55. this is to expose the SCE's configure capability to scripting
  56. Virtual:
  57. Yes.
  58. Arguments:
  59. bstrTemplate - The template path the configure is based on.
  60. lAreaMask - The areas this configure will be run.
  61. bstrLogFile - The log file path
  62. Return Value:
  63. None.
  64. Notes:
  65. 1. We should really be passing in AREA_ALL for the area mask parameter
  66. But that requires the caller to use a DWORD flag 65535 in script,
  67. which is odd. So, we opt to ignore the mask at this point. Meaning
  68. we will always use AREA_ALL.
  69. --*/
  70. {
  71. if (bstrTemplate == NULL)
  72. {
  73. return E_INVALIDARG;
  74. }
  75. //
  76. // process options
  77. //
  78. DWORD dwOption = SCE_OVERWRITE_DB;
  79. if (bstrLogFile == NULL || *bstrLogFile == L'\0')
  80. {
  81. dwOption |= SCE_DISABLE_LOG;
  82. }
  83. else
  84. {
  85. dwOption |= SCE_VERBOSE_LOG;
  86. }
  87. //
  88. // According to Vishnu, SCE will configure an INF file.
  89. //
  90. CComBSTR bstrTempDBFile(bstrTemplate);
  91. bstrTempDBFile += g_pwszTempDBName;
  92. if (bstrTempDBFile.m_str != NULL)
  93. {
  94. SCESTATUS rc = ::SceConfigureSystem(
  95. NULL,
  96. bstrTemplate,
  97. bstrTempDBFile,
  98. bstrLogFile,
  99. dwOption,
  100. lAreaMask,
  101. NULL,
  102. NULL,
  103. NULL
  104. );
  105. ::DeleteFile(bstrTempDBFile);
  106. //
  107. // we can opt to not to delete the database, but leaving it there will
  108. // create confusions
  109. //
  110. return SceStatusToHRESULT(rc);
  111. }
  112. else
  113. {
  114. return E_OUTOFMEMORY;
  115. }
  116. }
  117. STDMETHODIMP
  118. CSCEAgent::CreateRollbackTemplate (
  119. IN BSTR bstrTemplatePath,
  120. IN BSTR bstrRollbackPath,
  121. IN BSTR bstrLogFilePath
  122. )
  123. /*++
  124. Routine Description:
  125. Name:
  126. CSCEAgent::CreateRollbackTemplate
  127. Functionality:
  128. this is to expose the SCE's rollback tempalte creation capability to scripting
  129. Virtual:
  130. Yes.
  131. Arguments:
  132. bstrTemplatePath - The template path this rollback will be based on.
  133. bstrRollbackPath - The rollback template that will be created
  134. bstrLogFilePath - The logfile path
  135. Return Value:
  136. None.
  137. Notes:
  138. 1. I believe this log file path can be optional. Need to check with JinHuang
  139. --*/
  140. {
  141. if (bstrTemplatePath == NULL ||
  142. bstrRollbackPath == NULL)
  143. {
  144. return E_INVALIDARG;
  145. }
  146. DWORD dwWarning = 0;
  147. SCESTATUS rc = ::SceGenerateRollback(
  148. NULL,
  149. bstrTemplatePath,
  150. bstrRollbackPath,
  151. bstrLogFilePath,
  152. SCE_VERBOSE_LOG,
  153. AREA_ALL,
  154. &dwWarning
  155. );
  156. //
  157. // $undone:shawnwu, how should I use the dwWarning?
  158. //
  159. return SceStatusToHRESULT(rc);
  160. }
  161. //
  162. // UpdateServiceList is authored by VishnuP. Please send comments or
  163. // questions to him.
  164. //
  165. STDMETHODIMP
  166. CSCEAgent::UpdateServiceList (
  167. IN BSTR bstrServiceName,
  168. IN BSTR bstrStartupType
  169. )
  170. {
  171. if (bstrServiceName == NULL || bstrStartupType == NULL )
  172. {
  173. return E_INVALIDARG;
  174. }
  175. DWORD dwStartupType;
  176. if (0 == _wcsicmp(bstrStartupType, L"automatic")) {
  177. dwStartupType = 2;
  178. } else if (0 == _wcsicmp(bstrStartupType, L"manual")) {
  179. dwStartupType = 3;
  180. } else if (0 == _wcsicmp(bstrStartupType, L"disabled")) {
  181. dwStartupType = 4;
  182. } else {
  183. return E_INVALIDARG;
  184. }
  185. PSERVICE_NODE NewNode = NULL;
  186. NewNode = (PSERVICE_NODE)LocalAlloc(LMEM_ZEROINIT,
  187. sizeof(SERVICE_NODE)
  188. );
  189. if (NewNode == NULL) {
  190. return E_OUTOFMEMORY;
  191. }
  192. int iSvcNameLen = wcslen(bstrServiceName) + 1;
  193. NewNode->Name = (PWSTR)LocalAlloc(
  194. LMEM_ZEROINIT,
  195. iSvcNameLen * sizeof(WCHAR)
  196. );
  197. if (NewNode->Name == NULL) {
  198. LocalFree(NewNode);
  199. return E_OUTOFMEMORY;
  200. }
  201. wcsncpy(NewNode->Name, bstrServiceName, iSvcNameLen);
  202. NewNode->dwStartupType = dwStartupType;
  203. NewNode->Next = m_headServiceList;
  204. m_headServiceList = NewNode;
  205. return S_OK;
  206. }
  207. //
  208. // CreateServicesCfgRbkTemplates is authored by VishnuP. Please send comments or
  209. // questions to him.
  210. //
  211. STDMETHODIMP
  212. CSCEAgent::CreateServicesCfgRbkTemplates (
  213. IN BSTR bstrTemplatePath,
  214. IN BSTR bstrRollbackPath,
  215. IN BSTR bstrLogFilePath
  216. )
  217. {
  218. UNREFERENCED_PARAMETER(bstrLogFilePath);
  219. if (bstrTemplatePath == NULL || bstrRollbackPath == NULL)
  220. {
  221. return E_INVALIDARG;
  222. }
  223. DWORD dwNumServices = 0;
  224. SC_HANDLE hScm = NULL;
  225. DWORD rc = ERROR_SUCCESS;
  226. LPENUM_SERVICE_STATUS_PROCESS pInfo = NULL;
  227. DWORD *aSCMListStartupTypes = NULL;
  228. DWORD *aSCMListStartupTypesCfg = NULL;
  229. SCESVC_CONFIGURATION_INFO ServiceInfo;
  230. ServiceInfo.Count = dwNumServices;
  231. ServiceInfo.Lines = NULL;
  232. //
  233. // Connect to the service controller.
  234. //
  235. hScm = OpenSCManager(
  236. NULL,
  237. NULL,
  238. SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE);
  239. if (hScm == NULL) {
  240. rc = GetLastError();
  241. goto CleanUp;
  242. }
  243. DWORD cbInfo = 0;
  244. DWORD dwResume = 0;
  245. if ((!EnumServicesStatusEx(
  246. hScm,
  247. SC_ENUM_PROCESS_INFO,
  248. SERVICE_WIN32,
  249. SERVICE_STATE_ALL,
  250. NULL,
  251. 0,
  252. &cbInfo,
  253. &dwNumServices,
  254. &dwResume,
  255. NULL)) && ERROR_MORE_DATA == GetLastError()) {
  256. pInfo = (LPENUM_SERVICE_STATUS_PROCESS)LocalAlloc(LMEM_ZEROINIT, cbInfo);
  257. if (pInfo == NULL) {
  258. rc = ERROR_NOT_ENOUGH_MEMORY;
  259. goto CleanUp;
  260. }
  261. }
  262. else {
  263. rc = GetLastError();
  264. goto CleanUp;
  265. }
  266. if (!EnumServicesStatusEx(
  267. hScm,
  268. SC_ENUM_PROCESS_INFO,
  269. SERVICE_WIN32,
  270. SERVICE_STATE_ALL,
  271. (LPBYTE)pInfo,
  272. cbInfo,
  273. &cbInfo,
  274. &dwNumServices,
  275. &dwResume,
  276. NULL)) {
  277. rc = GetLastError();
  278. goto CleanUp;
  279. }
  280. //
  281. // get the startup type for each service
  282. //
  283. aSCMListStartupTypes = (DWORD *) LocalAlloc (
  284. LMEM_ZEROINIT,
  285. sizeof(DWORD) * dwNumServices
  286. );
  287. if (aSCMListStartupTypes == NULL) {
  288. rc = ERROR_NOT_ENOUGH_MEMORY;
  289. goto CleanUp;
  290. }
  291. aSCMListStartupTypesCfg = (DWORD *) LocalAlloc (
  292. LMEM_ZEROINIT,
  293. sizeof(DWORD) * dwNumServices
  294. );
  295. if (aSCMListStartupTypes == NULL) {
  296. rc = ERROR_NOT_ENOUGH_MEMORY;
  297. goto CleanUp;
  298. }
  299. for (DWORD ServiceIndex=0; ServiceIndex < dwNumServices; ServiceIndex++ ) {
  300. SC_HANDLE hService = NULL;
  301. DWORD BytesNeeded = 0;
  302. LPQUERY_SERVICE_CONFIG pConfig = NULL;
  303. hService = OpenService(
  304. hScm,
  305. pInfo[ServiceIndex].lpServiceName,
  306. SERVICE_QUERY_CONFIG);
  307. if (hService == NULL) {
  308. rc = GetLastError();
  309. goto CleanUp;
  310. }
  311. if ( !QueryServiceConfig(
  312. hService,
  313. NULL,
  314. 0,
  315. &BytesNeeded
  316. ) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  317. rc = GetLastError();
  318. if (hService) {
  319. CloseServiceHandle(hService);
  320. hService = NULL;
  321. }
  322. goto CleanUp;
  323. }
  324. pConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(LMEM_ZEROINIT, BytesNeeded);
  325. if ( pConfig == NULL ) {
  326. rc = ERROR_NOT_ENOUGH_MEMORY;
  327. if (hService) {
  328. CloseServiceHandle(hService);
  329. hService = NULL;
  330. }
  331. goto CleanUp;
  332. }
  333. //
  334. // the real query of config
  335. //
  336. if ( !QueryServiceConfig(
  337. hService,
  338. pConfig,
  339. BytesNeeded,
  340. &BytesNeeded
  341. ) ) {
  342. rc = GetLastError();
  343. if (hService) {
  344. CloseServiceHandle(hService);
  345. hService = NULL;
  346. }
  347. if (pConfig) {
  348. LocalFree(pConfig);
  349. pConfig = NULL;
  350. }
  351. goto CleanUp;
  352. }
  353. aSCMListStartupTypes[ServiceIndex] = (BYTE)(pConfig->dwStartType);
  354. if (hService) {
  355. CloseServiceHandle(hService);
  356. hService = NULL;
  357. }
  358. if (pConfig) {
  359. LocalFree(pConfig);
  360. pConfig = NULL;
  361. }
  362. }
  363. //
  364. // configure all startup types for manual and automatic and the rest as disabled
  365. //
  366. //
  367. // first generate the rollback (basically a system snapshot - could be optimized)
  368. //
  369. //
  370. // Prepare SCE structure for generating a configuration template
  371. //
  372. WCHAR ppSceTemplateTypeFormat[10][10] = {
  373. L"2,\"\"",
  374. L"3,\"\"",
  375. L"4,\"\""
  376. };
  377. DWORD dwAllocSize = sizeof(SCESVC_CONFIGURATION_LINE) * dwNumServices;
  378. ServiceInfo.Lines = (PSCESVC_CONFIGURATION_LINE) LocalAlloc(
  379. LMEM_ZEROINIT,
  380. dwAllocSize
  381. );
  382. if (ServiceInfo.Lines == NULL) {
  383. rc = ERROR_NOT_ENOUGH_MEMORY;
  384. goto CleanUp;
  385. }
  386. for (DWORD ServiceIndex=0; ServiceIndex < dwNumServices; ServiceIndex++ ) {
  387. ServiceInfo.Lines[ServiceIndex].Key = pInfo[ServiceIndex].lpServiceName;
  388. ServiceInfo.Lines[ServiceIndex].Value = ppSceTemplateTypeFormat[aSCMListStartupTypes[ServiceIndex] - 2];
  389. ServiceInfo.Lines[ServiceIndex].ValueLen = sizeof(ppSceTemplateTypeFormat[aSCMListStartupTypes[ServiceIndex] - 2]);
  390. }
  391. rc = ::SceSvcSetInformationTemplate(
  392. bstrRollbackPath,
  393. szServiceGeneral,
  394. TRUE,
  395. &ServiceInfo
  396. );
  397. BOOL bFoundService;
  398. for (DWORD ServiceIndex=0; ServiceIndex < dwNumServices; ServiceIndex++ ) {
  399. bFoundService = FALSE;
  400. for (PSERVICE_NODE tempNode = m_headServiceList; tempNode != NULL; tempNode = tempNode->Next ) {
  401. if (_wcsicmp (tempNode->Name, pInfo[ServiceIndex].lpServiceName) == 0) {
  402. aSCMListStartupTypesCfg[ServiceIndex] = tempNode->dwStartupType;
  403. bFoundService = TRUE;
  404. }
  405. }
  406. if (bFoundService == FALSE) {
  407. //
  408. // stop services that are not found
  409. //
  410. aSCMListStartupTypesCfg[ServiceIndex] = 4;
  411. }
  412. }
  413. for (DWORD ServiceIndex=0; ServiceIndex < dwNumServices; ServiceIndex++ ) {
  414. ServiceInfo.Lines[ServiceIndex].Value = ppSceTemplateTypeFormat[aSCMListStartupTypesCfg[ServiceIndex] - 2];
  415. ServiceInfo.Lines[ServiceIndex].ValueLen = sizeof(ppSceTemplateTypeFormat[aSCMListStartupTypesCfg[ServiceIndex] - 2]);
  416. }
  417. rc = ::SceSvcSetInformationTemplate(
  418. bstrTemplatePath,
  419. szServiceGeneral,
  420. TRUE,
  421. &ServiceInfo
  422. );
  423. CleanUp:
  424. if (hScm)
  425. CloseServiceHandle(hScm);
  426. if (pInfo)
  427. LocalFree(pInfo);
  428. if (aSCMListStartupTypes)
  429. LocalFree (aSCMListStartupTypes);
  430. if (aSCMListStartupTypesCfg)
  431. LocalFree (aSCMListStartupTypesCfg);
  432. if (ServiceInfo.Lines)
  433. LocalFree(ServiceInfo.Lines);
  434. //
  435. // after we create the templates, we will clean them up
  436. //
  437. Cleanup();
  438. return rc;
  439. }
  440. HRESULT
  441. SceStatusToHRESULT (
  442. IN SCESTATUS SceStatus
  443. )
  444. /*++
  445. Routine Description:
  446. Name:
  447. SceStatusToHRESULT
  448. Functionality:
  449. converts SCESTATUS error code to dos error defined in winerror.h
  450. Virtual:
  451. N/A.
  452. Arguments:
  453. none.
  454. Return Value:
  455. HRESULT.
  456. Notes:
  457. --*/
  458. {
  459. switch(SceStatus) {
  460. case SCESTATUS_SUCCESS:
  461. return HRESULT_FROM_WIN32(NO_ERROR);
  462. case SCESTATUS_OTHER_ERROR:
  463. return HRESULT_FROM_WIN32(ERROR_EXTENDED_ERROR);
  464. case SCESTATUS_INVALID_PARAMETER:
  465. return HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  466. case SCESTATUS_RECORD_NOT_FOUND:
  467. return HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS);
  468. case SCESTATUS_NO_MAPPING:
  469. return HRESULT_FROM_WIN32(ERROR_NONE_MAPPED);
  470. case SCESTATUS_TRUST_FAIL:
  471. return HRESULT_FROM_WIN32(ERROR_TRUSTED_DOMAIN_FAILURE);
  472. case SCESTATUS_INVALID_DATA:
  473. return HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  474. case SCESTATUS_OBJECT_EXIST:
  475. return HRESULT_FROM_WIN32(ERROR_FILE_EXISTS);
  476. case SCESTATUS_BUFFER_TOO_SMALL:
  477. return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
  478. case SCESTATUS_PROFILE_NOT_FOUND:
  479. return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  480. case SCESTATUS_BAD_FORMAT:
  481. return HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
  482. case SCESTATUS_NOT_ENOUGH_RESOURCE:
  483. return HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY);
  484. case SCESTATUS_ACCESS_DENIED:
  485. return HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED);
  486. case SCESTATUS_CANT_DELETE:
  487. return HRESULT_FROM_WIN32(ERROR_CURRENT_DIRECTORY);
  488. case SCESTATUS_PREFIX_OVERFLOW:
  489. return HRESULT_FROM_WIN32(ERROR_BUFFER_OVERFLOW);
  490. case SCESTATUS_ALREADY_RUNNING:
  491. return HRESULT_FROM_WIN32(ERROR_SERVICE_ALREADY_RUNNING);
  492. case SCESTATUS_SERVICE_NOT_SUPPORT:
  493. return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
  494. case SCESTATUS_MOD_NOT_FOUND:
  495. return HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND);
  496. case SCESTATUS_EXCEPTION_IN_SERVER:
  497. return HRESULT_FROM_WIN32(ERROR_EXCEPTION_IN_SERVICE);
  498. default:
  499. return HRESULT_FROM_WIN32(ERROR_EXTENDED_ERROR);
  500. }
  501. }