php_open_temporary_file.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. /*
  2. +----------------------------------------------------------------------+
  3. | PHP Version 5 |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1997-2016 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Author: Zeev Suraski <zeev@zend.com> |
  16. +----------------------------------------------------------------------+
  17. */
  18. /* $Id$ */
  19. #include "php.h"
  20. #include <errno.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. #ifdef PHP_WIN32
  25. #define O_RDONLY _O_RDONLY
  26. #include "win32/param.h"
  27. #include "win32/winutil.h"
  28. #elif defined(NETWARE)
  29. #ifdef USE_WINSOCK
  30. #include <novsock2.h>
  31. #else
  32. #include <sys/socket.h>
  33. #endif
  34. #include <sys/param.h>
  35. #else
  36. #include <sys/param.h>
  37. #include <sys/socket.h>
  38. #include <netinet/in.h>
  39. #include <netdb.h>
  40. #if HAVE_ARPA_INET_H
  41. #include <arpa/inet.h>
  42. #endif
  43. #endif
  44. #ifdef HAVE_SYS_TIME_H
  45. #include <sys/time.h>
  46. #endif
  47. #ifdef HAVE_SYS_FILE_H
  48. #include <sys/file.h>
  49. #endif
  50. #if !defined(P_tmpdir)
  51. #define P_tmpdir ""
  52. #endif
  53. /* {{{ php_do_open_temporary_file */
  54. /* Loosely based on a tempnam() implementation by UCLA */
  55. /*
  56. * Copyright (c) 1988, 1993
  57. * The Regents of the University of California. All rights reserved.
  58. *
  59. * Redistribution and use in source and binary forms, with or without
  60. * modification, are permitted provided that the following conditions
  61. * are met:
  62. * 1. Redistributions of source code must retain the above copyright
  63. * notice, this list of conditions and the following disclaimer.
  64. * 2. Redistributions in binary form must reproduce the above copyright
  65. * notice, this list of conditions and the following disclaimer in the
  66. * documentation and/or other materials provided with the distribution.
  67. * 3. All advertising materials mentioning features or use of this software
  68. * must display the following acknowledgement:
  69. * This product includes software developed by the University of
  70. * California, Berkeley and its contributors.
  71. * 4. Neither the name of the University nor the names of its contributors
  72. * may be used to endorse or promote products derived from this software
  73. * without specific prior written permission.
  74. *
  75. * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  76. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  77. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  78. * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  79. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  80. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  81. * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  82. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  83. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  84. * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  85. * SUCH DAMAGE.
  86. */
  87. static int php_do_open_temporary_file(const char *path, const char *pfx, char **opened_path_p TSRMLS_DC)
  88. {
  89. char *trailing_slash;
  90. char *opened_path;
  91. char cwd[MAXPATHLEN];
  92. cwd_state new_state;
  93. int fd = -1;
  94. #ifndef HAVE_MKSTEMP
  95. int open_flags = O_CREAT | O_TRUNC | O_RDWR
  96. #ifdef PHP_WIN32
  97. | _O_BINARY
  98. #endif
  99. ;
  100. #endif
  101. if (!path || !path[0]) {
  102. return -1;
  103. }
  104. #ifdef PHP_WIN32
  105. if (!php_win32_check_trailing_space(pfx, (const int)strlen(pfx))) {
  106. SetLastError(ERROR_INVALID_NAME);
  107. return -1;
  108. }
  109. #endif
  110. if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
  111. cwd[0] = '\0';
  112. }
  113. new_state.cwd = estrdup(cwd);
  114. new_state.cwd_length = strlen(cwd);
  115. if (virtual_file_ex(&new_state, path, NULL, CWD_REALPATH TSRMLS_CC)) {
  116. efree(new_state.cwd);
  117. return -1;
  118. }
  119. if (IS_SLASH(new_state.cwd[new_state.cwd_length - 1])) {
  120. trailing_slash = "";
  121. } else {
  122. trailing_slash = "/";
  123. }
  124. if (spprintf(&opened_path, 0, "%s%s%sXXXXXX", new_state.cwd, trailing_slash, pfx) >= MAXPATHLEN) {
  125. efree(opened_path);
  126. efree(new_state.cwd);
  127. return -1;
  128. }
  129. #ifdef PHP_WIN32
  130. if (GetTempFileName(new_state.cwd, pfx, 0, opened_path)) {
  131. /* Some versions of windows set the temp file to be read-only,
  132. * which means that opening it will fail... */
  133. if (VCWD_CHMOD(opened_path, 0600)) {
  134. efree(opened_path);
  135. efree(new_state.cwd);
  136. return -1;
  137. }
  138. fd = VCWD_OPEN_MODE(opened_path, open_flags, 0600);
  139. }
  140. #elif defined(HAVE_MKSTEMP)
  141. fd = mkstemp(opened_path);
  142. #else
  143. if (mktemp(opened_path)) {
  144. fd = VCWD_OPEN(opened_path, open_flags);
  145. }
  146. #endif
  147. if (fd == -1 || !opened_path_p) {
  148. efree(opened_path);
  149. } else {
  150. *opened_path_p = opened_path;
  151. }
  152. efree(new_state.cwd);
  153. return fd;
  154. }
  155. /* }}} */
  156. /* Cache the chosen temporary directory. */
  157. static
  158. #ifdef ZTS
  159. #ifdef PHP_WIN32
  160. __declspec(thread)
  161. #elif defined(__GNUC__)
  162. __thread
  163. #endif
  164. #endif
  165. char* temporary_directory;
  166. PHPAPI void php_shutdown_temporary_directory(void)
  167. {
  168. if (temporary_directory) {
  169. efree(temporary_directory);
  170. temporary_directory = NULL;
  171. }
  172. }
  173. /*
  174. * Determine where to place temporary files.
  175. */
  176. PHPAPI const char* php_get_temporary_directory(TSRMLS_D)
  177. {
  178. /* Did we determine the temporary directory already? */
  179. if (temporary_directory) {
  180. return temporary_directory;
  181. }
  182. /* Is there a temporary directory "sys_temp_dir" in .ini defined? */
  183. {
  184. char *sys_temp_dir = PG(sys_temp_dir);
  185. if (sys_temp_dir) {
  186. int len = strlen(sys_temp_dir);
  187. if (len >= 2 && sys_temp_dir[len - 1] == DEFAULT_SLASH) {
  188. temporary_directory = estrndup(sys_temp_dir, len - 1);
  189. return temporary_directory;
  190. } else if (len >= 1 && sys_temp_dir[len - 1] != DEFAULT_SLASH) {
  191. temporary_directory = estrndup(sys_temp_dir, len);
  192. return temporary_directory;
  193. }
  194. }
  195. }
  196. #ifdef PHP_WIN32
  197. /* We can't count on the environment variables TEMP or TMP,
  198. * and so must make the Win32 API call to get the default
  199. * directory for temporary files. Note this call checks
  200. * the environment values TMP and TEMP (in order) first.
  201. */
  202. {
  203. char sTemp[MAX_PATH];
  204. DWORD len = GetTempPath(sizeof(sTemp),sTemp);
  205. assert(0 < len); /* should *never* fail! */
  206. if (sTemp[len - 1] == DEFAULT_SLASH) {
  207. temporary_directory = estrndup(sTemp, len - 1);
  208. } else {
  209. temporary_directory = estrndup(sTemp, len);
  210. }
  211. return temporary_directory;
  212. }
  213. #else
  214. /* On Unix use the (usual) TMPDIR environment variable. */
  215. {
  216. char* s = getenv("TMPDIR");
  217. if (s && *s) {
  218. int len = strlen(s);
  219. if (s[len - 1] == DEFAULT_SLASH) {
  220. temporary_directory = estrndup(s, len - 1);
  221. } else {
  222. temporary_directory = estrndup(s, len);
  223. }
  224. return temporary_directory;
  225. }
  226. }
  227. #ifdef P_tmpdir
  228. /* Use the standard default temporary directory. */
  229. if (P_tmpdir) {
  230. temporary_directory = estrdup(P_tmpdir);
  231. return temporary_directory;
  232. }
  233. #endif
  234. /* Shouldn't ever(!) end up here ... last ditch default. */
  235. temporary_directory = estrndup("/tmp", sizeof("/tmp"));
  236. return temporary_directory;
  237. #endif
  238. }
  239. /* {{{ php_open_temporary_file
  240. *
  241. * Unlike tempnam(), the supplied dir argument takes precedence
  242. * over the TMPDIR environment variable
  243. * This function should do its best to return a file pointer to a newly created
  244. * unique file, on every platform.
  245. */
  246. PHPAPI int php_open_temporary_fd_ex(const char *dir, const char *pfx, char **opened_path_p, zend_bool open_basedir_check TSRMLS_DC)
  247. {
  248. int fd;
  249. const char *temp_dir;
  250. if (!pfx) {
  251. pfx = "tmp.";
  252. }
  253. if (opened_path_p) {
  254. *opened_path_p = NULL;
  255. }
  256. if (!dir || *dir == '\0') {
  257. def_tmp:
  258. temp_dir = php_get_temporary_directory(TSRMLS_C);
  259. if (temp_dir && *temp_dir != '\0' && (!open_basedir_check || !php_check_open_basedir(temp_dir TSRMLS_CC))) {
  260. return php_do_open_temporary_file(temp_dir, pfx, opened_path_p TSRMLS_CC);
  261. } else {
  262. return -1;
  263. }
  264. }
  265. /* Try the directory given as parameter. */
  266. fd = php_do_open_temporary_file(dir, pfx, opened_path_p TSRMLS_CC);
  267. if (fd == -1) {
  268. /* Use default temporary directory. */
  269. goto def_tmp;
  270. }
  271. return fd;
  272. }
  273. PHPAPI int php_open_temporary_fd(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
  274. {
  275. return php_open_temporary_fd_ex(dir, pfx, opened_path_p, 0 TSRMLS_CC);
  276. }
  277. PHPAPI FILE *php_open_temporary_file(const char *dir, const char *pfx, char **opened_path_p TSRMLS_DC)
  278. {
  279. FILE *fp;
  280. int fd = php_open_temporary_fd(dir, pfx, opened_path_p TSRMLS_CC);
  281. if (fd == -1) {
  282. return NULL;
  283. }
  284. fp = fdopen(fd, "r+b");
  285. if (fp == NULL) {
  286. close(fd);
  287. }
  288. return fp;
  289. }
  290. /* }}} */
  291. /*
  292. * Local variables:
  293. * tab-width: 4
  294. * c-basic-offset: 4
  295. * End:
  296. * vim600: sw=4 ts=4 fdm=marker
  297. * vim<600: sw=4 ts=4
  298. */