1: /*
2: +----------------------------------------------------------------------+
3: | PHP Version 5 |
4: +----------------------------------------------------------------------+
5: | Copyright (c) 1997-2014 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: | Authors: Rasmus Lerdorf <rasmus@lerdorf.on.ca> |
16: | Jim Winstead <jimw@php.net> |
17: +----------------------------------------------------------------------+
18: */
19:
20: /* $Id: fopen_wrappers.c,v 1.1.1.4 2014/06/15 20:04:01 misho Exp $ */
21:
22: /* {{{ includes
23: */
24: #include "php.h"
25: #include "php_globals.h"
26: #include "SAPI.h"
27:
28: #include <stdio.h>
29: #include <stdlib.h>
30: #include <errno.h>
31: #include <sys/types.h>
32: #include <sys/stat.h>
33: #include <fcntl.h>
34:
35: #ifdef PHP_WIN32
36: #define O_RDONLY _O_RDONLY
37: #include "win32/param.h"
38: #else
39: #include <sys/param.h>
40: #endif
41:
42: #include "ext/standard/head.h"
43: #include "ext/standard/php_standard.h"
44: #include "zend_compile.h"
45: #include "php_network.h"
46:
47: #if HAVE_PWD_H
48: #include <pwd.h>
49: #endif
50:
51: #include <sys/types.h>
52: #if HAVE_SYS_SOCKET_H
53: #include <sys/socket.h>
54: #endif
55:
56: #ifndef S_ISREG
57: #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
58: #endif
59:
60: #ifdef PHP_WIN32
61: #include <winsock2.h>
62: #elif defined(NETWARE) && defined(USE_WINSOCK)
63: #include <novsock2.h>
64: #else
65: #include <netinet/in.h>
66: #include <netdb.h>
67: #if HAVE_ARPA_INET_H
68: #include <arpa/inet.h>
69: #endif
70: #endif
71:
72: #if defined(PHP_WIN32) || defined(__riscos__) || defined(NETWARE)
73: #undef AF_UNIX
74: #endif
75:
76: #if defined(AF_UNIX)
77: #include <sys/un.h>
78: #endif
79: /* }}} */
80:
81: /* {{{ OnUpdateBaseDir
82: Allows any change to open_basedir setting in during Startup and Shutdown events,
83: or a tightening during activation/runtime/deactivation */
84: PHPAPI ZEND_INI_MH(OnUpdateBaseDir)
85: {
86: char **p, *pathbuf, *ptr, *end;
87: #ifndef ZTS
88: char *base = (char *) mh_arg2;
89: #else
90: char *base = (char *) ts_resource(*((int *) mh_arg2));
91: #endif
92:
93: p = (char **) (base + (size_t) mh_arg1);
94:
95: if (stage == PHP_INI_STAGE_STARTUP || stage == PHP_INI_STAGE_SHUTDOWN || stage == PHP_INI_STAGE_ACTIVATE || stage == PHP_INI_STAGE_DEACTIVATE) {
96: /* We're in a PHP_INI_SYSTEM context, no restrictions */
97: *p = new_value;
98: return SUCCESS;
99: }
100:
101: /* Otherwise we're in runtime */
102: if (!*p || !**p) {
103: /* open_basedir not set yet, go ahead and give it a value */
104: *p = new_value;
105: return SUCCESS;
106: }
107:
108: /* Shortcut: When we have a open_basedir and someone tries to unset, we know it'll fail */
109: if (!new_value || !*new_value) {
110: return FAILURE;
111: }
112:
113: /* Is the proposed open_basedir at least as restrictive as the current setting? */
114: ptr = pathbuf = estrdup(new_value);
115: while (ptr && *ptr) {
116: end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
117: if (end != NULL) {
118: *end = '\0';
119: end++;
120: }
121: if (php_check_open_basedir_ex(ptr, 0 TSRMLS_CC) != 0) {
122: /* At least one portion of this open_basedir is less restrictive than the prior one, FAIL */
123: efree(pathbuf);
124: return FAILURE;
125: }
126: ptr = end;
127: }
128: efree(pathbuf);
129:
130: /* Everything checks out, set it */
131: *p = new_value;
132:
133: return SUCCESS;
134: }
135: /* }}} */
136:
137: /* {{{ php_check_specific_open_basedir
138: When open_basedir is not NULL, check if the given filename is located in
139: open_basedir. Returns -1 if error or not in the open_basedir, else 0.
140: When open_basedir is NULL, always return 0.
141: */
142: PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path TSRMLS_DC)
143: {
144: char resolved_name[MAXPATHLEN];
145: char resolved_basedir[MAXPATHLEN];
146: char local_open_basedir[MAXPATHLEN];
147: char path_tmp[MAXPATHLEN];
148: char *path_file;
149: int resolved_basedir_len;
150: int resolved_name_len;
151: int path_len;
152: int nesting_level = 0;
153:
154: /* Special case basedir==".": Use script-directory */
155: if (strcmp(basedir, ".") || !VCWD_GETCWD(local_open_basedir, MAXPATHLEN)) {
156: /* Else use the unmodified path */
157: strlcpy(local_open_basedir, basedir, sizeof(local_open_basedir));
158: }
159:
160: path_len = strlen(path);
161: if (path_len > (MAXPATHLEN - 1)) {
162: /* empty and too long paths are invalid */
163: return -1;
164: }
165:
166: /* normalize and expand path */
167: if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
168: return -1;
169: }
170:
171: path_len = strlen(resolved_name);
172: memcpy(path_tmp, resolved_name, path_len + 1); /* safe */
173:
174: while (VCWD_REALPATH(path_tmp, resolved_name) == NULL) {
175: #if defined(PHP_WIN32) || defined(HAVE_SYMLINK)
176: #if defined(PHP_WIN32)
177: if (EG(windows_version_info).dwMajorVersion > 5) {
178: #endif
179: if (nesting_level == 0) {
180: int ret;
181: char buf[MAXPATHLEN];
182:
183: ret = php_sys_readlink(path_tmp, buf, MAXPATHLEN - 1);
184: if (ret < 0) {
185: /* not a broken symlink, move along.. */
186: } else {
187: /* put the real path into the path buffer */
188: memcpy(path_tmp, buf, ret);
189: path_tmp[ret] = '\0';
190: }
191: }
192: #if defined(PHP_WIN32)
193: }
194: #endif
195: #endif
196:
197: #if defined(PHP_WIN32) || defined(NETWARE)
198: path_file = strrchr(path_tmp, DEFAULT_SLASH);
199: if (!path_file) {
200: path_file = strrchr(path_tmp, '/');
201: }
202: #else
203: path_file = strrchr(path_tmp, DEFAULT_SLASH);
204: #endif
205: if (!path_file) {
206: /* none of the path components exist. definitely not in open_basedir.. */
207: return -1;
208: } else {
209: path_len = path_file - path_tmp + 1;
210: #if defined(PHP_WIN32) || defined(NETWARE)
211: if (path_len > 1 && path_tmp[path_len - 2] == ':') {
212: if (path_len != 3) {
213: return -1;
214: }
215: /* this is c:\ */
216: path_tmp[path_len] = '\0';
217: } else {
218: path_tmp[path_len - 1] = '\0';
219: }
220: #else
221: path_tmp[path_len - 1] = '\0';
222: #endif
223: }
224: nesting_level++;
225: }
226:
227: /* Resolve open_basedir to resolved_basedir */
228: if (expand_filepath(local_open_basedir, resolved_basedir TSRMLS_CC) != NULL) {
229: /* Handler for basedirs that end with a / */
230: resolved_basedir_len = strlen(resolved_basedir);
231: #if defined(PHP_WIN32) || defined(NETWARE)
232: if (basedir[strlen(basedir) - 1] == PHP_DIR_SEPARATOR || basedir[strlen(basedir) - 1] == '/') {
233: #else
234: if (basedir[strlen(basedir) - 1] == PHP_DIR_SEPARATOR) {
235: #endif
236: if (resolved_basedir[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) {
237: resolved_basedir[resolved_basedir_len] = PHP_DIR_SEPARATOR;
238: resolved_basedir[++resolved_basedir_len] = '\0';
239: }
240: } else {
241: resolved_basedir[resolved_basedir_len++] = PHP_DIR_SEPARATOR;
242: resolved_basedir[resolved_basedir_len] = '\0';
243: }
244:
245: resolved_name_len = strlen(resolved_name);
246: if (path_tmp[path_len - 1] == PHP_DIR_SEPARATOR) {
247: if (resolved_name[resolved_name_len - 1] != PHP_DIR_SEPARATOR) {
248: resolved_name[resolved_name_len] = PHP_DIR_SEPARATOR;
249: resolved_name[++resolved_name_len] = '\0';
250: }
251: }
252:
253: /* Check the path */
254: #if defined(PHP_WIN32) || defined(NETWARE)
255: if (strncasecmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) {
256: #else
257: if (strncmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) {
258: #endif
259: if (resolved_name_len > resolved_basedir_len &&
260: resolved_name[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) {
261: return -1;
262: } else {
263: /* File is in the right directory */
264: return 0;
265: }
266: } else {
267: /* /openbasedir/ and /openbasedir are the same directory */
268: if (resolved_basedir_len == (resolved_name_len + 1) && resolved_basedir[resolved_basedir_len - 1] == PHP_DIR_SEPARATOR) {
269: #if defined(PHP_WIN32) || defined(NETWARE)
270: if (strncasecmp(resolved_basedir, resolved_name, resolved_name_len) == 0) {
271: #else
272: if (strncmp(resolved_basedir, resolved_name, resolved_name_len) == 0) {
273: #endif
274: return 0;
275: }
276: }
277: return -1;
278: }
279: } else {
280: /* Unable to resolve the real path, return -1 */
281: return -1;
282: }
283: }
284: /* }}} */
285:
286: PHPAPI int php_check_open_basedir(const char *path TSRMLS_DC)
287: {
288: return php_check_open_basedir_ex(path, 1 TSRMLS_CC);
289: }
290:
291: /* {{{ php_check_open_basedir
292: */
293: PHPAPI int php_check_open_basedir_ex(const char *path, int warn TSRMLS_DC)
294: {
295: /* Only check when open_basedir is available */
296: if (PG(open_basedir) && *PG(open_basedir)) {
297: char *pathbuf;
298: char *ptr;
299: char *end;
300:
301: /* Check if the path is too long so we can give a more useful error
302: * message. */
303: if (strlen(path) > (MAXPATHLEN - 1)) {
304: php_error_docref(NULL TSRMLS_CC, E_WARNING, "File name is longer than the maximum allowed path length on this platform (%d): %s", MAXPATHLEN, path);
305: errno = EINVAL;
306: return -1;
307: }
308:
309: pathbuf = estrdup(PG(open_basedir));
310:
311: ptr = pathbuf;
312:
313: while (ptr && *ptr) {
314: end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
315: if (end != NULL) {
316: *end = '\0';
317: end++;
318: }
319:
320: if (php_check_specific_open_basedir(ptr, path TSRMLS_CC) == 0) {
321: efree(pathbuf);
322: return 0;
323: }
324:
325: ptr = end;
326: }
327: if (warn) {
328: php_error_docref(NULL TSRMLS_CC, E_WARNING, "open_basedir restriction in effect. File(%s) is not within the allowed path(s): (%s)", path, PG(open_basedir));
329: }
330: efree(pathbuf);
331: errno = EPERM; /* we deny permission to open it */
332: return -1;
333: }
334:
335: /* Nothing to check... */
336: return 0;
337: }
338: /* }}} */
339:
340: /* {{{ php_fopen_and_set_opened_path
341: */
342: static FILE *php_fopen_and_set_opened_path(const char *path, const char *mode, char **opened_path TSRMLS_DC)
343: {
344: FILE *fp;
345:
346: if (php_check_open_basedir((char *)path TSRMLS_CC)) {
347: return NULL;
348: }
349: fp = VCWD_FOPEN(path, mode);
350: if (fp && opened_path) {
351: *opened_path = expand_filepath_with_mode(path, NULL, NULL, 0, CWD_EXPAND TSRMLS_CC);
352: }
353: return fp;
354: }
355: /* }}} */
356:
357: /* {{{ php_fopen_primary_script
358: */
359: PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
360: {
361: char *path_info;
362: char *filename = NULL;
363: char *resolved_path = NULL;
364: int length;
365: zend_bool orig_display_errors;
366:
367: path_info = SG(request_info).request_uri;
368: #if HAVE_PWD_H
369: if (PG(user_dir) && *PG(user_dir) && path_info && '/' == path_info[0] && '~' == path_info[1]) {
370: char *s = strchr(path_info + 2, '/');
371:
372: if (s) { /* if there is no path name after the file, do not bother */
373: char user[32]; /* to try open the directory */
374: struct passwd *pw;
375: #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
376: struct passwd pwstruc;
377: long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
378: char *pwbuf;
379:
380: if (pwbuflen < 1) {
381: return FAILURE;
382: }
383:
384: pwbuf = emalloc(pwbuflen);
385: #endif
386: length = s - (path_info + 2);
387: if (length > (int)sizeof(user) - 1) {
388: length = sizeof(user) - 1;
389: }
390: memcpy(user, path_info + 2, length);
391: user[length] = '\0';
392: #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
393: if (getpwnam_r(user, &pwstruc, pwbuf, pwbuflen, &pw)) {
394: efree(pwbuf);
395: return FAILURE;
396: }
397: #else
398: pw = getpwnam(user);
399: #endif
400: if (pw && pw->pw_dir) {
401: spprintf(&filename, 0, "%s%c%s%c%s", pw->pw_dir, PHP_DIR_SEPARATOR, PG(user_dir), PHP_DIR_SEPARATOR, s + 1); /* Safe */
402: } else {
403: filename = SG(request_info).path_translated;
404: }
405: #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
406: efree(pwbuf);
407: #endif
408: }
409: } else
410: #endif
411: if (PG(doc_root) && path_info && (length = strlen(PG(doc_root))) &&
412: IS_ABSOLUTE_PATH(PG(doc_root), length)) {
413: int path_len = strlen(path_info);
414: filename = emalloc(length + path_len + 2);
415: if (filename) {
416: memcpy(filename, PG(doc_root), length);
417: if (!IS_SLASH(filename[length - 1])) { /* length is never 0 */
418: filename[length++] = PHP_DIR_SEPARATOR;
419: }
420: if (IS_SLASH(path_info[0])) {
421: length--;
422: }
423: strncpy(filename + length, path_info, path_len + 1);
424: }
425: } else {
426: filename = SG(request_info).path_translated;
427: }
428:
429:
430: if (filename) {
431: resolved_path = zend_resolve_path(filename, strlen(filename) TSRMLS_CC);
432: }
433:
434: if (!resolved_path) {
435: if (SG(request_info).path_translated != filename) {
436: STR_FREE(filename);
437: }
438: /* we have to free SG(request_info).path_translated here because
439: * php_destroy_request_info assumes that it will get
440: * freed when the include_names hash is emptied, but
441: * we're not adding it in this case */
442: STR_FREE(SG(request_info).path_translated);
443: SG(request_info).path_translated = NULL;
444: return FAILURE;
445: }
446: efree(resolved_path);
447:
448: orig_display_errors = PG(display_errors);
449: PG(display_errors) = 0;
450: if (zend_stream_open(filename, file_handle TSRMLS_CC) == FAILURE) {
451: PG(display_errors) = orig_display_errors;
452: if (SG(request_info).path_translated != filename) {
453: STR_FREE(filename);
454: }
455: STR_FREE(SG(request_info).path_translated); /* for same reason as above */
456: SG(request_info).path_translated = NULL;
457: return FAILURE;
458: }
459: PG(display_errors) = orig_display_errors;
460:
461: if (SG(request_info).path_translated != filename) {
462: STR_FREE(SG(request_info).path_translated); /* for same reason as above */
463: SG(request_info).path_translated = filename;
464: }
465:
466: return SUCCESS;
467: }
468: /* }}} */
469:
470: /* {{{ php_resolve_path
471: * Returns the realpath for given filename according to include path
472: */
473: PHPAPI char *php_resolve_path(const char *filename, int filename_length, const char *path TSRMLS_DC)
474: {
475: char resolved_path[MAXPATHLEN];
476: char trypath[MAXPATHLEN];
477: const char *ptr, *end, *p;
478: char *actual_path;
479: php_stream_wrapper *wrapper;
480:
481: if (!filename || CHECK_NULL_PATH(filename, filename_length)) {
482: return NULL;
483: }
484:
485: /* Don't resolve paths which contain protocol (except of file://) */
486: for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
487: if ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/')) {
488: wrapper = php_stream_locate_url_wrapper(filename, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
489: if (wrapper == &php_plain_files_wrapper) {
490: if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
491: return estrdup(resolved_path);
492: }
493: }
494: return NULL;
495: }
496:
497: if ((*filename == '.' &&
498: (IS_SLASH(filename[1]) ||
499: ((filename[1] == '.') && IS_SLASH(filename[2])))) ||
500: IS_ABSOLUTE_PATH(filename, filename_length) ||
501: !path ||
502: !*path) {
503: if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
504: return estrdup(resolved_path);
505: } else {
506: return NULL;
507: }
508: }
509:
510: ptr = path;
511: while (ptr && *ptr) {
512: /* Check for stream wrapper */
513: int is_stream_wrapper = 0;
514:
515: for (p = ptr; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
516: if ((*p == ':') && (p - ptr > 1) && (p[1] == '/') && (p[2] == '/')) {
517: /* .:// or ..:// is not a stream wrapper */
518: if (p[-1] != '.' || p[-2] != '.' || p - 2 != ptr) {
519: p += 3;
520: is_stream_wrapper = 1;
521: }
522: }
523: end = strchr(p, DEFAULT_DIR_SEPARATOR);
524: if (end) {
525: if ((end-ptr) + 1 + filename_length + 1 >= MAXPATHLEN) {
526: ptr = end + 1;
527: continue;
528: }
529: memcpy(trypath, ptr, end-ptr);
530: trypath[end-ptr] = '/';
531: memcpy(trypath+(end-ptr)+1, filename, filename_length+1);
532: ptr = end+1;
533: } else {
534: int len = strlen(ptr);
535:
536: if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
537: break;
538: }
539: memcpy(trypath, ptr, len);
540: trypath[len] = '/';
541: memcpy(trypath+len+1, filename, filename_length+1);
542: ptr = NULL;
543: }
544: actual_path = trypath;
545: if (is_stream_wrapper) {
546: wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
547: if (!wrapper) {
548: continue;
549: } else if (wrapper != &php_plain_files_wrapper) {
550: if (wrapper->wops->url_stat) {
551: php_stream_statbuf ssb;
552:
553: if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
554: return estrdup(trypath);
555: }
556: }
557: continue;
558: }
559: }
560: if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
561: return estrdup(resolved_path);
562: }
563: } /* end provided path */
564:
565: /* check in calling scripts' current working directory as a fall back case
566: */
567: if (zend_is_executing(TSRMLS_C)) {
568: const char *exec_fname = zend_get_executed_filename(TSRMLS_C);
569: int exec_fname_length = strlen(exec_fname);
570:
571: while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
572: if (exec_fname && exec_fname[0] != '[' &&
573: exec_fname_length > 0 &&
574: exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
575: memcpy(trypath, exec_fname, exec_fname_length + 1);
576: memcpy(trypath+exec_fname_length + 1, filename, filename_length+1);
577: actual_path = trypath;
578:
579: /* Check for stream wrapper */
580: for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
581: if ((*p == ':') && (p - trypath > 1) && (p[1] == '/') && (p[2] == '/')) {
582: wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
583: if (!wrapper) {
584: return NULL;
585: } else if (wrapper != &php_plain_files_wrapper) {
586: if (wrapper->wops->url_stat) {
587: php_stream_statbuf ssb;
588:
589: if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
590: return estrdup(trypath);
591: }
592: }
593: return NULL;
594: }
595: }
596:
597: if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
598: return estrdup(resolved_path);
599: }
600: }
601: }
602:
603: return NULL;
604: }
605: /* }}} */
606:
607: /* {{{ php_fopen_with_path
608: * Tries to open a file with a PATH-style list of directories.
609: * If the filename starts with "." or "/", the path is ignored.
610: */
611: PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const char *path, char **opened_path TSRMLS_DC)
612: {
613: char *pathbuf, *ptr, *end;
614: const char *exec_fname;
615: char trypath[MAXPATHLEN];
616: FILE *fp;
617: int path_length;
618: int filename_length;
619: int exec_fname_length;
620:
621: if (opened_path) {
622: *opened_path = NULL;
623: }
624:
625: if (!filename) {
626: return NULL;
627: }
628:
629: filename_length = strlen(filename);
630:
631: /* Relative path open */
632: if ((*filename == '.')
633: /* Absolute path open */
634: || IS_ABSOLUTE_PATH(filename, filename_length)
635: || (!path || (path && !*path))
636: ) {
637: return php_fopen_and_set_opened_path(filename, mode, opened_path TSRMLS_CC);
638: }
639:
640: /* check in provided path */
641: /* append the calling scripts' current working directory
642: * as a fall back case
643: */
644: if (zend_is_executing(TSRMLS_C)) {
645: exec_fname = zend_get_executed_filename(TSRMLS_C);
646: exec_fname_length = strlen(exec_fname);
647: path_length = strlen(path);
648:
649: while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
650: if ((exec_fname && exec_fname[0] == '[') || exec_fname_length <= 0) {
651: /* [no active file] or no path */
652: pathbuf = estrdup(path);
653: } else {
654: pathbuf = (char *) emalloc(exec_fname_length + path_length + 1 + 1);
655: memcpy(pathbuf, path, path_length);
656: pathbuf[path_length] = DEFAULT_DIR_SEPARATOR;
657: memcpy(pathbuf + path_length + 1, exec_fname, exec_fname_length);
658: pathbuf[path_length + exec_fname_length + 1] = '\0';
659: }
660: } else {
661: pathbuf = estrdup(path);
662: }
663:
664: ptr = pathbuf;
665:
666: while (ptr && *ptr) {
667: end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
668: if (end != NULL) {
669: *end = '\0';
670: end++;
671: }
672: if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) {
673: php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN);
674: }
675: fp = php_fopen_and_set_opened_path(trypath, mode, opened_path TSRMLS_CC);
676: if (fp) {
677: efree(pathbuf);
678: return fp;
679: }
680: ptr = end;
681: } /* end provided path */
682:
683: efree(pathbuf);
684: return NULL;
685: }
686: /* }}} */
687:
688: /* {{{ php_strip_url_passwd
689: */
690: PHPAPI char *php_strip_url_passwd(char *url)
691: {
692: register char *p, *url_start;
693:
694: if (url == NULL) {
695: return "";
696: }
697:
698: p = url;
699:
700: while (*p) {
701: if (*p == ':' && *(p + 1) == '/' && *(p + 2) == '/') {
702: /* found protocol */
703: url_start = p = p + 3;
704:
705: while (*p) {
706: if (*p == '@') {
707: int i;
708:
709: for (i = 0; i < 3 && url_start < p; i++, url_start++) {
710: *url_start = '.';
711: }
712: for (; *p; p++) {
713: *url_start++ = *p;
714: }
715: *url_start=0;
716: break;
717: }
718: p++;
719: }
720: return url;
721: }
722: p++;
723: }
724: return url;
725: }
726: /* }}} */
727:
728: /* {{{ expand_filepath
729: */
730: PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC)
731: {
732: return expand_filepath_ex(filepath, real_path, NULL, 0 TSRMLS_CC);
733: }
734: /* }}} */
735:
736: /* {{{ expand_filepath_ex
737: */
738: PHPAPI char *expand_filepath_ex(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len TSRMLS_DC)
739: {
740: return expand_filepath_with_mode(filepath, real_path, relative_to, relative_to_len, CWD_FILEPATH TSRMLS_CC);
741: }
742: /* }}} */
743:
744: /* {{{ expand_filepath_use_realpath
745: */
746: PHPAPI char *expand_filepath_with_mode(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len, int realpath_mode TSRMLS_DC)
747: {
748: cwd_state new_state;
749: char cwd[MAXPATHLEN];
750: int copy_len;
751:
752: if (!filepath[0]) {
753: return NULL;
754: } else if (IS_ABSOLUTE_PATH(filepath, strlen(filepath))) {
755: cwd[0] = '\0';
756: } else {
757: const char *iam = SG(request_info).path_translated;
758: const char *result;
759: if (relative_to) {
760: if (relative_to_len > MAXPATHLEN-1U) {
761: return NULL;
762: }
763: result = relative_to;
764: memcpy(cwd, relative_to, relative_to_len+1U);
765: } else {
766: result = VCWD_GETCWD(cwd, MAXPATHLEN);
767: }
768:
769: if (!result && (iam != filepath)) {
770: int fdtest = -1;
771:
772: fdtest = VCWD_OPEN(filepath, O_RDONLY);
773: if (fdtest != -1) {
774: /* return a relative file path if for any reason
775: * we cannot cannot getcwd() and the requested,
776: * relatively referenced file is accessible */
777: copy_len = strlen(filepath) > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : strlen(filepath);
778: if (real_path) {
779: memcpy(real_path, filepath, copy_len);
780: real_path[copy_len] = '\0';
781: } else {
782: real_path = estrndup(filepath, copy_len);
783: }
784: close(fdtest);
785: return real_path;
786: } else {
787: cwd[0] = '\0';
788: }
789: } else if (!result) {
790: cwd[0] = '\0';
791: }
792: }
793:
794: new_state.cwd = strdup(cwd);
795: new_state.cwd_length = strlen(cwd);
796:
797: if (virtual_file_ex(&new_state, filepath, NULL, realpath_mode TSRMLS_CC)) {
798: free(new_state.cwd);
799: return NULL;
800: }
801:
802: if (real_path) {
803: copy_len = new_state.cwd_length > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : new_state.cwd_length;
804: memcpy(real_path, new_state.cwd, copy_len);
805: real_path[copy_len] = '\0';
806: } else {
807: real_path = estrndup(new_state.cwd, new_state.cwd_length);
808: }
809: free(new_state.cwd);
810:
811: return real_path;
812: }
813: /* }}} */
814:
815: /*
816: * Local variables:
817: * tab-width: 4
818: * c-basic-offset: 4
819: * End:
820: * vim600: sw=4 ts=4 fdm=marker
821: * vim<600: sw=4 ts=4
822: */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>