From 2c37f6565d59b8d3404ae8321182cc3e33f0f67c Mon Sep 17 00:00:00 2001 From: Earnestly Date: Sat, 7 Feb 2026 22:15:56 +0000 Subject: [PATCH] Support for reading passwords from a specified fd This initial work adds the -pfd[N] flag to the 7z command so that an alternate file descriptor (fd) may be specified for reading the password instead of standard input (stdin). By adding this flag it becomes possible for 7z to accept data from stdin for use with the -si flag while also being being able to decrypt a password protected achieve without revealing the password on the command line. For example, generating a secret key and storing it in an encrypted archive without the need to expose any of the data to a filesystem: age-keygen | 7z a -pfd9 9< <(pass show archive) -siid.age archive.7z As a side effect the password is not echoed to the terminal, however this PR should not conflict with the work in #33. Note that the -p flag is necessary if the archive does not exist but should not be used if it does. --- CPP/7zip/UI/Common/ArchiveCommandLine.cpp | 27 +++++++++++++++++++ CPP/7zip/UI/Common/ArchiveCommandLine.h | 1 + CPP/7zip/UI/Console/List.cpp | 3 ++- CPP/7zip/UI/Console/List.h | 2 +- CPP/7zip/UI/Console/Main.cpp | 5 ++++ CPP/7zip/UI/Console/OpenCallbackConsole.cpp | 9 +++++++ CPP/7zip/UI/Console/OpenCallbackConsole.h | 1 + CPP/7zip/UI/Console/UpdateCallbackConsole.cpp | 19 +++++++++++++ CPP/7zip/UI/Console/UpdateCallbackConsole.h | 1 + CPP/7zip/UI/Console/UserInputUtils.h | 1 + 10 files changed, 67 insertions(+), 2 deletions(-) diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp index 7fe18fb..ae26ed1 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp @@ -120,6 +120,15 @@ static bool StringToUInt32(const wchar_t *s, UInt32 &v) return *end == 0; } +static bool StringToInt32(const wchar_t *s, Int32 &v) +{ + if (*s == 0) + return false; + const wchar_t *end; + v = ConvertStringToInt32(s, &end); + return *end == 0; +} + namespace NKey { enum Enum @@ -209,6 +218,7 @@ enum Enum #ifndef Z7_NO_CRYPTO , kPassword + , kPasswordFd #endif }; @@ -360,6 +370,7 @@ static const CSwitchForm kSwitchForms[] = #ifndef Z7_NO_CRYPTO , { "p", SWFRM_STRING } + , { "pfd", SWFRM_STRING } #endif }; @@ -1460,6 +1471,22 @@ void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options) options.PasswordEnabled = parser[NKey::kPassword].ThereIs; if (options.PasswordEnabled) options.Password = parser[NKey::kPassword].PostStrings[0]; + + options.PasswordFd = 0; + + if (parser[NKey::kPasswordFd].ThereIs) + { + const UString &s = parser[NKey::kPasswordFd].PostStrings[0]; + if (s.IsEmpty()) + throw CArcCmdLineException("No file descriptor given to -pfd", s); + else + { + Int32 v; + if (!StringToInt32(s, v)) + throw CArcCmdLineException("A file descriptor is required for -pfd", s); + options.PasswordFd = (int)v; + } + } #endif options.ShowDialog = parser[NKey::kShowDialog].ThereIs; diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.h b/CPP/7zip/UI/Common/ArchiveCommandLine.h index d17ec5a..bf7aa92 100644 --- a/CPP/7zip/UI/Common/ArchiveCommandLine.h +++ b/CPP/7zip/UI/Common/ArchiveCommandLine.h @@ -89,6 +89,7 @@ struct CArcCmdLineOptions #ifndef Z7_NO_CRYPTO bool PasswordEnabled; UString Password; + int PasswordFd; #endif UStringVector HashMethods; diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp index 874caef..8b346d1 100644 --- a/CPP/7zip/UI/Console/List.cpp +++ b/CPP/7zip/UI/Console/List.cpp @@ -1081,7 +1081,7 @@ HRESULT ListArchives( const NWildcard::CCensorNode &wildcardCensor, bool enableHeaders, bool techMode, #ifndef Z7_NO_CRYPTO - bool &passwordEnabled, UString &password, + bool &passwordEnabled, UString &password, int &passwordFd, #endif #ifndef Z7_SFX const CObjectVector *props, @@ -1161,6 +1161,7 @@ HRESULT ListArchives( openCallback.PasswordIsDefined = passwordEnabled; openCallback.Password = password; + openCallback.PasswordFd = passwordFd; #endif diff --git a/CPP/7zip/UI/Console/List.h b/CPP/7zip/UI/Console/List.h index d87f512..ab43731 100644 --- a/CPP/7zip/UI/Console/List.h +++ b/CPP/7zip/UI/Console/List.h @@ -31,7 +31,7 @@ HRESULT ListArchives( const NWildcard::CCensorNode &wildcardCensor, bool enableHeaders, bool techMode, #ifndef Z7_NO_CRYPTO - bool &passwordEnabled, UString &password, + bool &passwordEnabled, UString &password, int &passwordFd, #endif #ifndef Z7_SFX const CObjectVector *props, diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp index 90e00a4..86f7e42 100644 --- a/CPP/7zip/UI/Console/Main.cpp +++ b/CPP/7zip/UI/Console/Main.cpp @@ -163,6 +163,7 @@ static const char * const kHelpString = " -o{Directory} : set Output directory\n" #ifndef Z7_NO_CRYPTO " -p{Password} : set Password\n" + " -pfd{N} : read Password from fd\n" #endif " -r[-|0] : Recurse subdirectories for name search\n" " -sa{a|e|s} : set Archive name mode\n" @@ -1333,6 +1334,7 @@ int Main2( #ifndef Z7_NO_CRYPTO ecs->PasswordIsDefined = options.PasswordEnabled; ecs->Password = options.Password; + ecs->PasswordFd = options.PasswordFd; #endif ecs->Init(g_StdStream, g_ErrStream, percentsStream, options.DisablePercents); @@ -1517,6 +1519,7 @@ int Main2( #ifndef Z7_NO_CRYPTO options.PasswordEnabled, options.Password, + options.PasswordFd, #endif &options.Properties, numErrors, numWarnings); @@ -1551,6 +1554,7 @@ int Main2( (options.PasswordEnabled && !options.Password.IsEmpty()); openCallback.PasswordIsDefined = passwordIsDefined; openCallback.Password = options.Password; + openCallback.PasswordFd = options.PasswordFd; #endif CUpdateCallbackConsole callback; @@ -1564,6 +1568,7 @@ int Main2( callback.PasswordIsDefined = passwordIsDefined; callback.AskPassword = (options.PasswordEnabled && options.Password.IsEmpty()); callback.Password = options.Password; + callback.PasswordFd = options.PasswordFd; #endif callback.StdOutMode = uo.StdOutMode; diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp index 1e7adf5..58b53b3 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp @@ -87,6 +87,15 @@ HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password) if (!PasswordIsDefined) { ClosePercents(); + if (PasswordFd) { + FILE *_file = fdopen(PasswordFd, "r"); + + if (!_file) + return S_FALSE; + + g_StdIn = CStdInStream(_file); + } + RINOK(GetPassword_HRESULT(_so, Password)) PasswordIsDefined = true; } diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.h b/CPP/7zip/UI/Console/OpenCallbackConsole.h index 5e7c19c..9f8bdf6 100644 --- a/CPP/7zip/UI/Console/OpenCallbackConsole.h +++ b/CPP/7zip/UI/Console/OpenCallbackConsole.h @@ -67,6 +67,7 @@ public: bool PasswordIsDefined; // bool PasswordWasAsked; UString Password; + int PasswordFd; #endif }; diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp index 5185d5c..16006f5 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp @@ -828,6 +828,16 @@ HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, if (!PasswordIsDefined) { + if (PasswordFd) { + FILE *_file = fdopen(PasswordFd, "r"); + + if (!_file) + return S_FALSE; + + g_StdIn = CStdInStream(_file); + } + + if (AskPassword) { RINOK(GetPassword_HRESULT(_so, Password)) @@ -857,6 +867,15 @@ HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password) if (!PasswordIsDefined) { { + if (PasswordFd) { + FILE *_file = fdopen(PasswordFd, "r"); + + if (!_file) + return S_FALSE; + + g_StdIn = CStdInStream(_file); + } + RINOK(GetPassword_HRESULT(_so, Password)) PasswordIsDefined = true; } diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/CPP/7zip/UI/Console/UpdateCallbackConsole.h index a386371..2a4d9a5 100644 --- a/CPP/7zip/UI/Console/UpdateCallbackConsole.h +++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.h @@ -122,6 +122,7 @@ public: bool PasswordIsDefined; bool AskPassword; UString Password; + int PasswordFd; #endif CUpdateCallbackConsole(): diff --git a/CPP/7zip/UI/Console/UserInputUtils.h b/CPP/7zip/UI/Console/UserInputUtils.h index 695a3e6..d8ffd1c 100644 --- a/CPP/7zip/UI/Console/UserInputUtils.h +++ b/CPP/7zip/UI/Console/UserInputUtils.h @@ -3,6 +3,7 @@ #ifndef ZIP7_INC_USER_INPUT_UTILS_H #define ZIP7_INC_USER_INPUT_UTILS_H +#include "../../../Common/StdInStream.h" #include "../../../Common/StdOutStream.h" namespace NUserAnswerMode {