Sophie

Sophie

distrib > * > 2008.0 > x86_64 > by-pkgid > fb1832787a7adf918aad2d840f64675b > files > 16

php-5.2.4-3.5mdv2008.0.src.rpm

Index: ext/zip/php_zip.c
===================================================================
RCS file: /repository/php-src/ext/zip/php_zip.c,v
retrieving revision 1.1.2.43
retrieving revision 1.1.2.44
diff -u -p -r1.1.2.43 -r1.1.2.44
--- ext/zip/php_zip.c	18 Jan 2008 00:51:38 -0000	1.1.2.43
+++ ext/zip/php_zip.c	23 Oct 2008 16:13:50 -0000	1.1.2.44
@@ -79,81 +79,152 @@ static int le_zip_entry;
 		RETURN_FALSE; \
 	} \
 	RETURN_TRUE;
+/* }}} */
+
+#if (PHP_MAJOR_VERSION < 6)
+# define add_ascii_assoc_string add_assoc_string
+# define add_ascii_assoc_long add_assoc_long
+#endif
+
+/* Flatten a path by creating a relative path (to .) */
+static char * php_zip_make_relative_path(char *path, int path_len) /* {{{ */
+{
+	char *path_begin = path;
+	int prev_is_slash = 0;
+	char *e = path + path_len - 1;
+	size_t pos = path_len - 1;
+	size_t i;
+
+	if (IS_SLASH(path[0])) {
+		return path + 1;
+	}
+
+	if (path_len < 1 || path == NULL) {
+		return NULL;
+	}
 
+	i = path_len;
+
+	while (1) {
+		while (i > 0 && !IS_SLASH(path[i])) {
+			i--;
+		}
+
+		if (!i) {
+			return path;
+		}
+
+		if (i >= 2 && (path[i -1] == '.' || path[i -1] == ':')) {
+			/* i is the position of . or :, add 1 for / */
+			path_begin = path + i + 1;
+			break;
+		}
+		i--;
+	}
+
+	return path_begin;
+}
 /* }}} */
 
 /* {{{ php_zip_extract_file */
