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