pajoye          Thu Oct 23 21:18:13 2008 UTC

  Modified files:              
    /php-src/ext/zip    php_zip.c 
  Log:
  - MFB: flatten path and make them relative before extraction
  
http://cvs.php.net/viewvc.cgi/php-src/ext/zip/php_zip.c?r1=1.62&r2=1.63&diff_format=u
Index: php-src/ext/zip/php_zip.c
diff -u php-src/ext/zip/php_zip.c:1.62 php-src/ext/zip/php_zip.c:1.63
--- php-src/ext/zip/php_zip.c:1.62      Tue Oct 21 23:36:17 2008
+++ php-src/ext/zip/php_zip.c   Thu Oct 23 21:18:13 2008
@@ -16,7 +16,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: php_zip.c,v 1.62 2008/10/21 23:36:17 lbarnaud Exp $ */
+/* $Id: php_zip.c,v 1.63 2008/10/23 21:18:13 pajoye Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -88,80 +88,153 @@
                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 making 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;
+}
 /* }}} */
 
+#ifdef ZEND_ENGINE_2_1
 /* {{{ 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;
        }
+
        /* it is a directory only, see #40228 */
-       if (file_len > 1 && file[file_len - 1] == '/') {
+       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, (unsigned 
int *)&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
@@ -169,8 +242,10 @@
         * safemode status as its parent folder?
         */
        if (OPENBASEDIR_CHECKPATH(fullpath)) {
+               efree(fullpath);
                efree(file_dirname_fullpath);
                efree(file_basename);
+               free(new_state.cwd);
                return 0;
        }
 
@@ -179,11 +254,15 @@
                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);
@@ -194,6 +273,7 @@
        efree(fullpath);
        efree(file_basename);
        efree(file_dirname_fullpath);
+       free(new_state.cwd);
 
        if (n<0) {
                return 0;
@@ -449,6 +529,9 @@
                return 0;
        }
 
+       /* we assume that any glob pattern will match files from one directory 
only
+          so checking the dirname of the first match should be sufficient */
+       strncpy(cwd, globbuf.gl_pathv[0], MAXPATHLEN);
        if (OPENBASEDIR_CHECKPATH(cwd)) {
                return -1;
        }
@@ -582,6 +665,8 @@
 /* }}} */
 #endif
 
+#endif
+
 /* {{{ arginfo */
 static
 ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_open, 0, 0, 1)
@@ -655,6 +740,7 @@
 /* }}} */
 
 /* {{{ ZE2 OO definitions */
+#ifdef ZEND_ENGINE_2_1
 static zend_class_entry *zip_class_entry;
 static zend_object_handlers zip_object_handlers;
 
@@ -671,8 +757,10 @@
 
        int type;
 } zip_prop_handler;
+#endif
 /* }}} */
 
+#ifdef ZEND_ENGINE_2_1
 static void php_zip_register_prop_handler(HashTable *prop_handler, char *name, 
zip_read_int_t read_int_func, zip_read_const_char_t read_char_func, 
zip_read_const_char_from_ze_t read_char_from_obj_func, int rettype TSRMLS_DC) 
/* {{{ */
 {
        zip_prop_handler hnd;
@@ -921,7 +1009,20 @@
        }
 
        intern->za = NULL;
+
+#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION == 1 && PHP_RELEASE_VERSION > 
2) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 
5)
        zend_object_std_dtor(&intern->zo TSRMLS_CC);
+#else
+       if (intern->zo.guards) {
+               zend_hash_destroy(intern->zo.guards);
+               FREE_HASHTABLE(intern->zo.guards);
+       }
+
+       if (intern->zo.properties) {
+               zend_hash_destroy(intern->zo.properties);
+               FREE_HASHTABLE(intern->zo.properties);
+       }
+#endif
 
        if (intern->filename) {
                efree(intern->filename);
@@ -945,7 +1046,14 @@
        intern->buffers_cnt = 0;
        intern->prop_handler = &zip_prop_handlers;
 
+#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION 
== 5 && PHP_MINOR_VERSION == 1 && PHP_RELEASE_VERSION > 2))
        zend_object_std_init(&intern->zo, class_type TSRMLS_CC);
+#else
+       ALLOC_HASHTABLE(intern->zo.properties);
+       zend_hash_init(intern->zo.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
+       intern->zo.ce = class_type;
+#endif
+
        zend_hash_copy(intern->zo.properties, &class_type->default_properties, 
(copy_ctor_func_t) zval_add_ref,
                                        (void *) &tmp, sizeof(zval *));
 
@@ -959,6 +1067,7 @@
        return retval;
 }
 /* }}} */
