blob: d558fbc23f4af008bb9dc28bf8e3e0330d104bbe [file] [log] [blame]
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