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.

481 lines
13 KiB

  1. /*++
  2. Copyright (c) 1994-1995 Microsoft Corporation
  3. All rights reserved.
  4. Module Name:
  5. safewrap.cxx
  6. Abstract:
  7. This implements safe-wrappers for various system APIs.
  8. Author:
  9. Mark Lawrence (MLawrenc)
  10. Revision History:
  11. --*/
  12. #include "spllibp.hxx"
  13. #pragma hdrstop
  14. #include "splcom.h"
  15. #include "safewrap.hxx"
  16. /*++
  17. Routine Name:
  18. LoadLibraryFromSystem32
  19. Routine Description:
  20. Load the dll from system32 directory
  21. Arguments:
  22. lpLibFileName - Library file name
  23. Return Value:
  24. If the function succeeds, the return value is the handle;
  25. If the function fails, the return value is NULL. To get extended error
  26. information, call GetLastError.
  27. --*/
  28. HINSTANCE
  29. LoadLibraryFromSystem32(
  30. IN LPCTSTR lpLibFileName
  31. )
  32. {
  33. HINSTANCE hLib = NULL;
  34. static const TCHAR cszBackSlash[] = TEXT("\\");
  35. static const TCHAR cszSystem32[] = TEXT("system32\\");
  36. TCHAR szWindowDir[MAX_PATH];
  37. LPTSTR pszPath = NULL;
  38. DWORD dwWinDirLen = 0;
  39. if (dwWinDirLen = GetSystemWindowsDirectory (szWindowDir, MAX_PATH))
  40. {
  41. size_t cPathLen = dwWinDirLen + lstrlen (lpLibFileName) + COUNTOF (cszSystem32) + 2;
  42. pszPath = new TCHAR [cPathLen];
  43. if (pszPath)
  44. {
  45. StringCchCopy (pszPath, cPathLen, szWindowDir);
  46. if (szWindowDir[dwWinDirLen - 1] != cszBackSlash[0])
  47. {
  48. StringCchCat (pszPath, cPathLen, cszBackSlash);
  49. }
  50. StringCchCat (pszPath, cPathLen, cszSystem32);
  51. StringCchCat (pszPath, cPathLen, lpLibFileName);
  52. hLib = LoadLibrary(pszPath);
  53. }
  54. delete [] pszPath;
  55. }
  56. return hLib;
  57. }
  58. /*++
  59. Routine Name:
  60. SafeQueryValueAsStringPointer
  61. Routine Description:
  62. This does a query value on a string type. It guarantees:
  63. 1. The value retrieved is a REG_SZ.
  64. 2. The returned string is NULL terminated.
  65. Arguments:
  66. hKey - The key to retrieve the value from.
  67. pValueName - The value field.
  68. ppszString - The returned string, use FreeSplMem to free it.
  69. cchHint - A hint for the size of the buffer we would most likely need,
  70. use 0 if you have no idea, or don't care about two round
  71. trips.
  72. Return Value:
  73. An HRESULT - S_OK - Everything succeeded.
  74. S_FALSE - The string was read, but was not NULL terminated
  75. in the registry.
  76. --*/
  77. HRESULT
  78. SafeRegQueryValueAsStringPointer(
  79. IN HKEY hKey,
  80. IN PCWSTR pValueName,
  81. OUT PWSTR *ppszString,
  82. IN DWORD cchHint OPTIONAL
  83. )
  84. {
  85. HRESULT hr = pValueName && ppszString? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  86. DWORD cbData = 0;
  87. DWORD Type = 0;
  88. BOOL bTruncated = FALSE;
  89. BOOL bNullInRegistry = FALSE;
  90. PWSTR pszString = NULL;
  91. if (SUCCEEDED(hr))
  92. {
  93. if (cchHint)
  94. {
  95. pszString = reinterpret_cast<PWSTR>(AllocSplMem(cchHint * sizeof(WCHAR)));
  96. hr = pszString ? S_OK : HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  97. }
  98. }
  99. if (SUCCEEDED(hr))
  100. {
  101. cbData = cchHint * sizeof(WCHAR);
  102. hr = HResultFromWin32(RegQueryValueEx(hKey, pValueName, NULL, &Type, reinterpret_cast<BYTE *>(pszString), &cbData));
  103. //
  104. // This code in only unicode.
  105. //
  106. hr = SUCCEEDED(hr) ? (Type == REG_SZ && !(cbData & 0x01) ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_DATA)) : hr;
  107. }
  108. //
  109. // If this succeeded and we were passed a hint, then check and NULL terminate the string.
  110. //
  111. if (SUCCEEDED(hr) && pszString)
  112. {
  113. hr = CheckAndNullTerminateRegistryBuffer(pszString, cchHint, cbData / sizeof(WCHAR), &bTruncated, &bNullInRegistry);
  114. //
  115. // If we could not NULL terminate inside the buffer, then we will re-read using
  116. // the advertised registry buffer size
  117. //
  118. hr = SUCCEEDED(hr) ? (bTruncated ? HRESULT_FROM_WIN32(ERROR_MORE_DATA) : S_OK) : hr;
  119. }
  120. if (SUCCEEDED(hr))
  121. {
  122. if (pszString)
  123. {
  124. *ppszString = pszString;
  125. pszString = NULL;
  126. }
  127. else
  128. {
  129. hr = HRESULT_FROM_WIN32(ERROR_MORE_DATA);
  130. }
  131. }
  132. FreeSplMem(pszString);
  133. pszString = NULL;
  134. if (hr == HRESULT_FROM_WIN32(ERROR_MORE_DATA))
  135. {
  136. //
  137. // On our next read, we always add 1 to the buffer size. This is so that
  138. // we can be guaranteed of NULL termination (assuming the registry value
  139. // hasn't changed).
  140. //
  141. cchHint = (cbData + sizeof(WCHAR) - 1) / sizeof(WCHAR) + 1;
  142. pszString = reinterpret_cast<PWSTR>(AllocSplMem(cchHint * sizeof(WCHAR)));
  143. hr = pszString ? S_OK : HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  144. if (SUCCEEDED(hr))
  145. {
  146. cbData = cchHint * sizeof(WCHAR);
  147. hr = HResultFromWin32(RegQueryValueEx(hKey, pValueName, NULL, &Type, reinterpret_cast<BYTE *>(pszString), &cbData));
  148. hr = SUCCEEDED(hr) ? (Type == REG_SZ && !(cbData & 0x01) ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_DATA)) : hr;
  149. }
  150. if (SUCCEEDED(hr))
  151. {
  152. hr = CheckAndNullTerminateRegistryBuffer(pszString, cchHint, cbData / sizeof(WCHAR), &bTruncated, &bNullInRegistry);
  153. hr = SUCCEEDED(hr) ? (bTruncated ? HRESULT_FROM_WIN32(ERROR_INVALID_DATA) : S_OK) : hr;
  154. }
  155. if (SUCCEEDED(hr))
  156. {
  157. *ppszString = pszString;
  158. pszString = NULL;
  159. }
  160. }
  161. FreeSplMem(pszString);
  162. pszString = NULL;
  163. return SUCCEEDED(hr) ? (bNullInRegistry ? S_OK : S_FALSE) : hr;
  164. }
  165. /*++
  166. Routine Name:
  167. CheckAndNullTerminateRegistryBuffer
  168. Routine Description:
  169. This routine runs the buffer over the size returned by the registry backwards
  170. to find a NULL, if there is a NULL in the buffer, we return success, otherwise,
  171. if we can add a NULL within the buffer we do so. Otherwise, we truncate the string.
  172. Arguments:
  173. pszBuffer - The buffer we will bve checking.
  174. cchBuffer - The size of the buffer.
  175. cchRegBuffer - The size of the data returned from the registry.
  176. pbTruncated - If TRUE, the data was truncated, this will only happen
  177. if cchBuffer == cchRegBuffer.
  178. pbNullInRegistry - If TRUE, there was a NULL termination in the given buffer.
  179. Return Value:
  180. An HRESULT.
  181. --*/
  182. HRESULT
  183. CheckAndNullTerminateRegistryBuffer(
  184. IN PWSTR pszBuffer,
  185. IN UINT cchBuffer,
  186. IN UINT cchRegBuffer,
  187. OUT BOOL *pbTruncated,
  188. OUT BOOL *pbNullInRegistry
  189. )
  190. {
  191. HRESULT hr = pszBuffer && cchBuffer && cchRegBuffer <= cchBuffer && cchRegBuffer && pbTruncated && pbNullInRegistry
  192. ? S_OK : HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER);
  193. if (SUCCEEDED(hr))
  194. {
  195. UINT iRegScan = 0;
  196. //
  197. // Start at the end of the buffer and work backwards to find the NULL,
  198. // this is faster since the NULL is likely to be at the end.
  199. //
  200. for(iRegScan = cchRegBuffer; iRegScan > 0; iRegScan--)
  201. {
  202. if (!pszBuffer[iRegScan - 1])
  203. {
  204. break;
  205. }
  206. }
  207. //
  208. // If we reached the beginning of the buffer and there wasn't a NULL,
  209. // then see if we can NULL terminate ourselves.
  210. //
  211. if (!iRegScan)
  212. {
  213. *pbNullInRegistry = FALSE;
  214. if (cchBuffer > cchRegBuffer)
  215. {
  216. pszBuffer[cchRegBuffer] = L'\0';
  217. *pbTruncated = FALSE;
  218. }
  219. else
  220. {
  221. pszBuffer[cchRegBuffer - 1] = L'\0';
  222. *pbTruncated = TRUE;
  223. }
  224. }
  225. else
  226. {
  227. *pbNullInRegistry = TRUE;
  228. *pbTruncated = FALSE;
  229. }
  230. }
  231. return hr;
  232. }
  233. //
  234. // Test code follows
  235. //
  236. /*++
  237. Routine Name:
  238. TestNullTerminateRegistryBuffer
  239. Routine Description:
  240. This is test code for SafeRegQueryValueAsStringPointer. This code is not
  241. dead and functions as a validator for the above code.
  242. Arguments:
  243. None.
  244. Return Value:
  245. An HRESULT
  246. --*/
  247. HRESULT
  248. TestNullTerminateRegistryBuffer(
  249. VOID
  250. )
  251. {
  252. HRESULT hr = E_FAIL;
  253. //
  254. // This string must be quadword aligned or the registry does funky stuff
  255. // on the write.
  256. //
  257. const WCHAR NonNullString[] = { L'1', L'2', L'3', L'4', L'5', L'6', L'7', L'8' };
  258. const WCHAR NullString[] = L"1234567";
  259. const WCHAR EmptyString[] = L"";
  260. HKEY hKey = NULL;
  261. DWORD dwDisposition = 0;
  262. hr = HResultFromWin32(RegCreateKeyEx(HKEY_CURRENT_USER, L"StringTest", 0, NULL, 0, KEY_WRITE | KEY_READ, NULL, &hKey, &dwDisposition));
  263. if (SUCCEEDED(hr))
  264. {
  265. hr = SubTestVariations(hKey, L"NonNull", NonNullString, COUNTOF(NonNullString), L"12345678", S_FALSE);
  266. }
  267. if (SUCCEEDED(hr))
  268. {
  269. hr = SubTestVariations(hKey, L"Null", NullString, COUNTOF(NullString), NullString, S_OK);
  270. }
  271. if (SUCCEEDED(hr))
  272. {
  273. hr = SubTestVariations(hKey, L"Empty", EmptyString, COUNTOF(EmptyString), EmptyString, S_OK);
  274. }
  275. if (hKey)
  276. {
  277. RegCloseKey(hKey);
  278. }
  279. RegDeleteKey(HKEY_CURRENT_USER, L"StringTest");
  280. return hr;
  281. }
  282. /*++
  283. Routine Name:
  284. SubTestVariations
  285. Routine Description:
  286. This test a second set of standard variations depending on the string that
  287. is written into the registry.
  288. Arguments:
  289. hKey - The key we are writing to.
  290. pszValue - The value we are testing.
  291. pWriteBuffer - The buffer to write (may not be NULL-terminated)
  292. cchBuffer - The size of the buffer we are writing.
  293. pszCompareString - The string we expect to compare it against.
  294. hrExpected - The HR we expect from the function, must be a success code.
  295. Return Value:
  296. An HRESULT
  297. --*/
  298. HRESULT
  299. SubTestVariations(
  300. IN HKEY hKey,
  301. IN PCWSTR pszValue,
  302. IN PCWSTR pWriteBuffer,
  303. IN UINT cchBuffer,
  304. IN PCWSTR pszCompareString,
  305. IN HRESULT hrExpected
  306. )
  307. {
  308. HRESULT hr = hKey && pszValue && pWriteBuffer && pszCompareString && cchBuffer ? S_OK : E_INVALIDARG;
  309. PWSTR pszString = NULL;
  310. //
  311. // Write the string into the registry.
  312. //
  313. if (SUCCEEDED(hr))
  314. {
  315. hr = HResultFromWin32(RegSetValueExW(hKey, pszValue, 0, REG_SZ, reinterpret_cast<const BYTE *>(pWriteBuffer), cchBuffer * sizeof(pWriteBuffer[0])));
  316. }
  317. //
  318. // Variation 1, our hint buffer is 0.
  319. //
  320. if (SUCCEEDED(hr))
  321. {
  322. hr = SafeRegQueryValueAsStringPointer(hKey, pszValue, &pszString, 0);
  323. hr = hr == hrExpected && pszString ? (!wcscmp(pszString, pszCompareString) ? S_OK : E_FAIL) : (SUCCEEDED(hr) ? E_FAIL : hr);
  324. }
  325. FreeSplMem(pszString);
  326. pszString = NULL;
  327. //
  328. // Variation 2, our hint buffer is smaller than the reg size.
  329. //
  330. if (SUCCEEDED(hr))
  331. {
  332. hr = SafeRegQueryValueAsStringPointer(hKey, pszValue, &pszString, cchBuffer / 2);
  333. hr = hr == hrExpected && pszString ? (!wcscmp(pszString, pszCompareString) ? S_OK : E_FAIL) : (SUCCEEDED(hr) ? E_FAIL : hr);
  334. }
  335. FreeSplMem(pszString);
  336. pszString = NULL;
  337. //
  338. // Variation 3, our hint buffer is exactly the same size as the reg size.
  339. //
  340. if (SUCCEEDED(hr))
  341. {
  342. hr = SafeRegQueryValueAsStringPointer(hKey, pszValue, &pszString, cchBuffer);
  343. hr = hr == hrExpected && pszString ? (!wcscmp(pszString, pszCompareString) ? S_OK : E_FAIL) : (SUCCEEDED(hr) ? E_FAIL : hr);
  344. }
  345. //
  346. // Variation 4, our hint buffer is larger than the reg buffer.
  347. //
  348. FreeSplMem(pszString);
  349. pszString = NULL;
  350. if (SUCCEEDED(hr))
  351. {
  352. hr = SafeRegQueryValueAsStringPointer(hKey, pszValue, &pszString, cchBuffer * 2);
  353. hr = hr == hrExpected && pszString ? (!wcscmp(pszString, pszCompareString) ? S_OK : E_FAIL) : (SUCCEEDED(hr) ? E_FAIL : hr);
  354. }
  355. FreeSplMem(pszString);
  356. pszString = NULL;
  357. return hr;
  358. }