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.

439 lines
14 KiB

  1. /***
  2. *setenv.c -set an environment variable in the environment
  3. *
  4. * Copyright (c) 1993-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines __crtsetenv() - adds a new variable to environment.
  8. * Internal use only.
  9. *
  10. *Revision History:
  11. * 11-30-93 CFW Module created, most of it grabbed from putenv.c.
  12. * 12-07-93 CFW Change _TCHAR to _TSCHAR.
  13. * 01-15-94 CFW Use _tcsnicoll for global match.
  14. * 01-28-94 CFW Copy environment when re-alloc.
  15. * 03-25-94 GJF Declaration of __[w]initenv moved to internal.h.
  16. * 01-10-95 CFW Debug CRT allocs.
  17. * 01-18-95 GJF Must replace _tcsdup with _malloc_crt/_tcscpy for
  18. * _DEBUG build.
  19. * 06-01-95 CFW Free strings for removed environemnt variables.
  20. * 03-03-98 RKP Add support for 64 bit
  21. * 05-28-99 GJF When appropriate, free up the option string.
  22. * 08-03-99 PML Fix use-after-free bug in __crtsetenv()
  23. * 02-23-00 GB Fix __crtwsetenv() so as to work on Win9x.
  24. * 05-17-00 GB Use ERROR_CALL_NOT_IMPLEMENTED for existance of W API
  25. * 05-23-00 GB return error (-1) for API returning error
  26. *
  27. *******************************************************************************/
  28. #ifndef _POSIX_
  29. #include <windows.h>
  30. #include <cruntime.h>
  31. #include <internal.h>
  32. #include <stdlib.h>
  33. #include <tchar.h>
  34. #include <rterr.h>
  35. #include <dbgint.h>
  36. static _TSCHAR **copy_environ(_TSCHAR **);
  37. #ifdef WPRFLAG
  38. static int __cdecl wfindenv(const wchar_t *name, int len);
  39. #define USE_W 1
  40. #define USE_A 0
  41. #else
  42. static int __cdecl findenv(const char *name, int len);
  43. #endif
  44. /***
  45. *int __crtsetenv(option) - add/replace/remove variable in environment
  46. *
  47. *Purpose:
  48. * option should be of the form "option=value". If a string with the
  49. * given option part already exists, it is replaced with the given
  50. * string; otherwise the given string is added to the environment.
  51. * If the string is of the form "option=", then the string is
  52. * removed from the environment, if it exists. If the string has
  53. * no equals sign, error is returned.
  54. *
  55. *Entry:
  56. * char *option - option string to set in the environment list.
  57. * should be of the form "option=value".
  58. * int primary - Only the primary call to _crt[w]setenv needs to
  59. * create new copies or set the OS environment.
  60. * 1 indicates that this is the primary call.
  61. *
  62. *Exit:
  63. * returns 0 if OK, -1 if fails.
  64. *
  65. *Exceptions:
  66. *
  67. *Warnings:
  68. * This code will not work if variables are removed from the environment
  69. * by deleting them from environ[]. Use _putenv("option=") to remove a
  70. * variable.
  71. *
  72. * The option argument may be freed!
  73. *
  74. *******************************************************************************/
  75. #ifdef WPRFLAG
  76. int __cdecl __crtwsetenv (
  77. #else
  78. int __cdecl __crtsetenv (
  79. #endif
  80. _TSCHAR *option,
  81. const int primary
  82. )
  83. {
  84. #ifdef WPRFLAG
  85. static int f_use = USE_W;
  86. #endif
  87. int ix;
  88. int retval = 0;
  89. int remove; /* 1 if variable is to be removed */
  90. _TSCHAR **env;
  91. _TSCHAR *name, *value;
  92. const _TSCHAR *equal;
  93. /*
  94. * check that the option string is valid, find the equal sign
  95. * and verify '=' is not the first character in string.
  96. */
  97. if ( (option == NULL) || ((equal = _tcschr(option, _T('='))) == NULL)
  98. || option == equal)
  99. return(-1);
  100. /* if the character following '=' is null, we are removing the
  101. * the environment variable. Otherwise, we are adding or updating
  102. * an environment variable.
  103. */
  104. remove = (*(equal + 1) == _T('\0'));
  105. /*
  106. * the first time _[w]putenv() is called, copy the environment
  107. * block that was passed to [w]main to avoid making a
  108. * dangling pointer if the block is re-alloced.
  109. */
  110. #ifdef WPRFLAG
  111. if (_wenviron == __winitenv)
  112. _wenviron = copy_environ(_wenviron);
  113. #else
  114. if (_environ == __initenv)
  115. _environ = copy_environ(_environ);
  116. #endif
  117. /* see if requested environment array exists */
  118. if (_tenviron == NULL) {
  119. /*
  120. * The requested type of environment does not exist.
  121. * See if other type exists, if so convert it to requested type.
  122. * The functions that convert the enviroment (__mbtow_environ and
  123. * __wtomb_environ) will call this function (__crt[w]setenv) once
  124. * for each of the pre-existing environment variables. To avoid
  125. * an infinite loop, test the primary flag.
  126. */
  127. #ifdef WPRFLAG
  128. if (primary && _environ)
  129. {
  130. if (__mbtow_environ() != 0)
  131. return -1;
  132. }
  133. #else
  134. if (primary && _wenviron)
  135. {
  136. if (__wtomb_environ() != 0)
  137. return -1;
  138. }
  139. #endif
  140. else {
  141. /* nothing to remove, return */
  142. if ( remove )
  143. return 0;
  144. else {
  145. /* create ones that do not exist */
  146. if (_environ == NULL)
  147. {
  148. _environ = _malloc_crt(sizeof(char *));
  149. if (!_environ)
  150. return -1;
  151. *_environ = NULL;
  152. }
  153. if (_wenviron == NULL)
  154. {
  155. _wenviron = _malloc_crt(sizeof(wchar_t *));
  156. if (!_wenviron)
  157. return -1;
  158. *_wenviron = NULL;
  159. }
  160. }
  161. }
  162. }
  163. /*
  164. * At this point, the two types of environments are in sync (as much
  165. * as they can be anyway). The only way they can get out of sync
  166. * (besides users directly modifiying the environment) is if there
  167. * are conversion problems: If the user sets two Unicode EVs,
  168. * "foo1" and "foo2" and converting then to multibyte yields "foo?"
  169. * and "foo?", then the environment blocks will differ.
  170. */
  171. /* init env pointers */
  172. env = _tenviron;
  173. /* See if the string is already in the environment */
  174. #ifdef WPRFLAG
  175. ix = wfindenv(option, (int)(equal - option));
  176. #else
  177. ix = findenv(option, (int)(equal - option));
  178. #endif
  179. if ((ix >= 0) && (*env != NULL)) {
  180. /*
  181. * String is already in the environment. Free up the original
  182. * string. Then, install the new string or shrink the environment,
  183. * whichever is warranted.
  184. */
  185. _free_crt(env[ix]);
  186. if (remove) {
  187. void *pv;
  188. /* removing -- move all the later strings up */
  189. for ( ; env[ix] != NULL; ++ix) {
  190. env[ix] = env[ix+1];
  191. }
  192. /* shrink the environment memory block
  193. (ix now has number of strings, including NULL) --
  194. this realloc probably can't fail, since we're
  195. shrinking a mem block, but we're careful anyway. */
  196. if (pv = (_TSCHAR **) _realloc_crt(env, ix * sizeof(_TSCHAR *)))
  197. _tenviron = pv;
  198. }
  199. else {
  200. /* replace the option */
  201. env[ix] = (_TSCHAR *) option;
  202. }
  203. }
  204. else {
  205. /*
  206. * String is NOT in the environment
  207. */
  208. if ( !remove ) {
  209. void *pv;
  210. /*
  211. * Append the string to the environ table. Note that
  212. * table must be grown to do this.
  213. */
  214. if (ix < 0)
  215. ix = -ix; /* ix = length of environ table */
  216. pv = _realloc_crt(env, sizeof(_TSCHAR *) * (ix + 2));
  217. if (!pv)
  218. return -1;
  219. else
  220. env = (_TSCHAR **)pv;
  221. env[ix] = (_TSCHAR *)option;
  222. env[ix + 1] = NULL;
  223. _tenviron = env;
  224. }
  225. else {
  226. /*
  227. * We are asked to remove an environment var that isn't there.
  228. * Free the option string and return success.
  229. */
  230. _free_crt(option);
  231. return 0;
  232. }
  233. }
  234. /*
  235. * Update the OS environment. Don't give an error if this fails
  236. * since the failure will not affect the user unless he/she is making
  237. * direct API calls. Only need to do this for one type, OS converts
  238. * to other type automatically.
  239. */
  240. if ( primary &&
  241. (name = (_TSCHAR *)_malloc_crt((_tcslen(option) + 2) * sizeof(_TSCHAR))) != NULL )
  242. {
  243. _tcscpy(name, option);
  244. value = name + (equal - option);
  245. *value++ = _T('\0');
  246. #ifdef WPRFLAG
  247. if (f_use == USE_W)
  248. {
  249. if ( SetEnvironmentVariableW(name, remove ? NULL : value) == 0)
  250. {
  251. if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
  252. f_use = USE_A;
  253. else
  254. retval = -1;
  255. }
  256. }
  257. if (f_use == USE_A)
  258. {
  259. int size;
  260. char *c_name = NULL, *c_value = NULL;
  261. if ((size = WideCharToMultiByte(CP_ACP, 0, name, -1, NULL, 0, NULL, NULL)) == 0)
  262. retval = -1;
  263. /* allocate space for variable */
  264. else if ((c_name = (char *) _malloc_crt(size * sizeof(char))) == NULL)
  265. retval = -1;
  266. /* convert it */
  267. else if (WideCharToMultiByte(CP_ACP, 0, name, -1, c_name, size, NULL, NULL) == 0)
  268. retval = -1;
  269. else if ( !remove )
  270. {
  271. if ((size = WideCharToMultiByte(CP_ACP, 0, value, -1, NULL, 0, NULL, NULL)) == 0)
  272. retval = -1;
  273. /* allocate space for variable */
  274. else if ((c_value = (char *) _malloc_crt(size * sizeof(char))) == NULL)
  275. retval = -1;
  276. /* convert it */
  277. else if (WideCharToMultiByte(CP_ACP, 0, value, -1, c_value, size, NULL, NULL) == 0)
  278. retval = -1;
  279. }
  280. if (retval != -1)
  281. if (SetEnvironmentVariableA(c_name, remove ? NULL : c_value) == 0)
  282. retval = -1;
  283. _free_crt(c_value);
  284. _free_crt(c_name);
  285. }
  286. #else
  287. if (SetEnvironmentVariable(name, remove ? NULL : value) == 0)
  288. retval = -1;
  289. #endif
  290. _free_crt(name);
  291. }
  292. if (remove) {
  293. /* free option string since it won't be used anymore */
  294. _free_crt(option);
  295. }
  296. return retval;
  297. }
  298. /***
  299. *int findenv(name, len) - [STATIC]
  300. *
  301. *Purpose:
  302. * Scan for the given string within the environment
  303. *
  304. *Entry:
  305. *
  306. *Exit:
  307. * Returns the offset in "environ[]" of the given variable
  308. * Returns the negative of the length of environ[] if not found.
  309. * Returns 0 if the environment is empty.
  310. *
  311. * [NOTE: That a 0 return can mean that the environment is empty
  312. * or that the string was found as the first entry in the array.]
  313. *
  314. *Exceptions:
  315. *
  316. *******************************************************************************/
  317. #ifdef WPRFLAG
  318. static int __cdecl wfindenv (
  319. #else
  320. static int __cdecl findenv (
  321. #endif
  322. const _TSCHAR *name,
  323. int len
  324. )
  325. {
  326. _TSCHAR **env;
  327. for ( env = _tenviron ; *env != NULL ; env++ ) {
  328. /*
  329. * See if first len characters match, up to case
  330. */
  331. if ( _tcsnicoll(name, *env, len) == 0 )
  332. /*
  333. * the next character of the environment string must
  334. * be an '=' or a '\0'
  335. */
  336. if ( (*env)[len] == _T('=') || (*env)[len] == _T('\0') )
  337. return(int)(env - _tenviron);
  338. //
  339. // We cannot break here since findenv must report the total number of strings.
  340. // else
  341. // break;
  342. }
  343. return(-(int)(env - _tenviron));
  344. }
  345. /***
  346. *copy_environ - copy an environment block
  347. *
  348. *Purpose:
  349. * Create a copy of an environment block.
  350. *
  351. *Entry:
  352. * _TSCHAR **oldenviron - pointer to enviroment to be copied.
  353. *
  354. *Exit:
  355. * Returns a pointer to newly created environment.
  356. *
  357. *Exceptions:
  358. *
  359. *******************************************************************************/
  360. static _TSCHAR **copy_environ(_TSCHAR **oldenviron)
  361. {
  362. int cvars = 0;
  363. _TSCHAR **oldenvptr = oldenviron;
  364. _TSCHAR **newenviron, **newenvptr;
  365. /* no environment */
  366. if (oldenviron == NULL)
  367. return NULL;
  368. /* count number of environment variables */
  369. while (*oldenvptr++)
  370. cvars++;
  371. /* need pointer for each string, plus one null ptr at end */
  372. if ( (newenviron = newenvptr = (_TSCHAR **)
  373. _malloc_crt((cvars+1) * sizeof(_TSCHAR *))) == NULL )
  374. _amsg_exit(_RT_SPACEENV);
  375. /* duplicate the environment variable strings */
  376. oldenvptr = oldenviron;
  377. while (*oldenvptr)
  378. #ifdef _DEBUG
  379. {
  380. if ( (*newenvptr = _malloc_crt((_tcslen(*oldenvptr)+1)
  381. * sizeof(_TSCHAR))) != NULL )
  382. _tcscpy(*newenvptr, *oldenvptr);
  383. oldenvptr++;
  384. newenvptr++;
  385. }
  386. #else /* ndef _DEBUG */
  387. *newenvptr++ = _tcsdup(*oldenvptr++);
  388. #endif /* _DEBUG */
  389. *newenvptr = NULL;
  390. return newenviron;
  391. }
  392. #endif /* POSIX */