diff --git a/src/cpp-utils/io/DontEchoStdinToStdoutRAII.cpp b/src/cpp-utils/io/DontEchoStdinToStdoutRAII.cpp new file mode 100644 index 00000000..babafcd6 --- /dev/null +++ b/src/cpp-utils/io/DontEchoStdinToStdoutRAII.cpp @@ -0,0 +1 @@ +#include "DontEchoStdinToStdoutRAII.h" diff --git a/src/cpp-utils/io/DontEchoStdinToStdoutRAII.h b/src/cpp-utils/io/DontEchoStdinToStdoutRAII.h new file mode 100644 index 00000000..1bbaa66d --- /dev/null +++ b/src/cpp-utils/io/DontEchoStdinToStdoutRAII.h @@ -0,0 +1,39 @@ +#pragma once +#ifndef MESSMER_CPPUTILS_IO_DONTECHOSTDINTOSTDOUTRAII_H +#define MESSMER_CPPUTILS_IO_DONTECHOSTDINTOSTDOUTRAII_H + +#include +#include +#include +#include +#include "../macros.h" + +namespace cpputils { + +/** + * If you create an instance of this class in your scope, then any user input from stdin + * won't be echoed back to stdout until the instance leaves the scope. + * This can be very handy for password inputs where you don't want the password to be visible on screen. + */ +class DontEchoStdinToStdoutRAII final { +public: + DontEchoStdinToStdoutRAII() { + tcgetattr(STDIN_FILENO, &_old_state); + termios new_state = _old_state; + new_state.c_lflag &= ~ECHO; + tcsetattr(STDIN_FILENO, TCSANOW, &new_state); + } + + ~DontEchoStdinToStdoutRAII() { + tcsetattr(STDIN_FILENO, TCSANOW, &_old_state); + } + +private: + termios _old_state; + + DISALLOW_COPY_AND_ASSIGN(DontEchoStdinToStdoutRAII); +}; + +} + +#endif diff --git a/src/cryfs/cli/Cli.cpp b/src/cryfs/cli/Cli.cpp index 77a29e7b..2b2aa77d 100644 --- a/src/cryfs/cli/Cli.cpp +++ b/src/cryfs/cli/Cli.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "../filesystem/CryDevice.h" #include "../config/CryConfigLoader.h" #include "program_options/Parser.h" @@ -20,14 +21,6 @@ #include "VersionChecker.h" -#include - -// needed for libc to define PASS_MAX -#include -#ifdef PASS_MAX -#error The used libc implementation has a maximal password size for getpass(). We cannot use it to ask for passwords. -#endif - //TODO Fails with gpg-homedir in filesystem: gpg --homedir gpg-homedir --gen-key //TODO Many functions accessing the ProgramOptions object. Factor out into class that stores it as a member. //TODO Factor out class handling askPassword @@ -49,6 +42,8 @@ using cpputils::unique_ref; using cpputils::SCryptSettings; using cpputils::Console; using cpputils::HttpClient; +using cpputils::DontEchoStdinToStdoutRAII; +using std::cin; using std::cout; using std::string; using std::endl; @@ -131,9 +126,9 @@ namespace cryfs { } string Cli::_askPasswordForExistingFilesystem() { - string password = getpass("Password: "); + string password = _askPasswordFromStdin("Password: "); while (!_checkPassword(password)) { - password = getpass("Password: "); + password = _askPasswordFromStdin("Password: "); } return password; }; @@ -142,7 +137,7 @@ namespace cryfs { string password; bool again = false; do { - password = getpass("Password: "); + password = _askPasswordFromStdin("Password: "); if (!_checkPassword(password)) { again = true; continue; @@ -157,7 +152,7 @@ namespace cryfs { } bool Cli::_confirmPassword(const string &password) { - string confirmPassword = getpass("Confirm Password: "); + string confirmPassword = _askPasswordFromStdin("Confirm Password: "); if (password != confirmPassword) { std::cout << "Passwords don't match" << std::endl; return false; @@ -165,6 +160,17 @@ namespace cryfs { return true; } + string Cli::_askPasswordFromStdin(const string &prompt) { + DontEchoStdinToStdoutRAII _stdin_input_is_hidden_as_long_as_this_is_in_scope; + + std::cout << prompt << std::flush; + string result; + std::getline(cin, result); + std::cout << std::endl; + + return result; + } + bf::path Cli::_determineConfigFile(const ProgramOptions &options) { auto configFile = options.configFile(); if (configFile == none) { diff --git a/src/cryfs/cli/Cli.h b/src/cryfs/cli/Cli.h index b5ffa216..845dd89b 100644 --- a/src/cryfs/cli/Cli.h +++ b/src/cryfs/cli/Cli.h @@ -24,6 +24,7 @@ namespace cryfs { std::string _getPassword(const program_options::ProgramOptions &options, std::function askPassword); static std::string _askPasswordForExistingFilesystem(); static std::string _askPasswordForNewFilesystem(); + static std::string _askPasswordFromStdin(const std::string &prompt); static bool _confirmPassword(const std::string &password); static bool _checkPassword(const std::string &password); void _showVersion();