-/* TODO: Simplify it */
 static int php_zip_extract_file(struct zip * za, char *dest, char *file, int file_len TSRMLS_DC)
 {
 	php_stream_statbuf ssb;
 	struct zip_file *zf;
 	struct zip_stat sb;
 	char b[8192];
-
 	int n, len, ret;
-
 	php_stream *stream;
-
 	char *fullpath;
 	char *file_dirname_fullpath;
 	char file_dirname[MAXPATHLEN];
 	size_t dir_len;
-
 	char *file_basename;
 	size_t file_basename_len;
 	int is_dir_only = 0;
+	char *path_cleaned;
+	size_t path_cleaned_len;
+	cwd_state new_state;
+
+	new_state.cwd = (char*)malloc(1);
+	new_state.cwd[0] = '\0';
+	new_state.cwd_length = 0;
+
+	/* Clean/normlize the path and then transform any path (absolute or relative)
+		 to a path relative to cwd (../../mydir/foo.txt > mydir/foo.txt)
+	 */
+	virtual_file_ex(&new_state, file, NULL, CWD_EXPAND);
+	path_cleaned =  php_zip_make_relative_path(new_state.cwd, new_state.cwd_length);
+	path_cleaned_len = strlen(path_cleaned);
 
-	if (file_len >= MAXPATHLEN || zip_stat(za, file, 0, &sb) != 0) {
+	if (path_cleaned_len >= MAXPATHLEN || zip_stat(za, file, 0, &sb) != 0) {
 		return 0;
 	}
 
-	if (file_len > 1 && file[file_len - 1] == '/') {
+	/* it is a directory only, see #40228 */
+	if (path_cleaned_len > 1 && IS_SLASH(path_cleaned[path_cleaned_len - 1])) {
 		len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, file);
 		is_dir_only = 1;
 	} else {
-		memcpy(file_dirname, file, file_len);
-		dir_len = php_dirname(file_dirname, file_len);
+		memcpy(file_dirname, path_cleaned, path_cleaned_len);
+		dir_len = php_dirname(file_dirname, path_cleaned_len);
 
-		if (dir_len > 0) {
-			len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, file_dirname);
-		} else {
+		if (dir_len <= 0 || (dir_len == 1 && file_dirname[0] == '.')) {
 			len = spprintf(&file_dirname_fullpath, 0, "%s", dest);
+		} else {
+			len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, file_dirname);
 		}
 
-		php_basename(file, file_len, NULL, 0, &file_basename, (size_t *)&file_basename_len TSRMLS_CC);
+		php_basename(path_cleaned, path_cleaned_len, NULL, 0, &file_basename, (unsigned int *)&file_basename_len TSRMLS_CC);
 
 		if (OPENBASEDIR_CHECKPATH(file_dirname_fullpath)) {
 			efree(file_dirname_fullpath);
 			efree(file_basename);
+			free(new_state.cwd);
 			return 0;
 		}
 	}
 
 	/* let see if the path already exists */
 	if (php_stream_stat_path(file_dirname_fullpath, &ssb) < 0) {
-		ret = php_stream_mkdir(file_dirname_fullpath, 0777,  PHP_STREAM_MKDIR_RECURSIVE, NULL);
+
+#if defined(PHP_WIN32) && (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1)
+		char *e;
+		e = file_dirname_fullpath;
+		while (*e) {
+			   if (*e == '/') {
+					   *e = DEFAULT_SLASH;
+			   }
+			   e++;
+		}
+#endif
+
+		ret = php_stream_mkdir(file_dirname_fullpath, 0777,  PHP_STREAM_MKDIR_RECURSIVE|REPORT_ERRORS, NULL);
 		if (!ret) {
 			efree(file_dirname_fullpath);
+			if (!is_dir_only) {
 			efree(file_basename);
+				free(new_state.cwd);
+			}
 			return 0;
 		}
 	}
 
 	/* it is a standalone directory, job done */
-	if (file[file_len - 1] == '/') {
+	if (is_dir_only) {
 		efree(file_dirname_fullpath);
-		if (!is_dir_only) {
-			efree(file_basename);
-		}
+		free(new_state.cwd);
 		return 1;
 	}
 
-	len = spprintf(&fullpath, 0, "%s/%s/%s", dest, file_dirname, file_basename);
+	len = spprintf(&fullpath, 0, "%s/%s", file_dirname_fullpath, file_basename);
 	if (!len) {
 		efree(file_dirname_fullpath);
 		efree(file_basename);
+		free(new_state.cwd);
 		return 0;
+	} else if (len > MAXPATHLEN) {
+		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Full extraction path exceed MAXPATHLEN (%i)", MAXPATHLEN);
 	}
 
 	/* check again the full path, not sure if it
@@ -164,6 +235,7 @@ static int php_zip_extract_file(struct z
 		efree(fullpath);
 		efree(file_dirname_fullpath);
 		efree(file_basename);
+		free(new_state.cwd);
 		return 0;
 	}
 
@@ -172,10 +244,15 @@ static int php_zip_extract_file(struct z
 		efree(fullpath);
 		efree(file_dirname_fullpath);
 		efree(file_basename);
+		free(new_state.cwd);
 		return 0;
 	}
 
+#if (PHP_MAJOR_VERSION < 6)
 	stream = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL);
+#else
+	stream = php_stream_open_wrapper(fullpath, "w+b", REPORT_ERRORS, NULL);
+#endif
 	n = 0;
 	if (stream) {
 		while ((n=zip_fread(zf, b, sizeof(b))) > 0) php_stream_write(stream, b, n);
@@ -186,6 +263,7 @@ static int php_zip_extract_file(struct z
 	efree(fullpath);
 	efree(file_basename);
 	efree(file_dirname_fullpath);
+	free(new_state.cwd);
 
 	if (n<0) {
 		return 0;