diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cli/cli.cpp | 39 | ||||
-rw-r--r-- | src/lib/utils/os_utils.cpp | 56 | ||||
-rw-r--r-- | src/lib/utils/os_utils.h | 27 |
3 files changed, 96 insertions, 26 deletions
diff --git a/src/cli/cli.cpp b/src/cli/cli.cpp index f8ec55e7b..988fa623a 100644 --- a/src/cli/cli.cpp +++ b/src/cli/cli.cpp @@ -8,13 +8,10 @@ #include "argparse.h" #include <botan/rng.h> #include <botan/parsing.h> +#include <botan/internal/os_utils.h> #include <iostream> #include <fstream> -#if defined(BOTAN_TARGET_OS_HAS_POSIX1) - #include <termios.h> -#endif - namespace Botan_CLI { Command::Command(const std::string& cmd_spec) : m_spec(cmd_spec) @@ -210,34 +207,28 @@ Botan::RandomNumberGenerator& Command::rng() return *m_rng.get(); } -std::string Command::get_passphrase(const std::string& prompt) - { - error_output() << prompt << ": " << std::flush; - std::string pass; +namespace { -#if defined(BOTAN_TARGET_OS_HAS_POSIX1) +bool echo_suppression_supported() + { + auto echo = Botan::OS::suppress_echo_on_terminal(); + return (echo != nullptr); + } - struct termios old_flags; - int stdin_fd = fileno(stdin); - ::tcgetattr(stdin_fd, &old_flags); - struct termios noecho_flags = old_flags; - noecho_flags.c_lflag &= ~ECHO; - noecho_flags.c_lflag |= ECHONL; +} - if(::tcsetattr(stdin_fd, TCSANOW, &noecho_flags) != 0) - throw CLI_Error("Clearing terminal echo bit failed"); +std::string Command::get_passphrase(const std::string& prompt) + { + if(echo_suppression_supported() == false) + error_output() << "Warning: terminal echo suppression not enabled for this platform\n"; - std::getline(std::cin, pass); + error_output() << prompt << ": " << std::flush; + std::string pass; - if(::tcsetattr(stdin_fd, TCSANOW, &old_flags) != 0) - throw CLI_Error("Restoring terminal echo bit failed"); -#else + auto echo_suppress = Botan::OS::suppress_echo_on_terminal(); - // TODO equivalent for Windows ... std::getline(std::cin, pass); -#endif - return pass; } diff --git a/src/lib/utils/os_utils.cpp b/src/lib/utils/os_utils.cpp index ab9c73b0c..4c3aab476 100644 --- a/src/lib/utils/os_utils.cpp +++ b/src/lib/utils/os_utils.cpp @@ -1,6 +1,6 @@ /* * OS and machine specific utility functions -* (C) 2015,2016,2017 Jack Lloyd +* (C) 2015,2016,2017,2018 Jack Lloyd * (C) 2016 Daniel Neus * * Botan is released under the Simplified BSD License (see license.txt) @@ -26,6 +26,7 @@ #include <setjmp.h> #include <unistd.h> #include <errno.h> + #include <termios.h> #endif #if defined(BOTAN_TARGET_OS_IS_EMSCRIPTEN) @@ -470,4 +471,57 @@ int OS::run_cpu_instruction_probe(std::function<int ()> probe_fn) return probe_result; } +std::unique_ptr<OS::Echo_Suppression> OS::suppress_echo_on_terminal() + { +#if defined(BOTAN_TARGET_OS_HAS_POSIX1) + class POSIX_Echo_Suppression : public Echo_Suppression + { + public: + POSIX_Echo_Suppression() + { + m_stdin_fd = fileno(stdin); + if(::tcgetattr(m_stdin_fd, &m_old_termios) != 0) + throw Botan::System_Error("Getting terminal status failed", errno); + + struct termios noecho_flags = m_old_termios; + noecho_flags.c_lflag &= ~ECHO; + noecho_flags.c_lflag |= ECHONL; + + if(::tcsetattr(m_stdin_fd, TCSANOW, &noecho_flags) != 0) + throw Botan::System_Error("Clearing terminal echo bit failed", errno); + } + + void reenable_echo() override + { + if(m_stdin_fd > 0) + { + if(::tcsetattr(m_stdin_fd, TCSANOW, &m_old_termios) != 0) + throw Botan::System_Error("Restoring terminal echo bit failed", errno); + m_stdin_fd = -1; + } + } + + ~POSIX_Echo_Suppression() + { + try + { + reenable_echo(); + } + catch(...) + { + } + } + + private: + int m_stdin_fd; + struct termios m_old_termios; + }; + + return std::unique_ptr<Echo_Suppression>(new POSIX_Echo_Suppression); +#endif + + // Not supported on this platform, return null + return std::unique_ptr<Echo_Suppression>(); + } + } diff --git a/src/lib/utils/os_utils.h b/src/lib/utils/os_utils.h index 778ace4e9..39e30fcb7 100644 --- a/src/lib/utils/os_utils.h +++ b/src/lib/utils/os_utils.h @@ -1,6 +1,6 @@ /* * OS specific utility functions -* (C) 2015,2016,2017 Jack Lloyd +* (C) 2015,2016,2017,2018 Jack Lloyd * * Botan is released under the Simplified BSD License (see license.txt) */ @@ -117,6 +117,31 @@ void free_locked_pages(void* ptr, size_t length); */ int BOTAN_TEST_API run_cpu_instruction_probe(std::function<int ()> probe_fn); +/** +* Represents a terminal state +*/ +class BOTAN_UNSTABLE_API Echo_Suppression + { + public: + /** + * Reenable echo on this terminal. Can be safely called + * multiple times. May throw if an error occurs. + */ + virtual void reenable_echo() = 0; + + /** + * Implicitly calls reenable_echo, but swallows/ignored all + * errors which would leave the terminal in an invalid state. + */ + virtual ~Echo_Suppression() = default; + }; + +/** +* Suppress echo on the terminal +* Returns null if this operation is not supported on the current system. +*/ +std::unique_ptr<Echo_Suppression> BOTAN_UNSTABLE_API suppress_echo_on_terminal(); + } } |