diff options
Diffstat (limited to 'ext/zip/php_zip.c')
-rw-r--r-- | ext/zip/php_zip.c | 161 |
1 files changed, 55 insertions, 106 deletions
diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 8faa0cf0f9..79ac46df2b 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -95,99 +95,51 @@ static int le_zip_entry; # 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; - 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 PHP_ZIP_USE_OO +#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 (path_cleaned_len >= MAXPATHLEN || zip_stat(za, file, 0, &sb) != 0) { + if (file_len >= MAXPATHLEN || zip_stat(za, file, 0, &sb) != 0) { return 0; } - /* it is a directory only, see #40228 */ - if (path_cleaned_len > 1 && IS_SLASH(path_cleaned[path_cleaned_len - 1])) { + if (file_len > 1 && file[file_len - 1] == '/') { len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, file); is_dir_only = 1; } else { - memcpy(file_dirname, path_cleaned, path_cleaned_len); - dir_len = php_dirname(file_dirname, path_cleaned_len); + memcpy(file_dirname, file, file_len); + dir_len = php_dirname(file_dirname, file_len); - if (dir_len <= 0 || (dir_len == 1 && file_dirname[0] == '.')) { - len = spprintf(&file_dirname_fullpath, 0, "%s", dest); - } else { + if (dir_len > 0) { len = spprintf(&file_dirname_fullpath, 0, "%s/%s", dest, file_dirname); + } else { + len = spprintf(&file_dirname_fullpath, 0, "%s", dest); } - php_basename(path_cleaned, path_cleaned_len, NULL, 0, &file_basename, (unsigned int *)&file_basename_len TSRMLS_CC); + php_basename(file, file_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; } } @@ -206,32 +158,28 @@ static int php_zip_extract_file(struct zip * za, char *dest, char *file, int fil } #endif - ret = php_stream_mkdir(file_dirname_fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE|REPORT_ERRORS, NULL); + ret = php_stream_mkdir(file_dirname_fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL); if (!ret) { efree(file_dirname_fullpath); - if (!is_dir_only) { - efree(file_basename); - free(new_state.cwd); - } + efree(file_basename); return 0; } } /* it is a standalone directory, job done */ - if (is_dir_only) { + if (file[file_len - 1] == '/') { efree(file_dirname_fullpath); - free(new_state.cwd); + if (!is_dir_only) { + efree(file_basename); + } return 1; } - len = spprintf(&fullpath, 0, "%s/%s", file_dirname_fullpath, file_basename); + len = spprintf(&fullpath, 0, "%s/%s/%s", dest, file_dirname, 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 @@ -239,10 +187,8 @@ static int php_zip_extract_file(struct zip * za, char *dest, char *file, int fil * 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; } @@ -251,10 +197,8 @@ static int php_zip_extract_file(struct zip * za, char *dest, char *file, int fil 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 @@ -270,7 +214,6 @@ static int php_zip_extract_file(struct zip * za, char *dest, char *file, int fil efree(fullpath); efree(file_basename); efree(file_dirname_fullpath); - free(new_state.cwd); if (n<0) { return 0; @@ -529,7 +472,10 @@ int php_zip_glob(char *pattern, int pattern_len, long flags, zval *return_value /* 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)) { + if (PG(safe_mode) && (!php_checkuid(cwd, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { + return -1; + } + if (php_check_open_basedir(cwd TSRMLS_CC)) { return -1; } @@ -591,10 +537,14 @@ int php_zip_pcre(char *regexp, int regexp_len, char *path, int path_len, zval *r } #endif - if (OPENBASEDIR_CHECKPATH(path)) { + /* we assume that any glob pattern will match files from one directory only + so checking the dirname of the first match should be sufficient */ + if (PG(safe_mode) && (!php_checkuid(path, NULL, CHECKUID_CHECK_FILE_AND_DIR))) { + return -1; + } + if (php_check_open_basedir(path TSRMLS_CC)) { return -1; } - files_cnt = php_stream_scandir(path, &namelist, NULL, (void *) php_stream_dirent_alphasort); if (files_cnt > 0) { @@ -665,52 +615,62 @@ int php_zip_pcre(char *regexp, int regexp_len, char *path, int path_len, zval *r #endif /* {{{ arginfo */ +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_open, 0, 0, 1) ZEND_ARG_INFO(0, filename) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_close, 0, 0, 1) ZEND_ARG_INFO(0, zip) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_read, 0, 0, 1) ZEND_ARG_INFO(0, zip) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_entry_open, 0, 0, 2) ZEND_ARG_INFO(0, zip_dp) ZEND_ARG_INFO(0, zip_entry) ZEND_ARG_INFO(0, mode) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_entry_close, 0, 0, 1) ZEND_ARG_INFO(0, zip_ent) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_entry_read, 0, 0, 1) ZEND_ARG_INFO(0, zip_entry) ZEND_ARG_INFO(0, len) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_entry_name, 0, 0, 1) ZEND_ARG_INFO(0, zip_entry) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_entry_compressedsize, 0, 0, 1) ZEND_ARG_INFO(0, zip_entry) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_entry_filesize, 0, 0, 1) ZEND_ARG_INFO(0, zip_entry) ZEND_END_ARG_INFO() +static ZEND_BEGIN_ARG_INFO_EX(arginfo_zip_entry_compressionmethod, 0, 0, 1) ZEND_ARG_INFO(0, zip_entry) ZEND_END_ARG_INFO() /* }}} */ /* {{{ zend_function_entry */ -static const zend_function_entry zip_functions[] = { +static zend_function_entry zip_functions[] = { ZEND_RAW_FENTRY("zip_open", zif_zip_open, arginfo_zip_open, 0) ZEND_RAW_FENTRY("zip_close", zif_zip_close, arginfo_zip_close, 0) ZEND_RAW_FENTRY("zip_read", zif_zip_read, arginfo_zip_read, 0) @@ -727,7 +687,7 @@ static const zend_function_entry zip_functions[] = { /* }}} */ /* {{{ ZE2 OO definitions */ -#ifdef PHP_ZIP_USE_OO +#ifdef ZEND_ENGINE_2_1 static zend_class_entry *zip_class_entry; static zend_object_handlers zip_object_handlers; @@ -747,7 +707,7 @@ typedef struct _zip_prop_handler { #endif /* }}} */ -#ifdef PHP_ZIP_USE_OO +#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; @@ -1131,7 +1091,6 @@ static PHP_NAMED_FUNCTION(zif_zip_open) { char *filename; int filename_len; - char resolved_path[MAXPATHLEN + 1]; zip_rsrc *rsrc_int; int err = 0; @@ -1139,22 +1098,13 @@ static PHP_NAMED_FUNCTION(zif_zip_open) return; } - if (filename_len == 0) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty string as source"); - RETURN_FALSE; - } - if (OPENBASEDIR_CHECKPATH(filename)) { RETURN_FALSE; } - if(!expand_filepath(filename, resolved_path TSRMLS_CC)) { - RETURN_FALSE; - } - rsrc_int = (zip_rsrc *)emalloc(sizeof(zip_rsrc)); - rsrc_int->za = zip_open(resolved_path, 0, &err); + rsrc_int->za = zip_open(filename, 0, &err); if (rsrc_int->za == NULL) { efree(rsrc_int); RETURN_LONG((long)err); @@ -1234,8 +1184,8 @@ static PHP_NAMED_FUNCTION(zif_zip_entry_open) { zval * zip; zval * zip_entry; - char *mode = NULL; - int mode_len = 0; + char *mode; + int mode_len; zip_read_rsrc * zr_rsrc; zip_rsrc *z_rsrc; @@ -1404,7 +1354,7 @@ static PHP_NAMED_FUNCTION(zif_zip_entry_compressionmethod) } /* }}} */ -#ifdef PHP_ZIP_USE_OO +#ifdef ZEND_ENGINE_2_1 /* {{{ proto mixed ZipArchive::open(string source [, int flags]) Create new zip using source uri for output, return TRUE on success or the error code */ static ZIPARCHIVE_METHOD(open) @@ -1452,7 +1402,6 @@ static ZIPARCHIVE_METHOD(open) efree(ze_obj->filename); ze_obj->filename = NULL; } - intern = zip_open(resolved_path, flags, &err); if (!intern || err) { RETURN_LONG((long)err); @@ -1537,11 +1486,11 @@ static ZIPARCHIVE_METHOD(addEmptyDir) &dirname, &dirname_len) == FAILURE) { return; } - if (dirname_len<1) { RETURN_FALSE; } + if (dirname[dirname_len-1] != '/') { s=(char *)emalloc(dirname_len+2); strcpy(s, dirname); @@ -1572,10 +1521,10 @@ static void php_zip_add_from_pattern(INTERNAL_FUNCTION_PARAMETERS, int type) /* struct zip *intern; zval *this = getThis(); char *pattern; - char *path = NULL; + char *path; char *remove_path = NULL; char *add_path = NULL; - int pattern_len, add_path_len, remove_path_len, path_len = 0; + int pattern_len, add_path_len, remove_path_len, path_len; long remove_all_path = 0; long flags = 0; zval *options = NULL; @@ -2364,7 +2313,7 @@ static ZIPARCHIVE_METHOD(extractTo) } ZIP_FROM_OBJECT(intern, this); - if (zval_files && (Z_TYPE_P(zval_files) != IS_NULL)) { + if (zval_files) { switch (Z_TYPE_P(zval_files)) { case IS_STRING: if (!php_zip_extract_file(intern, pathto, Z_STRVAL_P(zval_files), Z_STRLEN_P(zval_files) TSRMLS_CC)) { @@ -2411,6 +2360,7 @@ static ZIPARCHIVE_METHOD(extractTo) } } } + RETURN_TRUE; } /* }}} */ @@ -2470,7 +2420,6 @@ static void php_zip_get_from(INTERNAL_FUNCTION_PARAMETERS, int type) /* {{{ */ buffer = safe_emalloc(len, 1, 2); n = zip_fread(zf, buffer, len); if (n < 1) { - efree(buffer); RETURN_EMPTY_STRING(); } @@ -2572,7 +2521,7 @@ static const zend_function_entry zip_class_functions[] = { /* {{{ PHP_MINIT_FUNCTION */ static PHP_MINIT_FUNCTION(zip) { -#ifdef PHP_ZIP_USE_OO +#ifdef ZEND_ENGINE_2_1 zend_class_entry ce; memcpy(&zip_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); @@ -2655,7 +2604,7 @@ static PHP_MINIT_FUNCTION(zip) */ static PHP_MSHUTDOWN_FUNCTION(zip) { -#ifdef PHP_ZIP_USE_OO +#ifdef ZEND_ENGINE_2_1 zend_hash_destroy(&zip_prop_handlers); php_unregister_url_stream_wrapper("zip" TSRMLS_CC); #endif |