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.

485 lines
15 KiB

  1. /*++
  2. Copyright (c) 1992-1993 Microsoft Corporation
  3. Module Name:
  4. ConfExp.c
  5. Abstract:
  6. This module contains NetpExpandConfigString().
  7. Author:
  8. JR (John Rogers, JohnRo@Microsoft) 26-May-1992
  9. Revision History:
  10. 26-May-1992 JohnRo
  11. Created. [but didn't use until April '93 --JR]
  12. 13-Apr-1993 JohnRo
  13. RAID 5483: server manager: wrong path given in repl dialog.
  14. --*/
  15. // These must be included first:
  16. #include <nt.h> // NT_SUCCESS(), etc.
  17. #include <ntrtl.h>
  18. #include <nturtl.h>
  19. #include <windows.h> // IN, LPCTSTR, OPTIONAL, etc.
  20. #include <lmcons.h> // NET_API_STATUS.
  21. // These may be included in any order:
  22. #include <config.h> // My prototype.
  23. #include <configp.h> // NetpGetWinRegConfigMaxSizes().
  24. #include <confname.h> // ENV_KEYWORD_SYSTEMROOT, etc.
  25. #include <debuglib.h> // IF_DEBUG()
  26. #include <lmerr.h> // NO_ERROR, ERROR_ and NERR_ equates.
  27. #include <netdebug.h> // NetpKdPrint().
  28. #include <netlib.h> // NetpMemoryAllocate(), etc.
  29. #include <netlibnt.h> // NetpNtStatusToApiStatus().
  30. #include <prefix.h> // PREFIX_ equates.
  31. #include <tstring.h> // NetpAlloc{type}From{type}, STRSIZE(), TCHAR_EOS, etc.
  32. #define DEFAULT_ROOT_KEY HKEY_LOCAL_MACHINE
  33. #define REG_PATH_TO_ENV (LPTSTR) \
  34. TEXT("System\\CurrentControlSet\\Control\\Session Manager")
  35. #define REG_PATH_TO_SYSROOT (LPTSTR) \
  36. TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion")
  37. #ifndef TCHAR_PERCENT
  38. #define TCHAR_PERCENT TEXT('%')
  39. #endif
  40. DBGSTATIC NET_API_STATUS
  41. NetpAddValueToTempEnvironment(
  42. IN OUT PVOID TemporaryEnvironment,
  43. IN LPCTSTR KeywordW,
  44. IN LPCTSTR ValueW
  45. )
  46. {
  47. NET_API_STATUS ApiStatus = NO_ERROR;
  48. UNICODE_STRING KeywordString;
  49. NTSTATUS NtStatus;
  50. UNICODE_STRING ValueString;
  51. RtlInitUnicodeString(
  52. &KeywordString, // dest
  53. KeywordW ); // src
  54. RtlInitUnicodeString(
  55. &ValueString, // dest
  56. ValueW ); // src
  57. NtStatus = RtlSetEnvironmentVariable(
  58. &TemporaryEnvironment,
  59. &KeywordString, // name
  60. &ValueString ); // value
  61. if ( !NT_SUCCESS( NtStatus ) ) {
  62. ApiStatus = NetpNtStatusToApiStatus( NtStatus );
  63. NetpAssert( ApiStatus != NO_ERROR );
  64. goto Cleanup;
  65. }
  66. ApiStatus = NO_ERROR;
  67. Cleanup:
  68. return (ApiStatus);
  69. } // NetpAddValueToTempEnvironment
  70. NET_API_STATUS
  71. NetpExpandConfigString(
  72. IN LPCTSTR UncServerName OPTIONAL,
  73. IN LPCTSTR UnexpandedString,
  74. OUT LPTSTR * ValueBufferPtr // Must be freed by NetApiBufferFree().
  75. )
  76. /*++
  77. Routine Description:
  78. This function expands a value string (which may include references to
  79. environment variables). For instance, an unexpanded string might be:
  80. %SystemRoot%\System32\Repl\Export
  81. This could be expanded to:
  82. c:\nt\System32\Repl\Export
  83. The expansion makes use of environment variables on UncServerName,
  84. if given. This allows remote administration of the directory
  85. replicator.
  86. Arguments:
  87. UncServerName - assumed to NOT BE EXPLICIT LOCAL SERVER NAME.
  88. UnexpandedString - points to source string to be expanded.
  89. ValueBufferPtr - indicates a pointer which will be set by this routine.
  90. This routine will allocate memory for a null-terminated string.
  91. The caller must free this with NetApiBufferFree() or equivalent.
  92. Return Value:
  93. NET_API_STATUS
  94. --*/
  95. {
  96. NET_API_STATUS ApiStatus = NO_ERROR;
  97. LPTSTR ExpandedString = NULL;
  98. DWORD LastAllocationSize = 0;
  99. NTSTATUS NtStatus;
  100. LPTSTR RandomKeywordW = NULL;
  101. DWORD RandomValueSize;
  102. LPTSTR RandomValueW = NULL;
  103. HKEY RootKey = DEFAULT_ROOT_KEY;
  104. HKEY SectionKey = DEFAULT_ROOT_KEY;
  105. PVOID TemporaryEnvironment = NULL;
  106. NetpAssert( sizeof(DWORD) == sizeof(ULONG) ); // Mixing win32 and NT APIs.
  107. //
  108. // Check for caller errors.
  109. //
  110. if (ValueBufferPtr == NULL) {
  111. // Can't goto Cleanup here, as it assumes this pointer is valid.
  112. return (ERROR_INVALID_PARAMETER);
  113. }
  114. *ValueBufferPtr = NULL; // assume error until proven otherwise.
  115. if ( (UnexpandedString == NULL) || ((*UnexpandedString) == TCHAR_EOS ) ) {
  116. ApiStatus = ERROR_INVALID_PARAMETER;
  117. goto Cleanup;
  118. }
  119. //
  120. // This is probably just a constant string. Can we do it the easy way?
  121. //
  122. if (STRCHR( UnexpandedString, TCHAR_PERCENT ) == NULL) {
  123. // Just need to allocate a copy of the input string.
  124. ExpandedString = NetpAllocWStrFromWStr( (LPTSTR) UnexpandedString );
  125. if (ExpandedString == NULL) {
  126. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  127. goto Cleanup;
  128. }
  129. // That's all, folks!
  130. ApiStatus = NO_ERROR;
  131. //
  132. // Otherwise, is this local? Maybe we can
  133. // handle local expansion the easy (fast) way: using win32 API.
  134. //
  135. } else if ( (UncServerName==NULL) || ((*UncServerName)==TCHAR_EOS) ) {
  136. DWORD CharsRequired = STRLEN( UnexpandedString )+1;
  137. NetpAssert( CharsRequired > 1 );
  138. do {
  139. // Clean up from previous pass.
  140. if (ExpandedString != NULL) {
  141. NetpMemoryFree( ExpandedString );
  142. ExpandedString = NULL;
  143. }
  144. // Allocate the memory.
  145. NetpAssert( CharsRequired > 1 );
  146. ExpandedString = NetpMemoryAllocate( CharsRequired * sizeof(TCHAR));
  147. if (ExpandedString == NULL) {
  148. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  149. goto Cleanup;
  150. }
  151. LastAllocationSize = CharsRequired * sizeof(TCHAR);
  152. IF_DEBUG( CONFIG ) {
  153. NetpKdPrint(( PREFIX_NETLIB
  154. "NetpExpandConfigString: expanding"
  155. " '" FORMAT_LPTSTR "' locally into " FORMAT_LPVOID
  156. ", alloc'ed size " FORMAT_DWORD ".\n",
  157. UnexpandedString, (LPVOID) ExpandedString,
  158. LastAllocationSize ));
  159. }
  160. // Expand string using local env vars.
  161. CharsRequired = ExpandEnvironmentStrings(
  162. UnexpandedString, // src
  163. ExpandedString, // dest
  164. LastAllocationSize / sizeof(TCHAR) ); // dest max char count
  165. if (CharsRequired == 0) {
  166. ApiStatus = (NET_API_STATUS) GetLastError();
  167. NetpKdPrint(( PREFIX_NETLIB
  168. "NetpExpandConfigString: "
  169. "ExpandEnvironmentStringsW failed, API status="
  170. FORMAT_API_STATUS ".\n", ApiStatus ));
  171. NetpAssert( ApiStatus != NO_ERROR );
  172. goto Cleanup;
  173. }
  174. } while ((CharsRequired*sizeof(TCHAR)) > LastAllocationSize);
  175. IF_DEBUG( CONFIG ) {
  176. NetpKdPrint(( PREFIX_NETLIB
  177. "NetpExpandConfigString: expanded '"
  178. FORMAT_LPTSTR "' to '" FORMAT_LPTSTR "'.\n",
  179. UnexpandedString, ExpandedString ));
  180. }
  181. ApiStatus = NO_ERROR;
  182. //
  183. // Oh well, remote expansion required.
  184. //
  185. } else {
  186. DWORD DataType;
  187. LONG Error;
  188. UNICODE_STRING ExpandedUnicode;
  189. DWORD SizeRequired;
  190. UNICODE_STRING UnexpandedUnicode;
  191. //
  192. // Connect to remote registry.
  193. //
  194. Error = RegConnectRegistry(
  195. (LPTSTR) UncServerName,
  196. DEFAULT_ROOT_KEY,
  197. & RootKey ); // result key
  198. if (Error != ERROR_SUCCESS) {
  199. NetpKdPrint(( PREFIX_NETLIB
  200. "NetpExpandConfigString: RegConnectRegistry(machine '"
  201. FORMAT_LPTSTR "') ret error " FORMAT_LONG ".\n",
  202. UncServerName, Error ));
  203. ApiStatus = (NET_API_STATUS) Error;
  204. NetpAssert( ApiStatus != NO_ERROR );
  205. goto Cleanup;
  206. }
  207. NetpAssert( RootKey != DEFAULT_ROOT_KEY );
  208. //
  209. // Create a temporary environment, which we'll fill in and let RTL
  210. // routines do the expansion for us.
  211. //
  212. NtStatus = RtlCreateEnvironment(
  213. (BOOLEAN) FALSE, // don't clone current env
  214. &TemporaryEnvironment );
  215. if ( !NT_SUCCESS( NtStatus ) ) {
  216. ApiStatus = NetpNtStatusToApiStatus( NtStatus );
  217. NetpKdPrint(( PREFIX_NETLIB
  218. "NetpExpandConfigString: RtlCreateEnvironment failed, "
  219. "NT status=" FORMAT_NTSTATUS
  220. ", API status=" FORMAT_API_STATUS ".\n",
  221. NtStatus, ApiStatus ));
  222. NetpAssert( ApiStatus != NO_ERROR );
  223. goto Cleanup;
  224. }
  225. NetpAssert( TemporaryEnvironment != NULL );
  226. //
  227. // Start by populating the temporary environment with SystemRoot.
  228. //
  229. Error = RegOpenKeyEx(
  230. RootKey,
  231. REG_PATH_TO_SYSROOT,
  232. REG_OPTION_NON_VOLATILE,
  233. KEY_READ, // desired access
  234. & SectionKey );
  235. if (Error == ERROR_FILE_NOT_FOUND) {
  236. ApiStatus = NERR_CfgCompNotFound;
  237. goto Cleanup;
  238. } else if (Error != ERROR_SUCCESS) {
  239. ApiStatus = (NET_API_STATUS) Error;
  240. NetpAssert( ApiStatus != NO_ERROR );
  241. goto Cleanup;
  242. }
  243. NetpAssert( SectionKey != DEFAULT_ROOT_KEY );
  244. ApiStatus = NetpGetWinRegConfigMaxSizes(
  245. SectionKey,
  246. NULL, // don't need keyword size
  247. &RandomValueSize ); // set max value size.
  248. if (ApiStatus != NO_ERROR) {
  249. goto Cleanup;
  250. }
  251. NetpAssert( RandomValueSize > 0 );
  252. RandomValueW = NetpMemoryAllocate( RandomValueSize );
  253. if (RandomValueW == NULL) {
  254. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  255. goto Cleanup;
  256. }
  257. Error = RegQueryValueEx(
  258. SectionKey,
  259. (LPTSTR) ENV_KEYWORD_SYSTEMROOT,
  260. NULL, // reserved
  261. & DataType,
  262. (LPVOID) RandomValueW, // out: value string (TCHARs).
  263. & RandomValueSize );
  264. if (Error != ERROR_SUCCESS) {
  265. ApiStatus = (NET_API_STATUS) Error;
  266. goto Cleanup;
  267. }
  268. if (DataType != REG_SZ) {
  269. NetpKdPrint(( PREFIX_NETLIB
  270. "NetpExpandConfigString: unexpected data type "
  271. FORMAT_DWORD ".\n", DataType ));
  272. ApiStatus = ERROR_INVALID_DATA;
  273. goto Cleanup;
  274. }
  275. if ( (RandomValueSize == 0)
  276. || ((RandomValueSize % sizeof(TCHAR)) != 0) ) {
  277. NetpKdPrint(( PREFIX_NETLIB
  278. "NetpExpandConfigString: unexpected data size "
  279. FORMAT_DWORD ".\n", RandomValueSize ));
  280. ApiStatus = ERROR_INVALID_DATA;
  281. goto Cleanup;
  282. }
  283. ApiStatus = NetpAddValueToTempEnvironment(
  284. TemporaryEnvironment,
  285. (LPTSTR) ENV_KEYWORD_SYSTEMROOT,
  286. RandomValueW );
  287. if (ApiStatus != NO_ERROR) {
  288. goto Cleanup;
  289. }
  290. //
  291. // Loop until we have enough storage.
  292. // Expand the string.
  293. //
  294. SizeRequired = STRSIZE( UnexpandedString ); // First pass, try same size
  295. RtlInitUnicodeString(
  296. &UnexpandedUnicode, // dest
  297. (PCWSTR) UnexpandedString ); // src
  298. do {
  299. // Clean up from previous pass.
  300. if (ExpandedString != NULL) {
  301. NetpMemoryFree( ExpandedString );
  302. ExpandedString = NULL;
  303. }
  304. // Allocate the memory.
  305. NetpAssert( SizeRequired > 0 );
  306. ExpandedString = NetpMemoryAllocate( SizeRequired );
  307. if (ExpandedString == NULL) {
  308. ApiStatus = ERROR_NOT_ENOUGH_MEMORY;
  309. goto Cleanup;
  310. }
  311. LastAllocationSize = SizeRequired;
  312. ExpandedUnicode.MaximumLength = (USHORT)SizeRequired;
  313. ExpandedUnicode.Buffer = ExpandedString;
  314. IF_DEBUG( CONFIG ) {
  315. NetpKdPrint(( PREFIX_NETLIB
  316. "NetpExpandConfigString: expanding"
  317. " '" FORMAT_LPTSTR "' remotely into " FORMAT_LPVOID
  318. ", alloc'ed size " FORMAT_DWORD ".\n",
  319. UnexpandedString, (LPVOID) ExpandedString,
  320. SizeRequired ));
  321. }
  322. NtStatus = RtlExpandEnvironmentStrings_U(
  323. TemporaryEnvironment, // env to use
  324. &UnexpandedUnicode, // source
  325. &ExpandedUnicode, // dest
  326. (PULONG) &SizeRequired ); // dest size needed next time.
  327. if ( NtStatus == STATUS_BUFFER_TOO_SMALL ) {
  328. NetpAssert( SizeRequired > LastAllocationSize );
  329. continue; // try again with larger buffer.
  330. } else if ( !NT_SUCCESS( NtStatus ) ) {
  331. ApiStatus = NetpNtStatusToApiStatus( NtStatus );
  332. NetpKdPrint(( PREFIX_NETLIB
  333. "NetpExpandConfigString: "
  334. "RtlExpandEnvironmentStrings_U failed, "
  335. "NT status=" FORMAT_NTSTATUS
  336. ", API status=" FORMAT_API_STATUS ".\n",
  337. NtStatus, ApiStatus ));
  338. NetpAssert( ApiStatus != NO_ERROR );
  339. goto Cleanup;
  340. } else {
  341. NetpAssert( NT_SUCCESS( NtStatus ) );
  342. break; // All done.
  343. }
  344. } while (SizeRequired > LastAllocationSize);
  345. ApiStatus = NO_ERROR;
  346. }
  347. Cleanup:
  348. IF_DEBUG( CONFIG ) {
  349. NetpKdPrint(( PREFIX_NETLIB
  350. "NetpExpandConfigString: returning, API status="
  351. FORMAT_API_STATUS ".\n", ApiStatus ));
  352. }
  353. if (ApiStatus == NO_ERROR) {
  354. NetpAssert( ExpandedString != NULL );
  355. *ValueBufferPtr = ExpandedString;
  356. } else {
  357. *ValueBufferPtr = NULL;
  358. if (ExpandedString != NULL) {
  359. NetpMemoryFree( ExpandedString );
  360. }
  361. }
  362. if (RandomKeywordW != NULL) {
  363. NetpMemoryFree( RandomKeywordW );
  364. }
  365. if (RandomValueW != NULL) {
  366. NetpMemoryFree( RandomValueW );
  367. }
  368. if (RootKey != DEFAULT_ROOT_KEY) {
  369. (VOID) RegCloseKey( RootKey );
  370. }
  371. if (SectionKey != DEFAULT_ROOT_KEY) {
  372. (VOID) RegCloseKey( SectionKey );
  373. }
  374. if (TemporaryEnvironment != NULL) {
  375. (VOID) RtlDestroyEnvironment( TemporaryEnvironment );
  376. }
  377. return (ApiStatus);
  378. } // NetpExpandConfigString