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.

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