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: 252 366 68.9 %
Date: 2014-04-18 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Fri, 18 Apr 2014 07:01:41 +0000 (6 days ago)

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