From: Remi Gacogne Date: Fri, 9 Apr 2021 13:15:09 +0000 (+0200) Subject: rec_control, pdnsutil: Read the credentials from the terminal/stdin X-Git-Tag: dnsdist-1.7.0-alpha1~12^2~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=061bc5f0c64db727ecf00fda5472bea970b7394a;p=thirdparty%2Fpdns.git rec_control, pdnsutil: Read the credentials from the terminal/stdin --- diff --git a/docs/manpages/pdnsutil.1.rst b/docs/manpages/pdnsutil.1.rst index 2e141cd8d1..12285832d0 100644 --- a/docs/manpages/pdnsutil.1.rst +++ b/docs/manpages/pdnsutil.1.rst @@ -189,10 +189,9 @@ edit-zone *ZONE* **EDITOR** is empty, *pdnsutil* falls back to using *editor*. get-meta *ZONE* [*ATTRIBUTE*]... Get zone metadata. If no *ATTRIBUTE* given, lists all known. -hash-password *PASSWORD* - This convenience command returns a hashed and salted version of the - password passed in parameter, for use as a webserver password or - api key. +hash-password + This convenience command asks for a password and returns a hashed + and salted version, for use as a webserver password or api key. hash-zone-record *ZONE* *RNAME* This convenience command hashes the name *RNAME* according to the NSEC3 settings of *ZONE*. Refuses to hash for zones with no NSEC3 diff --git a/docs/settings.rst b/docs/settings.rst index b8a7c0beda..423a588afc 100644 --- a/docs/settings.rst +++ b/docs/settings.rst @@ -137,7 +137,7 @@ Enable/disable the :doc:`http-api/index`. .. versionchanged:: 4.6.0 This setting now accepts a hashed and salted version. -Static pre-shared authentication key for access to the REST API. Since 4.6.0 the key can be hashed and salted using ``rec_control hash-password APIKEY`` instead of being stored in the configuration in plaintext. +Static pre-shared authentication key for access to the REST API. Since 4.6.0 the key can be hashed and salted using ``pdnsutil hash-password`` instead of being stored in the configuration in plaintext. .. _setting-autosecondary: @@ -1844,7 +1844,7 @@ Maximum request/response body size in megabytes. - String -Password required to access the webserver. Since 4.6.0 the password can be hashed and salted using ``pdnsutil hash-password PASS`` instead of being in plaintext. +Password required to access the webserver. Since 4.6.0 the password can be hashed and salted using ``pdnsutil hash-password`` instead of being in plaintext. .. _setting-webserver-port: diff --git a/pdns/credentials.cc b/pdns/credentials.cc index 139e6337ee..980e5d3dd0 100644 --- a/pdns/credentials.cc +++ b/pdns/credentials.cc @@ -27,6 +27,10 @@ #include #endif +#include +#include +#include + #include "credentials.hh" #include "misc.hh" @@ -156,3 +160,89 @@ bool CredentialsHolder::isHashingAvailable() return false; #endif } + +#include +#include + +std::string CredentialsHolder::readFromTerminal() +{ + struct termios term; + struct termios oterm; + memset(&term, 0, sizeof(term)); + term.c_lflag |= ECHO; + memset(&oterm, 0, sizeof(oterm)); + oterm.c_lflag |= ECHO; + bool restoreTermSettings = false; + int termAction = TCSAFLUSH; +#ifdef TCSASOFT + termAction |= TCSASOFT +#endif + + FDWrapper input(open("/dev/tty", O_RDONLY)); + if (int(input) != -1) { + if (tcgetattr(input, &oterm) == 0) { + memcpy(&term, &oterm, sizeof(term)); + term.c_lflag &= ~(ECHO | ECHONL); + tcsetattr(input, termAction, &term); + restoreTermSettings = true; + } + } + else { + input = FDWrapper(dup(STDIN_FILENO)); + } + FDWrapper output(open("/dev/tty", O_WRONLY)); + if (int(output) == -1) { + output = FDWrapper(dup(STDERR_FILENO)); + } + + struct std::map signals; + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = [](int s) { }; + sigaction(SIGALRM, &sa, &signals[SIGALRM]); + sigaction(SIGHUP, &sa, &signals[SIGHUP]); + sigaction(SIGINT, &sa, &signals[SIGINT]); + sigaction(SIGPIPE, &sa, &signals[SIGPIPE]); + sigaction(SIGQUIT, &sa, &signals[SIGQUIT]); + sigaction(SIGTERM, &sa, &signals[SIGTERM]); + sigaction(SIGTSTP, &sa, &signals[SIGTSTP]); + sigaction(SIGTTIN, &sa, &signals[SIGTTIN]); + sigaction(SIGTTOU, &sa, &signals[SIGTTOU]); + + std::string buffer; + /* let's allocate a huge buffer now to prevent reallocation, + which would leave parts of the buffer around */ + buffer.reserve(512); + + for (;;) { + char ch = '\0'; + auto got = read(input, &ch, 1); + if (got == 1 && ch != '\n' && ch != '\r') { + buffer.push_back(ch); + } + else { + break; + } + } + + if (!(term.c_lflag & ECHO)) { + if (write(output, "\n", 1) != 1) { + /* the compiler _really_ wants the result of write() to be checked.. */ + } + } + + if (restoreTermSettings) { + tcsetattr(input, termAction, &oterm); + } + + for (const auto& sig : signals) { + sigaction(sig.first, &sig.second, nullptr); + } + +#ifdef HAVE_LIBSODIUM + sodium_mlock(buffer.data(), buffer.size()); +#endif + + return buffer; +} diff --git a/pdns/credentials.hh b/pdns/credentials.hh index 9d42669d6b..2ed4ef938a 100644 --- a/pdns/credentials.hh +++ b/pdns/credentials.hh @@ -21,6 +21,7 @@ */ #pragma once +#include #include std::string hashPassword(const std::string& password); @@ -51,6 +52,7 @@ public: } static bool isHashingAvailable(); + static std::string readFromTerminal(); private: std::string d_credentials; diff --git a/pdns/pdnsutil.cc b/pdns/pdnsutil.cc index 9ac96d8cae..e55782e0ea 100644 --- a/pdns/pdnsutil.cc +++ b/pdns/pdnsutil.cc @@ -2332,7 +2332,7 @@ try cout<<"generate-zone-key {zsk|ksk} [ALGORITHM] [BITS]"< (i + 1)) { - ++i; - auto password = commands.at(i); - cout << hashPassword(password) << endl; - return 0; - } - else { - throw PDNSException("Command needs a password argument"); - } + auto password = CredentialsHolder::readFromTerminal(); + cout << hashPassword(password) << endl; + return 0; } ++i; } diff --git a/pdns/recursordist/docs/manpages/rec_control.1.rst b/pdns/recursordist/docs/manpages/rec_control.1.rst index f690b6650c..b0fb9d9d7e 100644 --- a/pdns/recursordist/docs/manpages/rec_control.1.rst +++ b/pdns/recursordist/docs/manpages/rec_control.1.rst @@ -153,9 +153,9 @@ get-qtypelist Retrieves QType statistics. Queries from cache aren't being counted yet. hash-password - Hash and salt the given password, to use as a webserver password or - API key. This command does not contact the recursor but does the - hashing inside rec_control. + Asks for a password then returns the hashed and salted version, + to use as a webserver password or API key. This command does + not contact the recursor but does the hashing inside rec_control. help Shows a list of supported commands understood by the running diff --git a/pdns/recursordist/docs/settings.rst b/pdns/recursordist/docs/settings.rst index 6e16c30d12..750a98ea7c 100644 --- a/pdns/recursordist/docs/settings.rst +++ b/pdns/recursordist/docs/settings.rst @@ -101,7 +101,7 @@ Directory where the REST API stores its configuration and zones. - String - Default: unset -Static pre-shared authentication key for access to the REST API. Since 4.6.0 the key can be hashed and salted using ``rec_control hash-password APIKEY`` instead of being stored in the configuration in plaintext. +Static pre-shared authentication key for access to the REST API. Since 4.6.0 the key can be hashed and salted using ``rec_control hash-password`` instead of being stored in the configuration in plaintext. .. _setting-api-readonly: @@ -2172,7 +2172,7 @@ The value between the hooks is a UUID that is generated for each request. This c - String - Default: unset -Password required to access the webserver. Since 4.6.0 the password can be hashed and salted using ``rec_control hash-password PASS`` instead of being in plaintext. +Password required to access the webserver. Since 4.6.0 the password can be hashed and salted using ``rec_control hash-password`` instead of being in plaintext. .. _setting-webserver-port: