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.

369 lines
13 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: E X P O R T S . C P P
  7. //
  8. // Contents: Exported functions from NETCFG.DLL
  9. //
  10. // Notes:
  11. //
  12. // Author: danielwe 5 Dec 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. #include "ncreg.h"
  18. #include "ncsetup.h"
  19. #include "ncsvc.h"
  20. #define REGSTR_PATH_SVCHOST L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Svchost"
  21. HRESULT
  22. HrPrepareForSvchostEnum (
  23. IN PCWSTR pszService,
  24. IN OUT CServiceManager* pscm,
  25. IN OUT CService* psvc,
  26. OUT LPQUERY_SERVICE_CONFIG* ppOriginalConfig,
  27. OUT HKEY* phkeySvchost,
  28. OUT PWSTR* ppszValueNameBuffer,
  29. OUT DWORD* pcchValueNameBuffer,
  30. OUT PWSTR* ppmszValueBuffer,
  31. OUT DWORD* pcbValueBuffer)
  32. {
  33. // Initialize the output parameters.
  34. //
  35. *ppOriginalConfig = NULL;
  36. *phkeySvchost = NULL;
  37. *ppszValueNameBuffer = NULL;
  38. *pcchValueNameBuffer = 0;
  39. *ppmszValueBuffer = NULL;
  40. *pcbValueBuffer = 0;
  41. const DWORD dwScmAccess = STANDARD_RIGHTS_REQUIRED |
  42. SC_MANAGER_CONNECT |
  43. SC_MANAGER_LOCK;
  44. const DWORD dwSvcAccess = STANDARD_RIGHTS_REQUIRED |
  45. SERVICE_QUERY_CONFIG |
  46. SERVICE_CHANGE_CONFIG;
  47. // Open the service and lock the service database so we can change
  48. // the service's configuration.
  49. //
  50. HRESULT hr = pscm->HrOpenService (
  51. psvc,
  52. pszService,
  53. WITH_LOCK,
  54. dwScmAccess,
  55. dwSvcAccess);
  56. if (SUCCEEDED(hr))
  57. {
  58. // Query the service's current configuration in the event we
  59. // need to revert what we set.
  60. //
  61. LPQUERY_SERVICE_CONFIG pOriginalConfig;
  62. hr = psvc->HrQueryServiceConfig (&pOriginalConfig);
  63. if (SUCCEEDED(hr))
  64. {
  65. // Open the svchost software key and query information
  66. // about it like the length of the longest value name
  67. // and longest value.
  68. //
  69. HKEY hkeySvchost;
  70. hr = HrRegOpenKeyEx (
  71. HKEY_LOCAL_MACHINE, REGSTR_PATH_SVCHOST,
  72. KEY_READ | KEY_SET_VALUE,
  73. &hkeySvchost);
  74. if (SUCCEEDED(hr))
  75. {
  76. DWORD cchMaxValueNameLen;
  77. DWORD cbMaxValueLen;
  78. LONG lr = RegQueryInfoKeyW (hkeySvchost,
  79. NULL, // lpClass
  80. NULL, // lpcbClass
  81. NULL, // lpReserved
  82. NULL, // lpcSubKeys
  83. NULL, // lpcbMaxSubKeyLen
  84. NULL, // lpcbMaxClassLen
  85. NULL, // lpcValues
  86. &cchMaxValueNameLen,
  87. &cbMaxValueLen,
  88. NULL, // lpcbSecurityDescriptor
  89. NULL // lpftLastWriteTime
  90. );
  91. hr = HRESULT_FROM_WIN32 (lr);
  92. if (SUCCEEDED(hr))
  93. {
  94. // Make sure the name buffer length (in bytes) is a
  95. // multiple of sizeof(WCHAR). This is because we expect
  96. // to use RegEnumValue which accepts and returns buffer
  97. // size in characters. We tell it the the buffer
  98. // capacity (in characters) is count of bytes divided
  99. // by sizeof(WCHAR). So, to avoid any round off
  100. // error (which would not occur in our favor) we make
  101. // sure that the buffer size is a multiple of
  102. // sizeof(WCHAR).
  103. //
  104. INT cbFraction = cbMaxValueLen % sizeof(WCHAR);
  105. if (cbFraction)
  106. {
  107. cbMaxValueLen += sizeof(WCHAR) - cbFraction;
  108. }
  109. // Need room for the null terminator as RegQueryInfoKey
  110. // doesn't return it.
  111. //
  112. cchMaxValueNameLen++;
  113. // Allocate buffers for the longest value name and value
  114. // data for our caller to use.
  115. //
  116. PWSTR pszValueNameBuffer = (PWSTR)
  117. MemAlloc (cchMaxValueNameLen * sizeof(WCHAR));
  118. PWSTR pmszValueBuffer = (PWSTR) MemAlloc (cbMaxValueLen);
  119. if ((pszValueNameBuffer != NULL) &&
  120. (pmszValueBuffer != NULL))
  121. {
  122. *ppOriginalConfig = pOriginalConfig;
  123. *phkeySvchost = hkeySvchost;
  124. *ppszValueNameBuffer = pszValueNameBuffer;
  125. *pcchValueNameBuffer = cchMaxValueNameLen;
  126. *ppmszValueBuffer = pmszValueBuffer;
  127. *pcbValueBuffer = cbMaxValueLen;
  128. hr = S_OK;
  129. }
  130. else
  131. {
  132. hr = E_OUTOFMEMORY;
  133. }
  134. }
  135. if (FAILED(hr))
  136. {
  137. RegCloseKey (hkeySvchost);
  138. }
  139. }
  140. if (FAILED(hr))
  141. {
  142. MemFree (pOriginalConfig);
  143. }
  144. }
  145. }
  146. TraceError ("HrPrepareForSvchostEnum", hr);
  147. return hr;
  148. }
  149. STDAPI
  150. SvchostChangeSvchostGroup (
  151. PCWSTR pszService,
  152. PCWSTR pszNewGroup
  153. )
  154. {
  155. Assert (pszService);
  156. Assert (pszNewGroup);
  157. static const WCHAR c_pszBasePath [] =
  158. L"%SystemRoot%\\System32\\svchost.exe -k ";
  159. // Validate the new group name by making sure it doesn't exceed
  160. // MAX_PATH when combined with the base path.
  161. //
  162. if (!pszService || !pszNewGroup ||
  163. !*pszService || !*pszNewGroup ||
  164. (lstrlenW (c_pszBasePath) + lstrlenW (pszNewGroup) > MAX_PATH))
  165. {
  166. return E_INVALIDARG;
  167. }
  168. // Form the new image path based on the base path and the new group
  169. // name.
  170. //
  171. WCHAR pszImagePath [MAX_PATH + 1];
  172. lstrcpyW (pszImagePath, c_pszBasePath);
  173. lstrcatW (pszImagePath, pszNewGroup);
  174. // Need to change the ImagePath of the service as well as the
  175. // Svchost Group values. The implementation tries to ensure that
  176. // both of these changes are made or neither of them are made.
  177. //
  178. // Prepare for the enumeration by setting up a few pieces of information
  179. // first. HrPrepareForSvchostEnum sets up all of these variables.
  180. //
  181. // SCM is opened and locked, pszService is opened for config change.
  182. //
  183. CServiceManager scm;
  184. CService svc;
  185. // pszService's current configration is obtained in the event we
  186. // need to rollback, we'll use this info to reset the ImagePath.
  187. //
  188. LPQUERY_SERVICE_CONFIG pOriginalConfig;
  189. // hkeySvcHost is opened at REGSTR_PATH_SVCHOST and is used to
  190. // enumerate the values under it.
  191. //
  192. HKEY hkeySvcHost;
  193. // These buffers are allocated so that RegEnumValue will have a place
  194. // to store what was enumerated.
  195. //
  196. PWSTR pszValueNameBuffer;
  197. DWORD cchValueNameBuffer;
  198. PWSTR pmszValueBuffer;
  199. DWORD cbValueBuffer;
  200. HRESULT hr = HrPrepareForSvchostEnum (
  201. pszService,
  202. &scm,
  203. &svc,
  204. &pOriginalConfig,
  205. &hkeySvcHost,
  206. &pszValueNameBuffer,
  207. &cchValueNameBuffer,
  208. &pmszValueBuffer,
  209. &cbValueBuffer);
  210. if (SUCCEEDED(hr))
  211. {
  212. // Set the new image path of the service.
  213. //
  214. hr = svc.HrSetImagePath (pszImagePath);
  215. if (SUCCEEDED(hr))
  216. {
  217. // fAddNewValue will be set to FALSE if we've found an existing
  218. // group name value.
  219. //
  220. BOOL fAddNewValue = TRUE;
  221. BOOL fChanged;
  222. // Now perform the enumeration. For each value enumerated,
  223. // make sure the service name is included in the multi-sz
  224. // for the valuename that matches the new group name. For all
  225. // other values, make sure the service name is not included
  226. // in the multi-sz.
  227. //
  228. DWORD dwIndex = 0;
  229. do
  230. {
  231. DWORD dwType;
  232. DWORD cchValueName = cchValueNameBuffer;
  233. DWORD cbValue = cbValueBuffer;
  234. hr = HrRegEnumValue (hkeySvcHost, dwIndex,
  235. pszValueNameBuffer, &cchValueName,
  236. &dwType,
  237. (LPBYTE)pmszValueBuffer, &cbValue);
  238. if (SUCCEEDED(hr) && (REG_MULTI_SZ == dwType))
  239. {
  240. // If we find a value that matches the group name,
  241. // make sure the service is a part of the mutli-sz
  242. // value.
  243. //
  244. if (0 == lstrcmpiW (pszNewGroup, pszValueNameBuffer))
  245. {
  246. // Since we found an existing group name, we don't
  247. // need to add a new one.
  248. //
  249. fAddNewValue = FALSE;
  250. PWSTR pmszNewValue;
  251. hr = HrAddSzToMultiSz (pszService,
  252. pmszValueBuffer,
  253. STRING_FLAG_DONT_MODIFY_IF_PRESENT |
  254. STRING_FLAG_ENSURE_AT_END,
  255. 0,
  256. &pmszNewValue,
  257. &fChanged);
  258. if (SUCCEEDED(hr) && fChanged)
  259. {
  260. hr = HrRegSetMultiSz (hkeySvcHost,
  261. pszNewGroup,
  262. pmszNewValue);
  263. MemFree (pmszNewValue);
  264. }
  265. }
  266. // Otherwise, since the value does not match the group
  267. // name, make sure the service is NOT part of the
  268. // mutli-sz value.
  269. //
  270. else
  271. {
  272. RemoveSzFromMultiSz (pszService,
  273. pmszValueBuffer, STRING_FLAG_REMOVE_ALL,
  274. &fChanged);
  275. if (fChanged)
  276. {
  277. hr = HrRegSetMultiSz (hkeySvcHost,
  278. pszValueNameBuffer,
  279. pmszValueBuffer);
  280. }
  281. }
  282. }
  283. else if (HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS) == hr)
  284. {
  285. hr = S_OK;
  286. break;
  287. }
  288. dwIndex++;
  289. }
  290. while (S_OK == hr);
  291. // If we need to add a new group name, do so.
  292. //
  293. if (SUCCEEDED(hr) && fAddNewValue)
  294. {
  295. // Add pszService to a empty multi-sz. This has the effect
  296. // of creating a multi-sz from a single string.
  297. //
  298. PWSTR pmszNewValue;
  299. hr = HrAddSzToMultiSz (pszService,
  300. NULL,
  301. STRING_FLAG_ENSURE_AT_END, 0,
  302. &pmszNewValue, &fChanged);
  303. if (S_OK == hr)
  304. {
  305. // We know that it should have been added, so assert
  306. // that the multi-sz "changed".
  307. //
  308. Assert (fChanged);
  309. // Add the new value by setting the multi-sz in the
  310. // registry.
  311. //
  312. hr = HrRegSetMultiSz (hkeySvcHost,
  313. pszNewGroup,
  314. pmszNewValue);
  315. MemFree (pmszNewValue);
  316. }
  317. }
  318. }
  319. RegCloseKey (hkeySvcHost);
  320. MemFree (pmszValueBuffer);
  321. MemFree (pszValueNameBuffer);
  322. MemFree (pOriginalConfig);
  323. }
  324. TraceError ("SvchostChangeSvchostGroup", hr);
  325. return hr;
  326. }