+#endif
 
 /* {{{ Resource dtors */
 
@@ -1063,7 +1172,7 @@
 
        rsrc_int = (zip_rsrc *)emalloc(sizeof(zip_rsrc));
 
-       rsrc_int->za = zip_open(filename, 0, &err);
+       rsrc_int->za = zip_open(resolved_path, 0, &err);
        if (rsrc_int->za == NULL) {
                efree(rsrc_int);
                RETURN_LONG((long)err);
@@ -1314,6 +1423,7 @@
 }
 /* }}} */
 
+#ifdef ZEND_ENGINE_2_1
 /* {{{ proto mixed ZipArchive::open(string source [, int flags]) U
 Create new zip using source uri for output, return TRUE on success or the 
error code */
 static ZIPARCHIVE_METHOD(open)
@@ -1351,7 +1461,7 @@
                RETURN_FALSE;
        }
 
-       if(!expand_filepath(filename, resolved_path TSRMLS_CC)) {
+       if (!expand_filepath(filename, resolved_path TSRMLS_CC)) {
                RETURN_FALSE;
        }
 
@@ -1366,6 +1476,7 @@
                efree(ze_obj->filename);
                ze_obj->filename = NULL;
        }
+
        intern = zip_open(resolved_path, flags, &err);
        if (!intern || err) {
                RETURN_LONG((long)err);
@@ -1450,11 +1561,11 @@
                        &dirname, &dirname_len, UG(ascii_conv)) == FAILURE) {
                return;
        }
+
        if (dirname_len<1) {
                RETURN_FALSE;
        }
 
-
        if (dirname[dirname_len-1] != '/') {
                s=(char *)emalloc(dirname_len+2);
                strcpy(s, dirname);
@@ -1480,7 +1591,6 @@
 }
 /* }}} */
 
-
 static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) 
/* {{{ */
 {
        struct zip *intern;
@@ -2387,7 +2497,6 @@
             }
         }
     }
-
        RETURN_TRUE;
 }
 /* }}} */
@@ -2448,6 +2557,7 @@
        buffer = safe_emalloc(len, 1, 2);
        n = zip_fread(zf, buffer, len);
        if (n < 1) {
+               efree(buffer);
                RETURN_EMPTY_STRING();
        }
 
@@ -2544,10 +2654,12 @@
        {NULL, NULL, NULL}
 };
 /* }}} */
+#endif
 
 /* {{{ PHP_MINIT_FUNCTION */
 static PHP_MINIT_FUNCTION(zip)
 {
+#ifdef ZEND_ENGINE_2_1
        zend_class_entry ce;
 
        memcpy(&zip_object_handlers, zend_get_std_object_handlers(), 
sizeof(zend_object_handlers));
@@ -2617,6 +2729,7 @@
        REGISTER_ZIP_CLASS_CONST_LONG("ER_DELETED",     ZIP_ER_DELETED);        
/* N Entry has been deleted */
 
        php_register_url_stream_wrapper("zip", &php_stream_zip_wrapper 
TSRMLS_CC);
+#endif
 
        le_zip_dir   = zend_register_list_destructors_ex(php_zip_free_dir,   
NULL, le_zip_dir_name,   module_number);
        le_zip_entry = zend_register_list_destructors_ex(php_zip_free_entry, 
NULL, le_zip_entry_name, module_number);
@@ -2629,9 +2742,10 @@
  */
 static PHP_MSHUTDOWN_FUNCTION(zip)
 {
+#ifdef ZEND_ENGINE_2_1
        zend_hash_destroy(&zip_prop_handlers);
        php_unregister_url_stream_wrapper("zip" TSRMLS_CC);
-
+#endif
        return SUCCESS;
 }
 /* }}} */
@@ -2643,7 +2757,7 @@
        php_info_print_table_start();
 
        php_info_print_table_row(2, "Zip", "enabled");
-       php_info_print_table_row(2, "Extension Version","$Id: php_zip.c,v 1.62 
2008/10/21 23:36:17 lbarnaud Exp $");
+       php_info_print_table_row(2, "Extension Version","$Id: php_zip.c,v 1.63 
2008/10/23 21:18:13 pajoye Exp $");
        php_info_print_table_row(2, "Zip version", PHP_ZIP_VERSION_STRING);
        php_info_print_table_row(2, "Libzip version", "0.9.0");
 

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to