summaryrefslogtreecommitdiff
path: root/main/fopen_wrappers.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/fopen_wrappers.c')
-rw-r--r--main/fopen_wrappers.c126
1 files changed, 102 insertions, 24 deletions
diff --git a/main/fopen_wrappers.c b/main/fopen_wrappers.c
index 6df4ada7e..41b0f2033 100644
--- a/main/fopen_wrappers.c
+++ b/main/fopen_wrappers.c
@@ -2,7 +2,7 @@
+----------------------------------------------------------------------+
| PHP Version 5 |
+----------------------------------------------------------------------+
- | Copyright (c) 1997-2006 The PHP Group |
+ | Copyright (c) 1997-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
@@ -17,7 +17,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: fopen_wrappers.c,v 1.175.2.3.2.1 2006/07/01 11:35:34 nlopess Exp $ */
+/* $Id: fopen_wrappers.c,v 1.175.2.3.2.11 2007/04/18 11:58:40 dmitry Exp $ */
/* {{{ includes
*/
@@ -46,12 +46,8 @@
#include "php_network.h"
#if HAVE_PWD_H
-#ifdef PHP_WIN32
-#include "win32/pwd.h"
-#else
#include <pwd.h>
#endif
-#endif
#include <sys/types.h>
#if HAVE_SYS_SOCKET_H
@@ -94,8 +90,12 @@ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path
char resolved_name[MAXPATHLEN];
char resolved_basedir[MAXPATHLEN];
char local_open_basedir[MAXPATHLEN];
+ char path_tmp[MAXPATHLEN];
+ char *path_file;
int resolved_basedir_len;
int resolved_name_len;
+ int path_len;
+ int nesting_level = 0;
/* Special case basedir==".": Use script-directory */
if (strcmp(basedir, ".") || !VCWD_GETCWD(local_open_basedir, MAXPATHLEN)) {
@@ -103,8 +103,66 @@ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path
strlcpy(local_open_basedir, basedir, sizeof(local_open_basedir));
}
- /* Resolve the real path into resolved_name */
- if ((expand_filepath(path, resolved_name TSRMLS_CC) != NULL) && (expand_filepath(local_open_basedir, resolved_basedir TSRMLS_CC) != NULL)) {
+ path_len = strlen(path);
+ if (path_len > (MAXPATHLEN - 1)) {
+ /* empty and too long paths are invalid */
+ return -1;
+ }
+
+ /* normalize and expand path */
+ if (expand_filepath(path, resolved_name TSRMLS_CC) == NULL) {
+ return -1;
+ }
+
+ path_len = strlen(resolved_name);
+ memcpy(path_tmp, resolved_name, path_len + 1); /* safe */
+
+ while (VCWD_REALPATH(path_tmp, resolved_name) == NULL) {
+#ifdef HAVE_SYMLINK
+ if (nesting_level == 0) {
+ int ret;
+ char buf[MAXPATHLEN];
+
+ ret = readlink(path_tmp, buf, MAXPATHLEN - 1);
+ if (ret < 0) {
+ /* not a broken symlink, move along.. */
+ } else {
+ /* put the real path into the path buffer */
+ memcpy(path_tmp, buf, ret);
+ path_tmp[ret] = '\0';
+ }
+ }
+#endif
+
+#if defined(PHP_WIN32) || defined(NETWARE)
+ path_file = strrchr(path_tmp, DEFAULT_SLASH);
+ if (!path_file) {
+ path_file = strrchr(path_tmp, '/');
+ }
+#else
+ path_file = strrchr(path_tmp, DEFAULT_SLASH);
+#endif
+ if (!path_file) {
+ /* none of the path components exist. definitely not in open_basedir.. */
+ return -1;
+ } else {
+ path_len = path_file - path_tmp + 1;
+#if defined(PHP_WIN32) || defined(NETWARE)
+ if (path_len > 1 && path_tmp[path_len - 2] == ':') {
+ /* this is c:\, */
+ path_tmp[path_len] = '\0';
+ } else {
+ path_tmp[path_len - 1] = '\0';
+ }
+#else
+ path_tmp[path_len - 1] = '\0';
+#endif
+ }
+ nesting_level++;
+ }
+
+ /* Resolve open_basedir to resolved_basedir */
+ if (expand_filepath(local_open_basedir, resolved_basedir TSRMLS_CC) != NULL) {
/* Handler for basedirs that end with a / */
resolved_basedir_len = strlen(resolved_basedir);
if (basedir[strlen(basedir) - 1] == PHP_DIR_SEPARATOR) {
@@ -114,7 +172,7 @@ PHPAPI int php_check_specific_open_basedir(const char *basedir, const char *path
}
}
- if (path[strlen(path)-1] == PHP_DIR_SEPARATOR) {
+ if (path_tmp[path_len - 1] == PHP_DIR_SEPARATOR) {
resolved_name_len = strlen(resolved_name);
if (resolved_name[resolved_name_len - 1] != PHP_DIR_SEPARATOR) {
resolved_name[resolved_name_len] = PHP_DIR_SEPARATOR;
@@ -259,39 +317,56 @@ static FILE *php_fopen_and_set_opened_path(const char *path, const char *mode, c
PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
{
FILE *fp;
+#ifndef PHP_WIN32
struct stat st;
+#endif
char *path_info, *filename;
int length;
filename = SG(request_info).path_translated;
path_info = SG(request_info).request_uri;
#if HAVE_PWD_H
- if (PG(user_dir) && *PG(user_dir)
- && path_info && '/' == path_info[0] && '~' == path_info[1]) {
-
- char user[32];
- struct passwd *pw;
+ if (PG(user_dir) && *PG(user_dir) && path_info && '/' == path_info[0] && '~' == path_info[1]) {
char *s = strchr(path_info + 2, '/');
filename = NULL; /* discard the original filename, it must not be used */
if (s) { /* if there is no path name after the file, do not bother */
- /* to try open the directory */
+ char user[32]; /* to try open the directory */
+ struct passwd *pw;
+#if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ struct passwd pwstruc;
+ long pwbuflen = sysconf(_SC_GETPW_R_SIZE_MAX);
+ char *pwbuf;
+
+ if (pwbuflen < 1) {
+ return FAILURE;
+ }
+
+ pwbuf = emalloc(pwbuflen);
+#endif
length = s - (path_info + 2);
- if (length > (int)sizeof(user) - 1)
+ if (length > (int)sizeof(user) - 1) {
length = sizeof(user) - 1;
+ }
memcpy(user, path_info + 2, length);
user[length] = '\0';
-
+#if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ if (getpwnam_r(user, &pwstruc, pwbuf, pwbuflen, &pw)) {
+ efree(pwbuf);
+ return FAILURE;
+ }
+#else
pw = getpwnam(user);
+#endif
if (pw && pw->pw_dir) {
- filename = emalloc(strlen(PG(user_dir)) + strlen(path_info) + strlen(pw->pw_dir) + 4);
- if (filename) {
- sprintf(filename, "%s%c%s%c%s", pw->pw_dir, PHP_DIR_SEPARATOR,
+ spprintf(&filename, 0, "%s%c%s%c%s", pw->pw_dir, PHP_DIR_SEPARATOR,
PG(user_dir), PHP_DIR_SEPARATOR, s+1); /* Safe */
- STR_FREE(SG(request_info).path_translated);
- SG(request_info).path_translated = filename;
- }
+ STR_FREE(SG(request_info).path_translated);
+ SG(request_info).path_translated = filename;
}
+#if defined(ZTS) && defined(HAVE_GETPWNAM_R) && defined(_SC_GETPW_R_SIZE_MAX)
+ efree(pwbuf);
+#endif
}
} else
#endif
@@ -325,11 +400,14 @@ PHPAPI int php_fopen_primary_script(zend_file_handle *file_handle TSRMLS_DC)
}
fp = VCWD_FOPEN(filename, "rb");
+#ifndef PHP_WIN32
/* refuse to open anything that is not a regular file */
if (fp && (0 > fstat(fileno(fp), &st) || !S_ISREG(st.st_mode))) {
fclose(fp);
fp = NULL;
}
+#endif
+
if (!fp) {
STR_FREE(SG(request_info).path_translated); /* for same reason as above */
SG(request_info).path_translated = NULL;
@@ -530,7 +608,7 @@ PHPAPI char *expand_filepath(const char *filepath, char *real_path TSRMLS_DC)
new_state.cwd = strdup(cwd);
new_state.cwd_length = strlen(cwd);
- if(virtual_file_ex(&new_state, filepath, NULL, 1)) {
+ if(virtual_file_ex(&new_state, filepath, NULL, CWD_FILEPATH)) {
free(new_state.cwd);
return NULL;
}