From 69ffa728745674395e9d82c3f00370ddde8e52c5 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Fri, 5 Mar 2021 14:21:13 +0100 Subject: [PATCH] Fix #80833: ZipArchive::getStream doesn't use setPassword As already elaborated in my comment on the ticket[1] this issue cannot be fixed in any stable version due to the ABI break. Thus, this patch adds an optional $password parameter to ::getStream(), so that users can retrieve streams of encrypted files in the archive. This also works for files with individual passwords (i.e. not using the general password of the archive), as can be seen in the accompanying test case. [1] --- ext/zip/php_zip.c | 7 +++++-- ext/zip/php_zip.h | 3 ++- ext/zip/tests/bug80833.phpt | 29 +++++++++++++++++++++++++++++ ext/zip/zip_stream.c | 11 +++++++++-- 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 ext/zip/tests/bug80833.phpt diff --git a/ext/zip/php_zip.c b/ext/zip/php_zip.c index 21182068d1d7f..df940818f1e97 100644 --- a/ext/zip/php_zip.c +++ b/ext/zip/php_zip.c @@ -2780,10 +2780,12 @@ static ZIPARCHIVE_METHOD(getStream) zend_string *filename; php_stream *stream; ze_zip_object *obj; + char *password = NULL; + size_t password_len; ZIP_FROM_OBJECT(intern, self); - if (zend_parse_parameters(ZEND_NUM_ARGS(), "P", &filename) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS(), "P|s!", &filename, &password, &password_len) == FAILURE) { return; } @@ -2793,7 +2795,7 @@ static ZIPARCHIVE_METHOD(getStream) obj = Z_ZIP_P(self); - stream = php_stream_zip_open(obj->filename, ZSTR_VAL(filename), mode STREAMS_CC); + stream = php_stream_zip_open_ex(obj->filename, ZSTR_VAL(filename), mode, password STREAMS_CC); if (stream) { php_stream_to_zval(stream, return_value); } else { @@ -2918,6 +2920,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_ziparchive_getstream, 0, 0, 1) ZEND_ARG_INFO(0, entryname) + ZEND_ARG_INFO(0, password) ZEND_END_ARG_INFO() #ifdef ZIP_OPSYS_DEFAULT diff --git a/ext/zip/php_zip.h b/ext/zip/php_zip.h index 7caf65f0068ec..2a72ee5db40aa 100644 --- a/ext/zip/php_zip.h +++ b/ext/zip/php_zip.h @@ -71,7 +71,8 @@ static inline ze_zip_object *php_zip_fetch_object(zend_object *obj) { #define Z_ZIP_P(zv) php_zip_fetch_object(Z_OBJ_P((zv))) php_stream *php_stream_zip_opener(php_stream_wrapper *wrapper, const char *path, const char *mode, int options, zend_string **opened_path, php_stream_context *context STREAMS_DC); -php_stream *php_stream_zip_open(const char *filename, const char *path, const char *mode STREAMS_DC); +php_stream *php_stream_zip_open_ex(const char *filename, const char *path, const char *mode, const char *password STREAMS_DC); +#define php_stream_zip_open(filename, path, mode) php_stream_zip_open_ex(filename, path, mode STREAMS_CC); extern const php_stream_wrapper php_stream_zip_wrapper; diff --git a/ext/zip/tests/bug80833.phpt b/ext/zip/tests/bug80833.phpt new file mode 100644 index 0000000000000..48daf4ab9e12a --- /dev/null +++ b/ext/zip/tests/bug80833.phpt @@ -0,0 +1,29 @@ +--TEST-- +Bug #80833 (ZipArchive::getStream doesn't use setPassword) +--SKIPIF-- + +--FILE-- +open(__DIR__ . "/80833.zip", ZipArchive::CREATE); +$create_zip->setPassword("default_password"); +$create_zip->addFromString("test.txt", "This is a test string."); +$create_zip->setEncryptionName("test.txt", ZipArchive::EM_AES_256, "file_password"); +$create_zip->close(); + +$extract_zip = new ZipArchive(); +$extract_zip->open(__DIR__ . "/80833.zip", ZipArchive::RDONLY); +$extract_zip->setPassword("default_password"); +$file_stream = $extract_zip->getStream("test.txt", "file_password"); +var_dump(stream_get_contents($file_stream)); +fclose($file_stream); +$extract_zip->close(); +?> +--CLEAN-- + +--EXPECT-- +string(22) "This is a test string." diff --git a/ext/zip/zip_stream.c b/ext/zip/zip_stream.c index bce62f56148ad..7dfefbd93fd44 100644 --- a/ext/zip/zip_stream.c +++ b/ext/zip/zip_stream.c @@ -210,7 +210,7 @@ const php_stream_ops php_stream_zipio_ops = { }; /* {{{ php_stream_zip_open */ -php_stream *php_stream_zip_open(const char *filename, const char *path, const char *mode STREAMS_DC) +php_stream *php_stream_zip_open_ex(const char *filename, const char *path, const char *mode, const char *password STREAMS_DC) { struct zip_file *zf = NULL; int err = 0; @@ -234,6 +234,14 @@ php_stream *php_stream_zip_open(const char *filename, const char *path, const ch return NULL; } + if (password != NULL) { + if (zip_set_default_password(stream_za, password) != 0) { + php_error_docref(NULL, E_WARNING, "password could not be set"); + zip_close(stream_za); + return NULL; + } + } + zf = zip_fopen(stream_za, path, 0); if (zf) { self = emalloc(sizeof(*self)); @@ -254,7 +262,6 @@ php_stream *php_stream_zip_open(const char *filename, const char *path, const ch } else { return stream; } - } /* }}} */