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.

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