| From 919af38414bfa455b8da2d0a3b48245c97dbbcfc Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Fran=C3=A7ois=20Degros?= <fdegros@chromium.org> |
| Date: Sat, 11 Jul 2020 19:19:54 +1000 |
| Subject: [PATCH] Read password from stdin |
| |
| If no password or an empty password is provided via stdin and the ZIP |
| contains encrypted files, then the ZIP is not mounted. |
| |
| If a non-empty password is provided, it is used to decrypt encrypted |
| files. The password itself is checked for validity when the ZIP is |
| mounted. If the password does not allow to decrypt the first encrypted |
| file encountered in the ZIP, then the ZIP is not mounted. Multipassword |
| ZIPs containing files encrypted with different passwords are thus not |
| supported. |
| --- |
| lib/fuseZipData.cpp | 59 ++++++++++++++++++++++++++++++++++++++++++++- |
| 1 file changed, 58 insertions(+), 1 deletion(-) |
| |
| diff --git a/lib/fuseZipData.cpp b/lib/fuseZipData.cpp |
| index d9ff5cb..bdddb94 100644 |
| --- a/lib/fuseZipData.cpp |
| +++ b/lib/fuseZipData.cpp |
| @@ -21,6 +21,7 @@ |
| #include <cassert> |
| #include <cerrno> |
| #include <cstring> |
| +#include <iostream> |
| #include <stdexcept> |
| |
| #include "fuseZipData.h" |
| @@ -29,6 +30,28 @@ |
| |
| #define FZ_ATTR_HARDLINK (0x800) |
| |
| +// Reads a password from the standard input and sets it as default password on |
| +// the given archive. |
| +static void SetPassword(zip_t *const archive) { |
| + // Write prompt to standard output. |
| + std::cout << "Password?" << std::endl; |
| + |
| + // Read password from standard input. |
| + std::string password; |
| + if (!std::getline(std::cin, password) || password.empty()) |
| + return; |
| + |
| + // Remove newline at the end of password. |
| + if (password.back() == '\n') |
| + password.pop_back(); |
| + |
| + if (password.empty()) |
| + return; |
| + |
| + if (zip_set_default_password(archive, password.c_str()) < 0) |
| + throw ZipError("Cannot set default password", archive); |
| +} |
| + |
| FuseZipData::FuseZipData(const char *archiveName, struct zip *z, const char *cwd, |
| bool force_precise_time): |
| m_zip(z), m_archiveName(archiveName), m_cwd(cwd), m_force_precise_time(force_precise_time) { |
| @@ -73,22 +96,56 @@ void FuseZipData::build_tree(bool readonly) { |
| if (readonly) { |
| for (zip_int64_t i = 0; i < n; ++i) { |
| const char *name = zip_get_name(m_zip, static_cast<zip_uint64_t>(i), ZIP_FL_ENC_GUESS); |
| + if (!name) |
| + throw ZipError("Cannot get file name", m_zip); |
| + |
| if ((name[0] == '/') || (strncmp(name, "../", 3) == 0)) { |
| needPrefix = true; |
| + break; |
| } |
| } |
| } |
| + |
| + zip_stat_t sb; |
| + |
| // add zip entries for all items except hardlinks |
| filemap_t origNames; |
| + bool checked_password = false; |
| for (zip_int64_t i = 0; i < n; ++i) { |
| zip_uint64_t id = static_cast<zip_uint64_t>(i); |
| bool isHardlink; |
| - const char *name = zip_get_name(m_zip, id, ZIP_FL_ENC_GUESS); |
| + |
| + if (zip_stat_index(m_zip, id, ZIP_FL_ENC_GUESS, &sb) < 0) |
| + throw ZipError("Cannot read file entry", m_zip); |
| + |
| + if ((sb.valid & ZIP_STAT_NAME) == 0) |
| + continue; |
| + |
| + const char *const name = sb.name; |
| mode_t mode = getEntryAttributes(id, name, isHardlink); |
| |
| if (isHardlink) |
| continue; |
| |
| + // Try to open the first encrypted file and read a few bytes in order to |
| + // check the password. |
| + if (!checked_password && (sb.valid & ZIP_STAT_ENCRYPTION_METHOD) != 0 && |
| + sb.encryption_method != ZIP_EM_NONE) { |
| + SetPassword(m_zip); |
| + const ZipFile file(zip_fopen_index(m_zip, id, 0)); |
| + if (!file) |
| + throw ZipError("Cannot decrypt file", m_zip); |
| + |
| + const size_t bufLen = 16; |
| + char buf[bufLen]; |
| + |
| + if (zip_fread(file.get(), buf, bufLen) < 0) |
| + throw ZipError("Cannot decrypt file", file.get()); |
| + |
| + // Password is Ok. |
| + checked_password = true; |
| + } |
| + |
| attachNode(i, name, mode, readonly, needPrefix, origNames); |
| } |
| // add hardlinks |
| -- |
| 2.29.1.341.ge80a0c044ae-goog |
| |