diff options
| -rw-r--r-- | Makefile | 5 | ||||
| -rw-r--r-- | TODO | 3 | ||||
| -rw-r--r-- | auth.cpp | 54 | ||||
| -rw-r--r-- | auth.h | 13 | ||||
| -rw-r--r-- | config.cpp | 3 | ||||
| -rw-r--r-- | debian/changelog | 1 | ||||
| -rw-r--r-- | response.cpp | 5 | ||||
| -rw-r--r-- | webserver.conf | 4 | ||||
| -rw-r--r-- | webserver.cpp | 30 | 
9 files changed, 100 insertions, 18 deletions
@@ -37,8 +37,10 @@ CXXTESTFLAGS=-Igoogletest/include -Igooglemock/include/ -Igoogletest -Igooglemoc  LIBS=\  -lboost_context \ --lboost_system \  -lboost_filesystem \ +-lboost_timer \ +-lboost_system \ +-lcrypt \  -lpthread \  -lssl -lcrypto \  -ldl @@ -63,6 +65,7 @@ LIBS+= \  endif  PROGSRC=\ +    auth.cpp \      base64.cpp \      config.cpp \      file.cpp \ @@ -1,7 +1,6 @@ -crypt pws  licence bsd -Speed up config.GetPath +Speed up config.GetPath  weblog: blättern  weblog: link consistency check (cron?)  weblog: style: zitate diff --git a/auth.cpp b/auth.cpp new file mode 100644 index 0000000..c9c9765 --- /dev/null +++ b/auth.cpp @@ -0,0 +1,54 @@ +#include "auth.h" + +#include <crypt.h> +#include <string.h> + +#include <stdexcept> +#include <iostream> + +// crypt specified password +std::string Auth::generate(const std::string& pw) +{ + struct crypt_data data; + memset((void *)&data, '\0', sizeof(data)); +  + if (crypt_gensalt_rn("$6$", 2000, nullptr, 0, data.setting, sizeof(data.setting)) == nullptr) +  throw std::runtime_error("Error on crypt_gensalt_r()"); + + strncpy(data.input, pw.data(), sizeof(data.input)); + + if (crypt_r(data.input, data.setting, &data) == nullptr) +  throw std::runtime_error("Error on crypt_r()"); + + return data.output; +} + +// validate specified password against crypted hash +bool Auth::validate(const std::string& crypted, const std::string& pw) +{ + struct crypt_data data; + memset((void *)&data, '\0', sizeof(data)); + + size_t pos = crypted.find_last_of('$'); + if (pos == crypted.npos) { +  std::cerr << "Warning: Bad password hash configured (format)" << std::endl; +  return false; + } + + if (sizeof(data.setting) <= pos) { +  std::cerr << "Warning: Bad password hash configured (salt size)" << std::endl; +  return false; + } + + memcpy(&data.setting, crypted.data(), pos); + + strncpy(data.input, pw.data(), sizeof(data.input)); + + if (crypt_r(data.input, data.setting, &data) == nullptr) { +  std::cerr << "Warning: Error on crypt_r()" << std::endl; +  return false; + } + + return crypted == data.output; +} + @@ -0,0 +1,13 @@ +#pragma once + +#include <string> + +// Password encryption via crypt(3) + +namespace Auth { + + std::string generate(const std::string& pw); + bool validate(const std::string& crypted, const std::string& pw); + +} + @@ -3,6 +3,7 @@  #include <boost/algorithm/string/predicate.hpp>  #include <boost/property_tree/ptree.hpp>  #include <boost/property_tree/xml_parser.hpp> +#include <boost/timer/timer.hpp>  #include <algorithm>  #include <exception> @@ -208,6 +209,8 @@ void Config::dump() const  // throws std::out_of_range if not found  const Path& Config::GetPath(const Socket& socket, const std::string& requested_host, const std::string& requested_path) const  { + //boost::timer::auto_cpu_timer t; +   // TODO: speed this up   std::string host{requested_host};   const Path* result{nullptr}; diff --git a/debian/changelog b/debian/changelog index eacca64..4d6642b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -4,6 +4,7 @@ webserver (1.3) unstable; urgency=medium    * Added statistics    * Removed upload limit (now 1GB)    * Support Ubuntu 1910 +  * Crypt(3) HTTP AUTH passwords   -- Roland Reichwein <rr@antcom.de>  Sat, 25 Apr 2020 12:35:44 +0200 diff --git a/response.cpp b/response.cpp index 696b859..9eda5ff 100644 --- a/response.cpp +++ b/response.cpp @@ -1,5 +1,6 @@  #include "response.h" +#include "auth.h"  #include "base64.h"  #include "file.h" @@ -292,7 +293,9 @@ response_type generate_response(request_type& req, Server& server)     std::string password{authorization.substr(pos + 1)};     auto it {auth.find(login)}; -   if (it == auth.end() || it->second != password) +   // it.second contains crypted/hash +   // password is plain text to validate against the hash +   if (it == auth.end() || !Auth::validate(it->second, password))      return HttpStatusAndStats("401", "Bad Authorization", req_ctx, res);    } diff --git a/webserver.conf b/webserver.conf index 5adc9ba..55a1870 100644 --- a/webserver.conf +++ b/webserver.conf @@ -29,7 +29,7 @@      <target>/home/ernie/testbox</target>      <WEBBOX_NAME>Testbox1</WEBBOX_NAME>      <WEBBOX_READONLY>0</WEBBOX_READONLY> -    <auth login="abc" password="def"/> +    <auth login="abc" password="$6$rounds=2000$HGwnefVabvSkS4Kg$5xYJDIVL7rkMGVVBOHf8/pHTJFKeEDytzS9em6En9qydgUFqbtbOTnTp/HyYk9At4eDL64jGKmbSKNFsXlquI1"/>     </path>     <path requested="/blog">      <plugin>weblog</plugin> @@ -45,7 +45,7 @@     <path requested="/cgi-bin">      <plugin>cgi</plugin>      <target>/home/ernie/code/webserver/cgi-bin</target> -    <auth login="abc" password="def"/> +    <auth login="abc" password="$6$rounds=2000$HGwnefVabvSkS4Kg$5xYJDIVL7rkMGVVBOHf8/pHTJFKeEDytzS9em6En9qydgUFqbtbOTnTp/HyYk9At4eDL64jGKmbSKNFsXlquI1"/>     </path>     <certpath>/home/ernie/code/webserver/fullchain.pem</certpath>     <keypath>/home/ernie/code/webserver/privkey.pem</keypath> diff --git a/webserver.cpp b/webserver.cpp index c49751e..98fedc3 100644 --- a/webserver.cpp +++ b/webserver.cpp @@ -1,3 +1,4 @@ +#include "auth.h"  #include "config.h"  #include "server.h"  #include "plugin.h" @@ -21,25 +22,30 @@ void initlocale() {  int main(int argc, char* argv[])  { - //initlocale(); // TODO: breaks plugins - - std::string config_filename; + try { +  //initlocale(); // TODO: breaks plugins - if (!(argc == 1 || argc == 3)) { -  usage(); -  return 1; - } +  std::string config_filename; - if (argc == 3) { -  if (argv[1] != "-c"s) { +  if (!(argc == 1 || argc == 3)) {     usage();     return 1;    } -  config_filename = argv[2]; - } +  if (argc == 3) { + +   // normal run with configuration file specified +   if (argv[1] == "-c"s) { +    config_filename = argv[2]; +   } else if (argv[1] == "-p"s) { // generate crypted password +    std::cout << Auth::generate(argv[2]) << std::endl; +    return 0; +   } else { +    usage(); +    return 1; +   } +  } - try {    Config config{config_filename};    PluginLoader plugin_loader(config);  | 
