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.

530 lines
18 KiB

  1. /*
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. RegQueryValueEx.cpp
  5. Abstract:
  6. This DLL hooks RegQueryValueExA so that we can return the "all-users" location
  7. for the StartMenu, Desktop and Startup folders instead of the per-user location.
  8. We also hook RegCreateKeyA/RegCreateKeyExA to make people who add entries to the
  9. HKCU "run" and "Uninstall" keys really add them to HKLM.
  10. Notes:
  11. History:
  12. 08/07/2000 reinerf Created
  13. 02/27/2001 robkenny Converted to use CString
  14. 02/14/2002 mnikkel Changed from legalstr.h to strsafe.h
  15. */
  16. #include "precomp.h"
  17. IMPLEMENT_SHIM_BEGIN(ProfilesRegQueryValueEx)
  18. #include "ShimHookMacro.h"
  19. APIHOOK_ENUM_BEGIN
  20. APIHOOK_ENUM_ENTRY(RegQueryValueExA)
  21. APIHOOK_ENUM_ENTRY(RegCreateKeyA)
  22. APIHOOK_ENUM_ENTRY(RegCreateKeyExA)
  23. APIHOOK_ENUM_ENTRY(RegOpenKeyA)
  24. APIHOOK_ENUM_ENTRY(RegOpenKeyExA)
  25. APIHOOK_ENUM_END
  26. #ifndef MAX
  27. #define MAX(x,y) (((x) > (y)) ? (x) : (y))
  28. #endif
  29. #ifndef ARRAYSIZE
  30. #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0]))
  31. #endif
  32. LPCSTR g_aBadKeys[] =
  33. {
  34. {"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"},
  35. {"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"},
  36. };
  37. LPCSTR g_aBadShellFolderKeys[] =
  38. {
  39. {"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders"},
  40. {"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders"},
  41. };
  42. // given an hkey, call NtQueryObject to lookup its name.
  43. // returns strings in the format: "\REGISTRY\USER\S-1-5-xxxxx\Software\Microsoft\Windows\CurrentVersion"
  44. BOOL GetKeyName(HKEY hk, LPSTR pszName, DWORD cchName)
  45. {
  46. BOOL bRet = FALSE;
  47. ULONG cbSize = 0;
  48. // get the size needed for the name buffer
  49. NtQueryObject(hk, ObjectNameInformation, NULL, 0, &cbSize);
  50. if (cbSize)
  51. {
  52. POBJECT_NAME_INFORMATION pNameInfo = (POBJECT_NAME_INFORMATION)LocalAlloc(LPTR, cbSize);
  53. if (pNameInfo)
  54. {
  55. NTSTATUS status = NtQueryObject(hk, ObjectNameInformation, (void*)pNameInfo, cbSize, NULL);
  56. if (NT_SUCCESS(status) && WideCharToMultiByte(CP_ACP, 0, pNameInfo->Name.Buffer, -1, pszName, cchName, NULL, NULL))
  57. {
  58. bRet = TRUE;
  59. }
  60. LocalFree(pNameInfo);
  61. }
  62. }
  63. return bRet;
  64. }
  65. // If hk points underneath HKCU and matches pszSearchName, then return TRUE
  66. BOOL DoesKeyMatch(HKEY hk, LPCSTR pszSearchName)
  67. {
  68. BOOL bRet = FALSE;
  69. // make sure it is not one of the pre-defined keys (eg HKEY_LOCAL_MACHINE)
  70. if (!((LONG)((ULONG_PTR)hk) & 0x80000000))
  71. {
  72. CHAR szKeyName[MAX_PATH * 2]; // should be big enought to hold any registry key path
  73. if (GetKeyName(hk, szKeyName, ARRAYSIZE(szKeyName)))
  74. {
  75. // is the key under HKCU ?
  76. if (StrCmpNIA(szKeyName, "\\REGISTRY\\USER\\", ARRAYSIZE("\\REGISTRY\\USER\\")-1) == 0)
  77. {
  78. LPSTR psz = StrRStrIA(szKeyName, NULL, pszSearchName);
  79. if (psz && (lstrlenA(psz) == lstrlenA(pszSearchName)))
  80. {
  81. // we found a substring and its the same length, so our hkey matches the search!
  82. bRet = TRUE;
  83. }
  84. }
  85. }
  86. }
  87. return bRet;
  88. }
  89. BOOL IsBadHKCUKey(HKEY hk, LPCSTR* ppszNewKey)
  90. {
  91. BOOL bRet = FALSE;
  92. int i;
  93. for (i=0; i < ARRAYSIZE(g_aBadKeys); i++)
  94. {
  95. if (DoesKeyMatch(hk, g_aBadKeys[i]))
  96. {
  97. *ppszNewKey = g_aBadKeys[i];
  98. bRet = TRUE;
  99. break;
  100. }
  101. }
  102. return bRet;
  103. }
  104. BOOL IsBadShellFolderKey(HKEY hk, LPCSTR* ppszNewKey)
  105. {
  106. BOOL bRet = FALSE;
  107. int i;
  108. for (i=0; i < ARRAYSIZE(g_aBadShellFolderKeys); i++)
  109. {
  110. if (DoesKeyMatch(hk, g_aBadShellFolderKeys[i]))
  111. {
  112. *ppszNewKey = g_aBadShellFolderKeys[i];
  113. bRet = TRUE;
  114. break;
  115. }
  116. }
  117. return bRet;
  118. }
  119. LONG
  120. APIHOOK(RegCreateKeyA)(
  121. HKEY hKey,
  122. LPCSTR pszSubKey,
  123. PHKEY phkResult
  124. )
  125. {
  126. LPCSTR pszNewHKLMKey;
  127. LONG lRet = ORIGINAL_API(RegCreateKeyA)(hKey, pszSubKey, phkResult);
  128. if ((lRet == ERROR_SUCCESS) &&
  129. IsBadHKCUKey(*phkResult, &pszNewHKLMKey))
  130. {
  131. // its a bad HKCU key-- redirect to HKLM
  132. RegCloseKey(*phkResult);
  133. lRet = ORIGINAL_API(RegCreateKeyA)(HKEY_LOCAL_MACHINE, pszNewHKLMKey, phkResult);
  134. LOGN(eDbgLevelInfo, "[RegCreateKeyA] overriding \"%s\" create key request w/ HKLM value (return = %d)", pszSubKey, lRet);
  135. }
  136. return lRet;
  137. }
  138. LONG
  139. APIHOOK(RegCreateKeyExA)(
  140. HKEY hKey,
  141. LPCSTR pszSubKey,
  142. DWORD Reserved,
  143. LPSTR lpClass,
  144. DWORD dwOptions,
  145. REGSAM samDesired,
  146. LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  147. PHKEY phkResult,
  148. LPDWORD lpdwDisposition
  149. )
  150. {
  151. LPCSTR pszNewHKLMKey;
  152. LONG lRet = ORIGINAL_API(RegCreateKeyExA)(hKey,
  153. pszSubKey,
  154. Reserved,
  155. lpClass,
  156. dwOptions,
  157. samDesired,
  158. lpSecurityAttributes,
  159. phkResult,
  160. lpdwDisposition);
  161. if ((lRet == ERROR_SUCCESS) &&
  162. IsBadHKCUKey(*phkResult, &pszNewHKLMKey))
  163. {
  164. // its a bad HCKU key-- redirect to HKLM
  165. RegCloseKey(*phkResult);
  166. lRet = ORIGINAL_API(RegCreateKeyExA)(HKEY_LOCAL_MACHINE,
  167. pszNewHKLMKey,
  168. Reserved,
  169. lpClass,
  170. dwOptions,
  171. samDesired,
  172. lpSecurityAttributes,
  173. phkResult,
  174. lpdwDisposition);
  175. LOGN(eDbgLevelInfo, "[RegCreateKeyExA] overriding \"%s\" create key request w/ HKLM value (return = %d)", pszSubKey, lRet);
  176. }
  177. return lRet;
  178. }
  179. LONG
  180. APIHOOK(RegOpenKeyA)(
  181. HKEY hKey,
  182. LPCSTR pszSubKey,
  183. PHKEY phkResult
  184. )
  185. {
  186. LPCSTR pszNewHKLMKey;
  187. LONG lRet = ORIGINAL_API(RegOpenKeyA)(hKey, pszSubKey, phkResult);
  188. if ((lRet == ERROR_SUCCESS) &&
  189. IsBadHKCUKey(*phkResult, &pszNewHKLMKey))
  190. {
  191. // its a bad HCKU key-- redirect to HKLM
  192. RegCloseKey(*phkResult);
  193. lRet = ORIGINAL_API(RegOpenKeyA)(HKEY_LOCAL_MACHINE, pszNewHKLMKey, phkResult);
  194. LOGN(eDbgLevelInfo, "[RegOpenKeyA] overriding \"%s\" create key request w/ HKLM value (return = %d)", pszSubKey, lRet);
  195. }
  196. return lRet;
  197. }
  198. LONG
  199. APIHOOK(RegOpenKeyExA)(
  200. HKEY hKey,
  201. LPCSTR pszSubKey,
  202. DWORD ulOptions,
  203. REGSAM samDesired,
  204. PHKEY phkResult
  205. )
  206. {
  207. LPCSTR pszNewHKLMKey;
  208. LONG lRet = ORIGINAL_API(RegOpenKeyExA)(hKey, pszSubKey, ulOptions, samDesired, phkResult);
  209. if ((lRet == ERROR_SUCCESS) &&
  210. IsBadHKCUKey(*phkResult, &pszNewHKLMKey))
  211. {
  212. // its a bad HCKU key-- redirect to HKLM
  213. RegCloseKey(*phkResult);
  214. lRet = ORIGINAL_API(RegOpenKeyExA)(HKEY_LOCAL_MACHINE, pszNewHKLMKey, ulOptions, samDesired, phkResult);
  215. LOGN(eDbgLevelInfo, "[RegOpenKeyExA] overriding \"%s\" create key request w/ HKLM value (return = %d)", pszSubKey, lRet);
  216. }
  217. return lRet;
  218. }
  219. LONG
  220. GetAllUsersRegValueA(
  221. LPSTR szRegValue,
  222. DWORD cbOriginal,
  223. DWORD* pcbData,
  224. int nFolder,
  225. int nFolderCommon
  226. )
  227. {
  228. LONG lRet = ERROR_SUCCESS;
  229. if (!szRegValue)
  230. {
  231. // if the caller is querying for the necessary size, return the "worst case" since we don't know if
  232. // we are going to have to lie or not
  233. *pcbData = MAX_PATH;
  234. }
  235. else if (szRegValue[0] != '\0')
  236. {
  237. CHAR szPath[MAX_PATH];
  238. if (SUCCEEDED(SHGetFolderPathA(NULL, nFolder, NULL, SHGFP_TYPE_CURRENT, szPath))) {
  239. CHAR szShortRegPath[MAX_PATH];
  240. CHAR szShortGSFPath[MAX_PATH];
  241. BOOL bUseLFN = FALSE;
  242. BOOL bSame = FALSE;
  243. if (lstrcmpiA(szPath, szRegValue) == 0) {
  244. bSame = TRUE;
  245. bUseLFN = TRUE;
  246. } else {
  247. DWORD dwSize = GetShortPathNameA(szPath, szShortGSFPath, ARRAYSIZE(szShortGSFPath));
  248. DWORD dwSize2= GetShortPathNameA(szRegValue, szShortRegPath, ARRAYSIZE(szShortRegPath));
  249. if (dwSize > 0 && dwSize < ARRAYSIZE(szShortGSFPath) &&
  250. dwSize2 > 0 && dwSize < ARRAYSIZE(szShortRegPath) &&
  251. lstrcmpiA(szShortGSFPath, szShortRegPath) == 0 ) {
  252. bSame = TRUE;
  253. //
  254. // Since the sfn was returned, use that to copy over the output buffer.
  255. //
  256. bUseLFN = FALSE;
  257. }
  258. }
  259. if (bSame && SUCCEEDED(SHGetFolderPathA(NULL, nFolderCommon, NULL, SHGFP_TYPE_CURRENT, szPath))) {
  260. if (bUseLFN) {
  261. if ((lstrlenA(szPath) + 1) <= (int)cbOriginal) {
  262. LOGN(
  263. eDbgLevelInfo,
  264. "[GetAllUsersRegValueA] overriding per-user reg value w/ common value");
  265. StringCchCopyA(szRegValue, MAX_PATH, szPath);
  266. } else {
  267. LOGN(
  268. eDbgLevelInfo,
  269. "[GetAllUsersRegValueA] returning ERROR_MORE_DATA for special folder value");
  270. lRet = ERROR_MORE_DATA;
  271. }
  272. //
  273. // Either we used this much room, or this is how much we need to have.
  274. //
  275. *pcbData = lstrlenA(szPath) + 1;
  276. } else {
  277. DWORD dwSize = GetShortPathNameA(szPath, szShortGSFPath, ARRAYSIZE(szShortGSFPath));
  278. if (dwSize > 0 && dwSize < ARRAYSIZE(szShortGSFPath)) {
  279. if ((lstrlenA(szShortGSFPath) + 1) <= (int)cbOriginal) {
  280. LOGN(
  281. eDbgLevelInfo,
  282. "[GetAllUsersRegValueA] overriding per-user reg value w/ common value");
  283. StringCchCopyA(szRegValue, cbOriginal, szShortGSFPath);
  284. } else {
  285. LOGN(
  286. eDbgLevelInfo,
  287. "[GetAllUsersRegValueA] returning ERROR_MORE_DATA for special folder value");
  288. lRet = ERROR_MORE_DATA;
  289. }
  290. //
  291. // Either we used this much room, or this is how much we need to have.
  292. //
  293. *pcbData = lstrlenA(szShortGSFPath) + 1;
  294. }
  295. }
  296. }
  297. }
  298. }
  299. return lRet;
  300. }
  301. //
  302. // If the app is asking for the per-user "Desktop", "Start Menu" or "Startup" values by
  303. // groveling the registry, then redirect it to the proper per-machine values.
  304. //
  305. LONG
  306. APIHOOK(RegQueryValueExA)(
  307. HKEY hKey, // handle to key
  308. LPCSTR lpValueName, // value name
  309. LPDWORD lpReserved, // reserved
  310. LPDWORD lpType, // type buffer
  311. LPBYTE lpData, // data buffer
  312. LPDWORD lpcbData // size of data buffer
  313. )
  314. {
  315. DWORD cbOriginal = (lpcbData ? *lpcbData : 0); // save off the original buffer size
  316. LPCSTR pszNewHKLMKey;
  317. LONG lRet = ORIGINAL_API(RegQueryValueExA)(hKey,
  318. lpValueName,
  319. lpReserved,
  320. lpType,
  321. lpData,
  322. lpcbData);
  323. if ((lpValueName && lpcbData) && // (not simply checking for existance of the value...)
  324. IsBadShellFolderKey(hKey, &pszNewHKLMKey))
  325. {
  326. CHAR szTemp[MAX_PATH];
  327. if (CompareStringA(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_NEUTRAL),SORT_DEFAULT),
  328. NORM_IGNORECASE, lpValueName, -1,
  329. "Desktop",-1) == CSTR_EQUAL) {
  330. DPFN(
  331. eDbgLevelInfo,
  332. "[RegQueryValueExA] querying for 'Desktop' value\n");
  333. if (lRet == ERROR_SUCCESS) {
  334. lRet = GetAllUsersRegValueA((LPSTR)lpData,
  335. cbOriginal,
  336. lpcbData,
  337. CSIDL_DESKTOP,
  338. CSIDL_COMMON_DESKTOPDIRECTORY);
  339. } else if (lRet == ERROR_MORE_DATA) {
  340. if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, NULL, SHGFP_TYPE_CURRENT, szTemp))) {
  341. *lpcbData = MAX(*lpcbData, (DWORD)((lstrlenA(szTemp) + 1) * sizeof(CHAR)));
  342. }
  343. }
  344. } else if (CompareStringA(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_NEUTRAL),SORT_DEFAULT),
  345. NORM_IGNORECASE, lpValueName, -1,
  346. "Start Menu",-1) == CSTR_EQUAL) {
  347. DPFN(
  348. eDbgLevelInfo,
  349. "[RegQueryValueExA] querying for 'Start Menu' value\n");
  350. if (lRet == ERROR_SUCCESS) {
  351. lRet = GetAllUsersRegValueA((LPSTR)lpData,
  352. cbOriginal,
  353. lpcbData,
  354. CSIDL_STARTMENU,
  355. CSIDL_COMMON_STARTMENU);
  356. } else if (lRet == ERROR_MORE_DATA) {
  357. if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_STARTMENU, NULL, SHGFP_TYPE_CURRENT, szTemp))) {
  358. *lpcbData = MAX(*lpcbData, (DWORD)((lstrlenA(szTemp) + 1) * sizeof(CHAR)));
  359. }
  360. }
  361. } else if (CompareStringA(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_NEUTRAL),SORT_DEFAULT),
  362. NORM_IGNORECASE, lpValueName, -1,
  363. "Startup",-1) == CSTR_EQUAL) {
  364. DPFN(
  365. eDbgLevelInfo,
  366. "[RegQueryValueExA] querying for 'Startup' value\n");
  367. if (lRet == ERROR_SUCCESS) {
  368. lRet = GetAllUsersRegValueA((LPSTR)lpData, cbOriginal, lpcbData, CSIDL_STARTUP, CSIDL_COMMON_STARTUP);
  369. } else if (lRet == ERROR_MORE_DATA) {
  370. if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_STARTUP, NULL, SHGFP_TYPE_CURRENT, szTemp))) {
  371. *lpcbData = MAX(*lpcbData, (DWORD)((lstrlenA(szTemp) + 1) * sizeof(CHAR)));
  372. }
  373. }
  374. } else if (CompareStringA(MAKELCID(MAKELANGID(LANG_ENGLISH,SUBLANG_NEUTRAL),SORT_DEFAULT),
  375. NORM_IGNORECASE, lpValueName, -1,
  376. "Programs",-1) == CSTR_EQUAL) {
  377. DPFN(
  378. eDbgLevelInfo,
  379. "[RegQueryValueExA] querying for 'Programs' value\n");
  380. if (lRet == ERROR_SUCCESS) {
  381. lRet = GetAllUsersRegValueA((LPSTR)lpData, cbOriginal, lpcbData, CSIDL_PROGRAMS, CSIDL_COMMON_PROGRAMS);
  382. } else if (lRet == ERROR_MORE_DATA) {
  383. if (SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_COMMON_PROGRAMS, NULL, SHGFP_TYPE_CURRENT, szTemp))) {
  384. *lpcbData = MAX(*lpcbData, (DWORD)((lstrlenA(szTemp) + 1) * sizeof(CHAR)));
  385. }
  386. }
  387. }
  388. }
  389. return lRet;
  390. }
  391. BOOL
  392. NOTIFY_FUNCTION(
  393. DWORD fdwReason
  394. )
  395. {
  396. if (fdwReason == DLL_PROCESS_ATTACH) {
  397. OSVERSIONINFOEX osvi = {0};
  398. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  399. if (GetVersionEx((OSVERSIONINFO*)&osvi)) {
  400. if (!((VER_SUITE_TERMINAL & osvi.wSuiteMask) &&
  401. !(VER_SUITE_SINGLEUSERTS & osvi.wSuiteMask))) {
  402. //
  403. // Only install hooks if we are not on a "Terminal Server"
  404. // (aka "Application Server") machine.
  405. //
  406. APIHOOK_ENTRY(ADVAPI32.DLL, RegQueryValueExA);
  407. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyA);
  408. APIHOOK_ENTRY(ADVAPI32.DLL, RegCreateKeyExA);
  409. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyA);
  410. APIHOOK_ENTRY(ADVAPI32.DLL, RegOpenKeyExA);
  411. }
  412. }
  413. }
  414. return TRUE;
  415. }
  416. HOOK_BEGIN
  417. CALL_NOTIFY_FUNCTION
  418. HOOK_END
  419. IMPLEMENT_SHIM_END