Source code of Windows XP (NT5)
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.

346 lines
7.9 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Environment.Cpp
  5. Abstract:
  6. Various environment-related function
  7. Notes:
  8. Cloning environment for the purpose of using it in Rtl* environment-related functions
  9. History:
  10. 10/26/00 VadimB Created
  11. --*/
  12. #include "precomp.h"
  13. // This module has been given an official blessing to use the str routines.
  14. #include "LegalStr.h"
  15. IMPLEMENT_SHIM_BEGIN(Win2kPropagateLayer)
  16. #include "ShimHookMacro.h"
  17. #include "Win2kPropagateLayer.h"
  18. //
  19. // This is so we can compare offsets if we know the segments are equal
  20. //
  21. #define OFFSET(x) (LOWORD((DWORD)(x)))
  22. //
  23. // I'm cheating here to make some functions a little faster;
  24. // we won't have to push a word on the stack every time
  25. //
  26. static WORD gwMatch;
  27. //
  28. // ChrCmp - Case sensitive character comparison for DBCS
  29. // Assumes w1, gwMatch are characters to be compared
  30. // Return FALSE if they match, TRUE if no match
  31. //
  32. static BOOL ChrCmp( WORD w1 )
  33. {
  34. //
  35. // Most of the time this won't match, so test it first for speed.
  36. //
  37. if( LOBYTE( w1 ) == LOBYTE( gwMatch ) )
  38. {
  39. if( IsDBCSLeadByte( LOBYTE( w1 ) ) )
  40. {
  41. return( w1 != gwMatch );
  42. }
  43. return FALSE;
  44. }
  45. return TRUE;
  46. }
  47. //
  48. // StrRChr - Find last occurrence of character in string
  49. // Assumes lpStart points to start of string
  50. // lpEnd points to end of string (NOT included in search)
  51. // wMatch is the character to match
  52. // returns ptr to the last occurrence of ch in str, NULL if not found.
  53. //
  54. static LPSTR StrRChr( LPSTR lpStart, LPSTR lpEnd, WORD wMatch )
  55. {
  56. LPSTR lpFound = NULL;
  57. if( !lpEnd )
  58. lpEnd = lpStart + strlen( lpStart );
  59. gwMatch = wMatch;
  60. for( ; OFFSET( lpStart ) < OFFSET( lpEnd ); lpStart = CharNextA( lpStart ) )
  61. {
  62. if( !ChrCmp( *(LPWORD)lpStart ) )
  63. lpFound = lpStart;
  64. }
  65. return( lpFound );
  66. }
  67. //
  68. // Find environment variable pszName within the buffer pszEnv
  69. // ppszVal receives pointer to the variable's value
  70. //
  71. PSZ
  72. ShimFindEnvironmentVar(
  73. PSZ pszName,
  74. PSZ pszEnv,
  75. PSZ* ppszVal
  76. )
  77. {
  78. int nNameLen = strlen(pszName);
  79. PSZ pTemp;
  80. if (pszEnv != NULL) {
  81. while (*pszEnv != '\0') {
  82. //
  83. // Check the first char to be speedy.
  84. //
  85. if (*pszName == *pszEnv) {
  86. //
  87. // Compare the rest now.
  88. //
  89. if ((pTemp = StrRChr(pszEnv, NULL, '=')) != NULL &&
  90. (int)(pTemp - pszEnv) == nNameLen &&
  91. !_strnicmp(pszEnv, pszName, nNameLen)) {
  92. //
  93. // Found it.
  94. //
  95. if (ppszVal != NULL) {
  96. *ppszVal = pTemp + 1;
  97. }
  98. return pszEnv;
  99. }
  100. }
  101. pszEnv += strlen(pszEnv) + 1;
  102. }
  103. }
  104. return NULL;
  105. }
  106. //
  107. // returns size in characters
  108. // of an env block
  109. // pStrCount receives the number of env strings
  110. //
  111. DWORD
  112. ShimGetEnvironmentSize(
  113. PSZ pszEnv,
  114. LPDWORD pStrCount
  115. )
  116. {
  117. PSZ pTemp = pszEnv;
  118. DWORD dwCount = 0;
  119. while (*pTemp != '\0') {
  120. dwCount++;
  121. pTemp += strlen(pTemp) + 1;
  122. }
  123. pTemp++;
  124. if (pStrCount != NULL) {
  125. *pStrCount = dwCount;
  126. }
  127. return (DWORD)(pTemp - pszEnv);
  128. }
  129. // returns size (in characters) of an environment block
  130. DWORD
  131. ShimGetEnvironmentSize(
  132. WCHAR* pwszEnv,
  133. LPDWORD pStrCount
  134. )
  135. {
  136. WCHAR* pTemp = pwszEnv;
  137. DWORD dwCount = 0;
  138. while(*pTemp != L'\0') {
  139. dwCount++;
  140. pTemp += wcslen(pTemp) + 1;
  141. }
  142. pTemp++; // include terminating '\0'
  143. if (pStrCount != NULL) {
  144. *pStrCount = dwCount;
  145. }
  146. return (DWORD)(pTemp - pwszEnv);
  147. }
  148. //
  149. // returns cloned (unicode) environment
  150. //
  151. NTSTATUS
  152. ShimCloneEnvironment(
  153. LPVOID* ppEnvOut,
  154. LPVOID lpEnvironment,
  155. BOOL bUnicode
  156. )
  157. {
  158. NTSTATUS Status = STATUS_INVALID_PARAMETER;
  159. DWORD dwEnvSize = 0;
  160. LPVOID lpEnvNew = NULL;
  161. MEMORY_BASIC_INFORMATION MemoryInformation;
  162. if (lpEnvironment == NULL) {
  163. Status = RtlCreateEnvironment(TRUE, &lpEnvNew);
  164. } else {
  165. //
  166. // Find the environment's size in characters but recalc in unicode.
  167. //
  168. dwEnvSize = (bUnicode ? ShimGetEnvironmentSize((WCHAR*)lpEnvironment, NULL) :
  169. ShimGetEnvironmentSize((PSZ)lpEnvironment, NULL));
  170. //
  171. // Allocate memory -- using Zw routines (that is what rtl is using).
  172. //
  173. MemoryInformation.RegionSize = (dwEnvSize + 2) * sizeof(UNICODE_NULL);
  174. Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
  175. &lpEnvNew,
  176. 0,
  177. &MemoryInformation.RegionSize,
  178. MEM_COMMIT,
  179. PAGE_READWRITE);
  180. if (!NT_SUCCESS(Status)) {
  181. LOGN(
  182. eDbgLevelError,
  183. "[ShimCloneEnvironment] Failed to allocate %d bytes for the environment block.",
  184. dwEnvSize * sizeof(UNICODE_NULL));
  185. return Status;
  186. }
  187. if (bUnicode) {
  188. //
  189. // Unicode, just copy the environment
  190. //
  191. RtlMoveMemory(lpEnvNew, lpEnvironment, dwEnvSize * sizeof(UNICODE_NULL));
  192. } else {
  193. //
  194. // The environment is ANSI, so we need to convert.
  195. //
  196. UNICODE_STRING UnicodeBuffer;
  197. ANSI_STRING AnsiBuffer;
  198. AnsiBuffer.Buffer = (CHAR*)lpEnvironment;
  199. AnsiBuffer.Length = AnsiBuffer.MaximumLength = (USHORT)dwEnvSize; // size in bytes = size in chars, includes \0\0
  200. UnicodeBuffer.Buffer = (WCHAR*)lpEnvNew;
  201. UnicodeBuffer.Length = (USHORT)dwEnvSize * sizeof(UNICODE_NULL);
  202. UnicodeBuffer.MaximumLength = (USHORT)(dwEnvSize + 2) * sizeof(UNICODE_NULL); // leave room for \0
  203. Status = RtlAnsiStringToUnicodeString(&UnicodeBuffer, &AnsiBuffer, FALSE);
  204. if (!NT_SUCCESS(Status)) {
  205. LOGN(
  206. eDbgLevelError,
  207. "[ShimCloneEnvironment] Failed to convert ANSI environment to UNICODE. Status = 0x%x",
  208. Status);
  209. }
  210. }
  211. }
  212. if (NT_SUCCESS(Status)) {
  213. *ppEnvOut = lpEnvNew;
  214. } else {
  215. if (lpEnvNew != NULL) {
  216. RtlDestroyEnvironment(lpEnvNew);
  217. }
  218. }
  219. return Status;
  220. }
  221. NTSTATUS
  222. ShimFreeEnvironment(
  223. LPVOID lpEnvironment
  224. )
  225. {
  226. NTSTATUS Status;
  227. __try {
  228. Status = RtlDestroyEnvironment(lpEnvironment);
  229. if (!NT_SUCCESS(Status)) {
  230. LOGN(
  231. eDbgLevelError,
  232. "[ShimFreeEnvironment] RtlDestroyEnvironment failed. Status = 0x%x",
  233. Status);
  234. }
  235. } __except(WOWPROCESSHISTORYEXCEPTIONFILTER) {
  236. Status = STATUS_ACCESS_VIOLATION;
  237. }
  238. return Status;
  239. }
  240. //
  241. // Set environment variable, possibly create or clone provided environment
  242. //
  243. NTSTATUS
  244. ShimSetEnvironmentVar(
  245. LPVOID* ppEnvironment,
  246. WCHAR* pwszVarName,
  247. WCHAR* pwszVarValue
  248. )
  249. {
  250. UNICODE_STRING ustrVarName;
  251. UNICODE_STRING ustrVarValue;
  252. NTSTATUS Status;
  253. RtlInitUnicodeString(&ustrVarName, pwszVarName);
  254. if (NULL != pwszVarValue) {
  255. RtlInitUnicodeString(&ustrVarValue, pwszVarValue);
  256. }
  257. Status = RtlSetEnvironmentVariable(ppEnvironment,
  258. &ustrVarName,
  259. (NULL == pwszVarValue) ? NULL : &ustrVarValue);
  260. if (!NT_SUCCESS(Status)) {
  261. LOGN(
  262. eDbgLevelError,
  263. "[ShimSetEnvironmentVar] RtlSetEnvironmentVariable failed. Status = 0x%x",
  264. Status);
  265. }
  266. return Status;
  267. }
  268. IMPLEMENT_SHIM_END