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