|
|
|
@ -90,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)) { |
|
|
|
@ -99,8 +103,64 @@ 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'; |
|
|
|
#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) { |
|
|
|
@ -110,7 +170,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; |
|
|
|
|