PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - main - fopen_wrappers.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 249 335 74.3 %
Date: 2014-11-22 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    +----------------------------------------------------------------------+
       3             :    | PHP Version 7                                                        |
       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$ */
      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       20526 : PHPAPI ZEND_INI_MH(OnUpdateBaseDir)
      85             : {
      86             :         char **p, *pathbuf, *ptr, *end;
      87             : #ifndef ZTS
      88       20526 :         char *base = (char *) mh_arg2;
      89             : #else
      90             :         char *base = (char *) ts_resource(*((int *) mh_arg2));
      91             : #endif
      92             : 
      93       20526 :         p = (char **) (base + (size_t) mh_arg1);
      94             : 
      95       20526 :         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       20516 :                 *p = new_value ? new_value->val : NULL;
      98       20516 :                 return SUCCESS;
      99             :         }
     100             : 
     101             :         /* Otherwise we're in runtime */
     102          10 :         if (!*p || !**p) {
     103             :                 /* open_basedir not set yet, go ahead and give it a value */
     104           8 :                 *p = new_value->val;
     105           8 :                 return SUCCESS;
     106             :         }
     107             : 
     108             :         /* Shortcut: When we have a open_basedir and someone tries to unset, we know it'll fail */
     109           2 :         if (!new_value || !*new_value->val) {
     110           0 :                 return FAILURE;
     111             :         }
     112             : 
     113             :         /* Is the proposed open_basedir at least as restrictive as the current setting? */
     114           2 :         ptr = pathbuf = estrdup(new_value->val);
     115           5 :         while (ptr && *ptr) {
     116           2 :                 end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
     117           2 :                 if (end != NULL) {
     118           0 :                         *end = '\0';
     119           0 :                         end++;
     120             :                 }
     121           2 :                 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           1 :                         efree(pathbuf);
     124           1 :                         return FAILURE;
     125             :                 }
     126           1 :                 ptr = end;
     127             :         }
     128           1 :         efree(pathbuf);
     129             : 
     130             :         /* Everything checks out, set it */
     131           1 :         *p = new_value->val;
     132             : 
     133           1 :         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        1096 : 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        1096 :         int nesting_level = 0;
     153             : 
     154             :         /* Special case basedir==".": Use script-directory */
     155        1096 :         if (strcmp(basedir, ".") || !VCWD_GETCWD(local_open_basedir, MAXPATHLEN)) {
     156             :                 /* Else use the unmodified path */
     157          29 :                 strlcpy(local_open_basedir, basedir, sizeof(local_open_basedir));
     158             :         }
     159             : 
     160        1096 :         path_len = (int)strlen(path);
     161        1096 :         if (path_len > (MAXPATHLEN - 1)) {
     162             :                 /* empty and too long paths are invalid */
     163           0 :                 return -1;
     164             :         }
     165             : 
     166             :         /* normalize and expand path */
     167        1096 :         if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
     168           1 :                 return -1;
     169             :         }
     170             : 
     171        1095 :         path_len = (int)strlen(resolved_name);
     172        1095 :         memcpy(path_tmp, resolved_name, path_len + 1); /* safe */
     173             : 
     174        2552 :         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         362 :                         if (nesting_level == 0) {
     180             :                                 int ret;
     181             :                                 char buf[MAXPATHLEN];
     182             : 
     183         359 :                                 ret = php_sys_readlink(path_tmp, buf, MAXPATHLEN - 1);
     184         359 :                                 if (ret < 0) {
     185             :                                         /* not a broken symlink, move along.. */
     186             :                                 } else {
     187             :                                         /* put the real path into the path buffer */
     188           0 :                                         memcpy(path_tmp, buf, ret);
     189           0 :                                         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         362 :                 path_file = strrchr(path_tmp, DEFAULT_SLASH);
     204             : #endif
     205         362 :                 if (!path_file) {
     206             :                         /* none of the path components exist. definitely not in open_basedir.. */
     207           0 :                         return -1;
     208             :                 } else {
     209         362 :                         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         362 :                         path_tmp[path_len - 1] = '\0';
     222             : #endif
     223             :                 }
     224         362 :                 nesting_level++;
     225             :         }
     226             : 
     227             :         /* Resolve open_basedir to resolved_basedir */
     228        1095 :         if (expand_filepath(local_open_basedir, resolved_basedir TSRMLS_CC) != NULL) {
     229        1095 :                 int basedir_len = (int)strlen(basedir);
     230             :                 /* Handler for basedirs that end with a / */
     231        1095 :                 resolved_basedir_len = (int)strlen(resolved_basedir);
     232             : #if defined(PHP_WIN32) || defined(NETWARE)
     233             :                 if (basedir[basedir_len - 1] == PHP_DIR_SEPARATOR || basedir[basedir_len - 1] == '/') {
     234             : #else
     235        1095 :                 if (basedir[basedir_len - 1] == PHP_DIR_SEPARATOR) {
     236             : #endif
     237           3 :                         if (resolved_basedir[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) {
     238           0 :                                 resolved_basedir[resolved_basedir_len] = PHP_DIR_SEPARATOR;
     239           0 :                                 resolved_basedir[++resolved_basedir_len] = '\0';
     240             :                         }
     241             :                 } else {
     242        1092 :                                 resolved_basedir[resolved_basedir_len++] = PHP_DIR_SEPARATOR;
     243        1092 :                                 resolved_basedir[resolved_basedir_len] = '\0';
     244             :                 }
     245             : 
     246        1095 :                 resolved_name_len = (int)strlen(resolved_name);
     247        1095 :                 if (path_tmp[path_len - 1] == PHP_DIR_SEPARATOR) {
     248          69 :                         if (resolved_name[resolved_name_len - 1] != PHP_DIR_SEPARATOR) {
     249          37 :                                 resolved_name[resolved_name_len] = PHP_DIR_SEPARATOR;
     250          37 :                                 resolved_name[++resolved_name_len] = '\0';
     251             :                         }
     252             :                 }
     253             : 
     254             :                 /* Check the path */
     255             : #if defined(PHP_WIN32) || defined(NETWARE)
     256             :                 if (strncasecmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) {
     257             : #else
     258        1095 :                 if (strncmp(resolved_basedir, resolved_name, resolved_basedir_len) == 0) {
     259             : #endif
     260        1007 :                         if (resolved_name_len > resolved_basedir_len &&
     261         502 :                                 resolved_name[resolved_basedir_len - 1] != PHP_DIR_SEPARATOR) {
     262           0 :                                 return -1;
     263             :                         } else {
     264             :                                 /* File is in the right directory */
     265         505 :                                 return 0;
     266             :                         }
     267             :                 } else {
     268             :                         /* /openbasedir/ and /openbasedir are the same directory */
     269         590 :                         if (resolved_basedir_len == (resolved_name_len + 1) && resolved_basedir[resolved_basedir_len - 1] == PHP_DIR_SEPARATOR) {
     270             : #if defined(PHP_WIN32) || defined(NETWARE)
     271             :                                 if (strncasecmp(resolved_basedir, resolved_name, resolved_name_len) == 0) {
     272             : #else
     273         250 :                                 if (strncmp(resolved_basedir, resolved_name, resolved_name_len) == 0) {
     274             : #endif
     275         249 :                                         return 0;
     276             :                                 }
     277             :                         }
     278         341 :                         return -1;
     279             :                 }
     280             :         } else {
     281             :                 /* Unable to resolve the real path, return -1 */
     282           0 :                 return -1;
     283             :         }
     284             : }
     285             : /* }}} */
     286             : 
     287      406362 : PHPAPI int php_check_open_basedir(const char *path TSRMLS_DC)
     288             : {
     289      406362 :         return php_check_open_basedir_ex(path, 1 TSRMLS_CC);
     290             : }
     291             : 
     292             : /* {{{ php_check_open_basedir
     293             :  */
     294      460604 : PHPAPI int php_check_open_basedir_ex(const char *path, int warn TSRMLS_DC)
     295             : {
     296             :         /* Only check when open_basedir is available */
     297      460604 :         if (PG(open_basedir) && *PG(open_basedir)) {
     298             :                 char *pathbuf;
     299             :                 char *ptr;
     300             :                 char *end;
     301             : 
     302             :                 /* Check if the path is too long so we can give a more useful error
     303             :                 * message. */
     304        1097 :                 if (strlen(path) > (MAXPATHLEN - 1)) {
     305           1 :                         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);
     306           1 :                         errno = EINVAL;
     307           1 :                         return -1;
     308             :                 }
     309             : 
     310        1096 :                 pathbuf = estrdup(PG(open_basedir));
     311             : 
     312        1096 :                 ptr = pathbuf;
     313             : 
     314        2534 :                 while (ptr && *ptr) {
     315        1096 :                         end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
     316        1096 :                         if (end != NULL) {
     317           0 :                                 *end = '\0';
     318           0 :                                 end++;
     319             :                         }
     320             : 
     321        1096 :                         if (php_check_specific_open_basedir(ptr, path TSRMLS_CC) == 0) {
     322         754 :                                 efree(pathbuf);
     323         754 :                                 return 0;
     324             :                         }
     325             : 
     326         342 :                         ptr = end;
     327             :                 }
     328         342 :                 if (warn) {
     329         315 :                         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));
     330             :                 }
     331         342 :                 efree(pathbuf);
     332         342 :                 errno = EPERM; /* we deny permission to open it */
     333         342 :                 return -1;
     334             :         }
     335             : 
     336             :         /* Nothing to check... */
     337      459507 :         return 0;
     338             : }
     339             : /* }}} */
     340             : 
     341             : /* {{{ php_fopen_and_set_opened_path
     342             :  */
     343         132 : static FILE *php_fopen_and_set_opened_path(const char *path, const char *mode, char **opened_path TSRMLS_DC)
     344             : {
     345             :         FILE *fp;
     346             : 
     347         132 :         if (php_check_open_basedir((char *)path TSRMLS_CC)) {
     348           0 :                 return NULL;
     349             :         }
     350         132 :         fp = VCWD_FOPEN(path, mode);
     351         132 :         if (fp && opened_path) {
     352           0 :                 *opened_path = expand_filepath_with_mode(path, NULL, NULL, 0, CWD_EXPAND TSRMLS_CC);
     353             :         }
     354         132 :         return fp;
     355             : }
     356             : /* }}} */
     357             : 
     358             : /* {{{ php_fopen_primary_script
     359             :  */
     360         401 : PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
     361             : {
     362             :         char *path_info;
     363         401 :         char *filename = NULL;
     364         401 :         char *resolved_path = NULL;
     365             :         int length;
     366             :         zend_bool orig_display_errors;
     367             : 
     368         401 :         path_info = SG(request_info).request_uri;
     369             : #if HAVE_PWD_H
     370         401 :         if (PG(user_dir) && *PG(user_dir) && path_info && '/' == path_info[0] && '~' == path_info[1]) {
     371           0 :                 char *s = strchr(path_info + 2, '/');
     372             : 
     373           0 :                 if (s) {                        /* if there is no path name after the file, do not bother */
     374             :                         char user[32];                  /* to try open the directory */
     375             :                         struct passwd *pw;
     376             : #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
     377             :                         struct passwd pwstruc;
     378             :                         long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
     379             :                         char *pwbuf;
     380             : 
     381             :                         if (pwbuflen < 1) {
     382             :                                 return FAILURE;
     383             :                         }
     384             : 
     385             :                         pwbuf = emalloc(pwbuflen);
     386             : #endif
     387           0 :                         length = s - (path_info + 2);
     388           0 :                         if (length > (int)sizeof(user) - 1) {
     389           0 :                                 length = sizeof(user) - 1;
     390             :                         }
     391           0 :                         memcpy(user, path_info + 2, length);
     392           0 :                         user[length] = '\0';
     393             : #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
     394             :                         if (getpwnam_r(user, &pwstruc, pwbuf, pwbuflen, &pw)) {
     395             :                                 efree(pwbuf);
     396             :                                 return FAILURE;
     397             :                         }
     398             : #else
     399           0 :                         pw = getpwnam(user);
     400             : #endif
     401           0 :                         if (pw && pw->pw_dir) {
     402           0 :                                 spprintf(&filename, 0, "%s%c%s%c%s", pw->pw_dir, PHP_DIR_SEPARATOR, PG(user_dir), PHP_DIR_SEPARATOR, s + 1); /* Safe */
     403             :                         } else {
     404           0 :                                 filename = SG(request_info).path_translated;
     405             :                         } 
     406             : #if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
     407             :                         efree(pwbuf);
     408             : #endif
     409             :                 }
     410             :         } else
     411             : #endif
     412         401 :         if (PG(doc_root) && path_info && (length = (int)strlen(PG(doc_root))) &&
     413           0 :                 IS_ABSOLUTE_PATH(PG(doc_root), length)) {
     414           0 :                 int path_len = (int)strlen(path_info);
     415           0 :                 filename = emalloc(length + path_len + 2);
     416           0 :                 if (filename) {
     417           0 :                         memcpy(filename, PG(doc_root), length);
     418           0 :                         if (!IS_SLASH(filename[length - 1])) {  /* length is never 0 */
     419           0 :                                 filename[length++] = PHP_DIR_SEPARATOR;
     420             :                         }
     421           0 :                         if (IS_SLASH(path_info[0])) {
     422           0 :                                 length--;
     423             :                         }
     424           0 :                         strncpy(filename + length, path_info, path_len + 1);
     425             :                 }
     426             :         } else {
     427         401 :                 filename = SG(request_info).path_translated;
     428             :         }
     429             : 
     430             : 
     431         401 :         if (filename) {
     432         401 :                 resolved_path = zend_resolve_path(filename, (int)strlen(filename) TSRMLS_CC);
     433             :         }
     434             : 
     435         401 :         if (!resolved_path) {
     436           7 :                 if (SG(request_info).path_translated != filename) {
     437           0 :                         if (filename) {
     438           0 :                                 efree(filename);
     439             :                         }
     440             :                 }
     441             :                 /* we have to free SG(request_info).path_translated here because
     442             :                  * php_destroy_request_info assumes that it will get
     443             :                  * freed when the include_names hash is emptied, but
     444             :                  * we're not adding it in this case */
     445           7 :                 if (SG(request_info).path_translated) {
     446           7 :                         efree(SG(request_info).path_translated);
     447           7 :                         SG(request_info).path_translated = NULL;
     448             :                 }
     449           7 :                 return FAILURE;
     450             :         }
     451         394 :         efree(resolved_path);
     452             : 
     453         394 :         orig_display_errors = PG(display_errors);
     454         394 :         PG(display_errors) = 0;
     455         394 :         if (zend_stream_open(filename, file_handle TSRMLS_CC) == FAILURE) {
     456           0 :                 PG(display_errors) = orig_display_errors;
     457           0 :                 if (SG(request_info).path_translated != filename) {
     458           0 :                         if (filename) {
     459           0 :                                 efree(filename);
     460             :                         }
     461             :                 }
     462           0 :                 if (SG(request_info).path_translated) {
     463           0 :                         efree(SG(request_info).path_translated);
     464           0 :                         SG(request_info).path_translated = NULL;
     465             :                 }
     466           0 :                 return FAILURE;
     467             :         }
     468         394 :         PG(display_errors) = orig_display_errors;
     469             : 
     470         394 :         if (SG(request_info).path_translated != filename) {
     471           0 :                 if (SG(request_info).path_translated) {
     472           0 :                         efree(SG(request_info).path_translated);
     473             :                 }
     474           0 :                 SG(request_info).path_translated = filename;
     475             :         }
     476             : 
     477         394 :         return SUCCESS;
     478             : }
     479             : /* }}} */
     480             : 
     481             : /* {{{ php_resolve_path
     482             :  * Returns the realpath for given filename according to include path
     483             :  */
     484       15430 : PHPAPI char *php_resolve_path(const char *filename, int filename_length, const char *path TSRMLS_DC)
     485             : {
     486             :         char resolved_path[MAXPATHLEN];
     487             :         char trypath[MAXPATHLEN];
     488             :         const char *ptr, *end, *p;
     489             :         const char *actual_path;
     490             :         php_stream_wrapper *wrapper;
     491             : 
     492       15430 :         if (!filename || CHECK_NULL_PATH(filename, filename_length)) {
     493           0 :                 return NULL;
     494             :         }
     495             : 
     496             :         /* Don't resolve paths which contain protocol (except of file://) */
     497       15430 :         for (p = filename; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
     498       15430 :         if ((*p == ':') && (p - filename > 1) && (p[1] == '/') && (p[2] == '/')) {
     499         285 :                 wrapper = php_stream_locate_url_wrapper(filename, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
     500         285 :                 if (wrapper == &php_plain_files_wrapper) {
     501           4 :                         if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
     502           2 :                                 return estrdup(resolved_path);
     503             :                         }
     504             :                 }
     505         283 :                 return NULL;
     506             :         }
     507             : 
     508       36806 :         if ((*filename == '.' && 
     509           4 :              (IS_SLASH(filename[1]) || 
     510           0 :               ((filename[1] == '.') && IS_SLASH(filename[2])))) ||
     511       15141 :             IS_ABSOLUTE_PATH(filename, filename_length) ||
     512             :             !path ||
     513        6516 :             !*path) {
     514        8629 :                 if (tsrm_realpath(filename, resolved_path TSRMLS_CC)) {
     515        8618 :                         return estrdup(resolved_path);
     516             :                 } else {
     517          11 :                         return NULL;
     518             :                 }
     519             :         }
     520             : 
     521        6516 :         ptr = path;
     522       25897 :         while (ptr && *ptr) {
     523             :                 /* Check for stream wrapper */
     524       12980 :                 int is_stream_wrapper = 0;
     525             : 
     526       12980 :                 for (p = ptr; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
     527       12980 :                 if ((*p == ':') && (p - ptr > 1) && (p[1] == '/') && (p[2] == '/')) {
     528             :                         /* .:// or ..:// is not a stream wrapper */
     529          45 :                         if (p[-1] != '.' || p[-2] != '.' || p - 2 != ptr) {
     530          45 :                                 p += 3;
     531          45 :                                 is_stream_wrapper = 1;
     532             :                         }
     533             :                 }
     534       12980 :                 end = strchr(p, DEFAULT_DIR_SEPARATOR);
     535       12980 :                 if (end) {
     536        6577 :                         if ((end-ptr) + 1 + filename_length + 1 >= MAXPATHLEN) {
     537           0 :                                 ptr = end + 1;
     538           0 :                                 continue;
     539             :                         }
     540        6577 :                         memcpy(trypath, ptr, end-ptr);
     541        6577 :                         trypath[end-ptr] = '/';
     542        6577 :                         memcpy(trypath+(end-ptr)+1, filename, filename_length+1);
     543        6577 :                         ptr = end+1;
     544             :                 } else {
     545        6403 :                         int len = (int)strlen(ptr);
     546             : 
     547        6403 :                         if (len + 1 + filename_length + 1 >= MAXPATHLEN) {
     548           0 :                                 break;
     549             :                         }
     550        6403 :                         memcpy(trypath, ptr, len);
     551        6403 :                         trypath[len] = '/';
     552        6403 :                         memcpy(trypath+len+1, filename, filename_length+1);
     553        6403 :                         ptr = NULL;
     554             :                 }
     555       12980 :                 actual_path = trypath;
     556       12980 :                 if (is_stream_wrapper) {
     557          45 :                         wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
     558          45 :                         if (!wrapper) {
     559           0 :                                 continue;
     560          45 :                         } else if (wrapper != &php_plain_files_wrapper) {
     561          45 :                                 if (wrapper->wops->url_stat) {
     562             :                                         php_stream_statbuf ssb;
     563             : 
     564          45 :                                         if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
     565          33 :                                                 return estrdup(trypath);
     566             :                                         }
     567             :                                 }
     568          12 :                                 continue;
     569             :                         }
     570             :                 }
     571       12935 :                 if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
     572          82 :                         return estrdup(resolved_path);
     573             :                 }
     574             :         } /* end provided path */
     575             : 
     576             :         /* check in calling scripts' current working directory as a fall back case
     577             :          */
     578        6401 :         if (zend_is_executing(TSRMLS_C)) {
     579        6394 :                 const char *exec_fname = zend_get_executed_filename(TSRMLS_C);
     580        6394 :                 int exec_fname_length = (int)strlen(exec_fname);
     581             : 
     582      153666 :                 while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
     583       12788 :                 if (exec_fname && exec_fname[0] != '[' &&
     584             :                     exec_fname_length > 0 &&
     585        6394 :                     exec_fname_length + 1 + filename_length + 1 < MAXPATHLEN) {
     586        6394 :                         memcpy(trypath, exec_fname, exec_fname_length + 1);
     587        6394 :                         memcpy(trypath+exec_fname_length + 1, filename, filename_length+1);
     588        6394 :                         actual_path = trypath;
     589             : 
     590             :                         /* Check for stream wrapper */
     591        6394 :                         for (p = trypath; isalnum((int)*p) || *p == '+' || *p == '-' || *p == '.'; p++);
     592        6394 :                         if ((*p == ':') && (p - trypath > 1) && (p[1] == '/') && (p[2] == '/')) {
     593           4 :                                 wrapper = php_stream_locate_url_wrapper(trypath, &actual_path, STREAM_OPEN_FOR_INCLUDE TSRMLS_CC);
     594           4 :                                 if (!wrapper) {
     595           0 :                                         return NULL;
     596           4 :                                 } else if (wrapper != &php_plain_files_wrapper) {
     597           4 :                                         if (wrapper->wops->url_stat) {
     598             :                                                 php_stream_statbuf ssb;
     599             : 
     600           4 :                                                 if (SUCCESS == wrapper->wops->url_stat(wrapper, trypath, 0, &ssb, NULL TSRMLS_CC)) {
     601           2 :                                                         return estrdup(trypath);
     602             :                                                 }
     603             :                                         }
     604           2 :                                         return NULL;
     605             :                                 }
     606             :                         }
     607             : 
     608        6390 :                         if (tsrm_realpath(actual_path, resolved_path TSRMLS_CC)) {
     609        6318 :                                 return estrdup(resolved_path);
     610             :                         }
     611             :                 }
     612             :         }
     613             : 
     614          79 :         return NULL;
     615             : }
     616             : /* }}} */
     617             : 
     618             : /* {{{ php_fopen_with_path
     619             :  * Tries to open a file with a PATH-style list of directories.
     620             :  * If the filename starts with "." or "/", the path is ignored.
     621             :  */
     622          66 : PHPAPI FILE *php_fopen_with_path(const char *filename, const char *mode, const char *path, char **opened_path TSRMLS_DC)
     623             : {
     624             :         char *pathbuf, *ptr, *end;
     625             :         const char *exec_fname;
     626             :         char trypath[MAXPATHLEN];
     627             :         FILE *fp;
     628             :         int path_length;
     629             :         int filename_length;
     630             :         int exec_fname_length;
     631             : 
     632          66 :         if (opened_path) {
     633          66 :                 *opened_path = NULL;
     634             :         }
     635             : 
     636          66 :         if (!filename) {
     637           0 :                 return NULL;
     638             :         }
     639             : 
     640          66 :         filename_length = (int)strlen(filename);
     641             : 
     642             :         /* Relative path open */
     643         198 :         if ((*filename == '.')
     644             :         /* Absolute path open */
     645          66 :          || IS_ABSOLUTE_PATH(filename, filename_length)
     646          66 :          || (!path || (path && !*path))
     647             :         ) {
     648           0 :                 return php_fopen_and_set_opened_path(filename, mode, opened_path TSRMLS_CC);
     649             :         }
     650             : 
     651             :         /* check in provided path */
     652             :         /* append the calling scripts' current working directory
     653             :          * as a fall back case
     654             :          */
     655          66 :         if (zend_is_executing(TSRMLS_C)) {
     656           0 :                 exec_fname = zend_get_executed_filename(TSRMLS_C);
     657           0 :                 exec_fname_length = (int)strlen(exec_fname);
     658           0 :                 path_length = (int)strlen(path);
     659             : 
     660           0 :                 while ((--exec_fname_length >= 0) && !IS_SLASH(exec_fname[exec_fname_length]));
     661           0 :                 if ((exec_fname && exec_fname[0] == '[') || exec_fname_length <= 0) {
     662             :                         /* [no active file] or no path */
     663           0 :                         pathbuf = estrdup(path);
     664             :                 } else {
     665           0 :                         pathbuf = (char *) emalloc(exec_fname_length + path_length + 1 + 1);
     666           0 :                         memcpy(pathbuf, path, path_length);
     667           0 :                         pathbuf[path_length] = DEFAULT_DIR_SEPARATOR;
     668           0 :                         memcpy(pathbuf + path_length + 1, exec_fname, exec_fname_length);
     669           0 :                         pathbuf[path_length + exec_fname_length + 1] = '\0';
     670             :                 }
     671             :         } else {
     672          66 :                 pathbuf = estrdup(path);
     673             :         }
     674             : 
     675          66 :         ptr = pathbuf;
     676             : 
     677         264 :         while (ptr && *ptr) {
     678         132 :                 end = strchr(ptr, DEFAULT_DIR_SEPARATOR);
     679         132 :                 if (end != NULL) {
     680          66 :                         *end = '\0';
     681          66 :                         end++;
     682             :                 }
     683         132 :                 if (snprintf(trypath, MAXPATHLEN, "%s/%s", ptr, filename) >= MAXPATHLEN) {
     684           0 :                         php_error_docref(NULL TSRMLS_CC, E_NOTICE, "%s/%s path was truncated to %d", ptr, filename, MAXPATHLEN);
     685             :                 }
     686         132 :                 fp = php_fopen_and_set_opened_path(trypath, mode, opened_path TSRMLS_CC);
     687         132 :                 if (fp) {
     688           0 :                         efree(pathbuf);
     689           0 :                         return fp;
     690             :                 }
     691         132 :                 ptr = end;
     692             :         } /* end provided path */
     693             : 
     694          66 :         efree(pathbuf);
     695          66 :         return NULL;
     696             : }
     697             : /* }}} */
     698             : 
     699             : /* {{{ php_strip_url_passwd
     700             :  */
     701         536 : PHPAPI char *php_strip_url_passwd(char *url)
     702             : {
     703             :         register char *p, *url_start;
     704             : 
     705         536 :         if (url == NULL) {
     706           0 :                 return "";
     707             :         }
     708             : 
     709         536 :         p = url;
     710             : 
     711       18275 :         while (*p) {
     712       17355 :                 if (*p == ':' && *(p + 1) == '/' && *(p + 2) == '/') {
     713             :                         /* found protocol */
     714         152 :                         url_start = p = p + 3;
     715             : 
     716        7243 :                         while (*p) {
     717        6941 :                                 if (*p == '@') {
     718             :                                         int i;
     719             : 
     720           8 :                                         for (i = 0; i < 3 && url_start < p; i++, url_start++) {
     721           6 :                                                 *url_start = '.';
     722             :                                         }
     723          24 :                                         for (; *p; p++) {
     724          22 :                                                 *url_start++ = *p;
     725             :                                         }
     726           2 :                                         *url_start=0;
     727           2 :                                         break;
     728             :                                 }
     729        6939 :                                 p++;
     730             :                         }
     731         152 :                         return url;
     732             :                 }
     733       17203 :                 p++;
     734             :         }
     735         384 :         return url;
     736             : }
     737             : /* }}} */
     738             : 
     739             : /* {{{ expand_filepath
     740             :  */
     741      114653 : PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC)
     742             : {
     743      114653 :         return expand_filepath_ex(filepath, real_path, NULL, 0 TSRMLS_CC);
     744             : }
     745             : /* }}} */
     746             : 
     747             : /* {{{ expand_filepath_ex
     748             :  */
     749      114821 : PHPAPI char *expand_filepath_ex(const char *filepath, char *real_path, const char *relative_to, size_t relative_to_len TSRMLS_DC)
     750             : {
     751      114821 :         return expand_filepath_with_mode(filepath, real_path, relative_to, relative_to_len, CWD_FILEPATH TSRMLS_CC);
     752             : }
     753             : /* }}} */
     754             : 
     755             : /* {{{ expand_filepath_use_realpath
     756             :  */
     757      115416 : 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)
     758             : {
     759             :         cwd_state new_state;
     760             :         char cwd[MAXPATHLEN];
     761             :         int copy_len;
     762             :         int path_len;
     763             : 
     764      115416 :         if (!filepath[0]) {
     765           2 :                 return NULL;
     766             :         }
     767             : 
     768      115414 :         path_len = (int)strlen(filepath);
     769             : 
     770      115414 :         if (IS_ABSOLUTE_PATH(filepath, path_len)) {
     771      114161 :                 cwd[0] = '\0';
     772             :         } else {
     773        1253 :                 const char *iam = SG(request_info).path_translated;
     774             :                 const char *result;
     775        1253 :                 if (relative_to) {
     776          32 :                         if (relative_to_len > MAXPATHLEN-1U) {
     777           0 :                                 return NULL;
     778             :                         }
     779          32 :                         result = relative_to;
     780          32 :                         memcpy(cwd, relative_to, relative_to_len+1U);
     781             :                 } else {
     782        1221 :                         result = VCWD_GETCWD(cwd, MAXPATHLEN);
     783             :                 }
     784             : 
     785        1253 :                 if (!result && (iam != filepath)) {
     786           0 :                         int fdtest = -1;
     787             : 
     788           0 :                         fdtest = VCWD_OPEN(filepath, O_RDONLY);
     789           0 :                         if (fdtest != -1) {
     790             :                                 /* return a relative file path if for any reason
     791             :                                  * we cannot cannot getcwd() and the requested,
     792             :                                  * relatively referenced file is accessible */
     793           0 :                                 copy_len = path_len > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : path_len;
     794           0 :                                 if (real_path) {
     795           0 :                                         memcpy(real_path, filepath, copy_len);
     796           0 :                                         real_path[copy_len] = '\0';
     797             :                                 } else {
     798           0 :                                         real_path = estrndup(filepath, copy_len);
     799             :                                 }
     800           0 :                                 close(fdtest);
     801           0 :                                 return real_path;
     802             :                         } else {
     803           0 :                                 cwd[0] = '\0';
     804             :                         }
     805        1253 :                 } else if (!result) {
     806           0 :                         cwd[0] = '\0';
     807             :                 }
     808             :         }
     809             : 
     810      115414 :         new_state.cwd = estrdup(cwd);
     811      115414 :         new_state.cwd_length = (int)strlen(cwd);
     812             : 
     813      115414 :         if (virtual_file_ex(&new_state, filepath, NULL, realpath_mode TSRMLS_CC)) {
     814           3 :                 efree(new_state.cwd);
     815           3 :                 return NULL;
     816             :         }
     817             : 
     818      115411 :         if (real_path) {
     819       23408 :                 copy_len = new_state.cwd_length > MAXPATHLEN - 1 ? MAXPATHLEN - 1 : new_state.cwd_length;
     820       23408 :                 memcpy(real_path, new_state.cwd, copy_len);
     821       23408 :                 real_path[copy_len] = '\0';
     822             :         } else {
     823       92003 :                 real_path = estrndup(new_state.cwd, new_state.cwd_length);
     824             :         }
     825      115411 :         efree(new_state.cwd);
     826             : 
     827      115411 :         return real_path;
     828             : }
     829             : /* }}} */
     830             : 
     831             : /*
     832             :  * Local variables:
     833             :  * tab-width: 4
     834             :  * c-basic-offset: 4
     835             :  * End:
     836             :  * vim600: sw=4 ts=4 fdm=marker
     837             :  * vim<600: sw=4 ts=4
     838             :  */

Generated by: LCOV version 1.10

Generated at Sat, 22 Nov 2014 23:01:30 +0000 (5 days ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.