From de26451445e962b9228abcbf401b398d60b28ea1 Mon Sep 17 00:00:00 2001 From: rublon-bwi <134260122+rublon-bwi@users.noreply.github.com> Date: Mon, 28 Jul 2025 14:51:35 +0200 Subject: [PATCH] Bwi/v2.3.1 (#18) * Fix handling of fail mode * Fix handling proxy configuration * Minor changes to logging * Fix compiler warnings --- CMakeLists.txt | 2 +- PAM/ssh/include/rublon/configuration.hpp | 26 ++++++++---- PAM/ssh/include/rublon/error_handler.hpp | 2 +- PAM/ssh/include/rublon/utils.hpp | 54 +++++++++--------------- PAM/ssh/include/rublon/websockets.hpp | 2 +- 5 files changed, 40 insertions(+), 46 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cda36dc..d0d1ab0 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ include(GNUInstallDirs) set(PROJECT_VERSION_MAJOR 2) set(PROJECT_VERSION_MINOR 3) -set(PROJECT_VERSION_PATCH 0) +set(PROJECT_VERSION_PATCH 1) set(RUBLON_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") set(CMAKE_CXX_STANDARD 17) diff --git a/PAM/ssh/include/rublon/configuration.hpp b/PAM/ssh/include/rublon/configuration.hpp index 0c304f3..4d52ec1 100644 --- a/PAM/ssh/include/rublon/configuration.hpp +++ b/PAM/ssh/include/rublon/configuration.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -69,6 +70,9 @@ class ConfigurationReader { auto posEqual = line.find('='); std::pmr::string key{line.substr(0, posEqual), &memoryResource}; std::pmr::string value{line.substr(posEqual + 1), &memoryResource}; + + details::trimInPlace(key); + details::trimInPlace(value); keyValues[std::move(key)] = std::move(value); } @@ -86,6 +90,7 @@ class ConfigurationReader { if(it == keyValues.end()) { return std::nullopt; } + return string{it->second.data(), it->second.size(), memoryResource}; }; @@ -120,7 +125,7 @@ class ConfigurationReader { std::pmr::string val{&memoryResource}; val = it->second; - std::transform(val.begin(), val.end(), val.begin(), [](unsigned char c) { return static_cast< char >(std::tolower(c)); }); + std::transform(val.begin(), val.end(), val.begin(), [](auto c) { return std::tolower(c); }); if(val == "1" || val == "true" || val == "yes" || val == "on") return true; @@ -134,6 +139,7 @@ class ConfigurationReader { if(it == keyValues.end()) return std::nullopt; auto val = it->second; + std::transform(val.begin(), val.end(), val.begin(), [](auto c) { return std::tolower(c); }); if(val == "bypass") return FailMode::bypass; if(val == "deny") @@ -198,6 +204,11 @@ class ConfigurationReader { return true; }; + auto toLowerCaseOpt = [](auto & str) { + if(str) + std::transform(str->cbegin(), str->cend(), str->begin(), [](auto c) { return std::tolower(c); }); + }; + /// NOTE: // getStringOpt can return a valid empty string, for example configuration entry like // option= @@ -281,15 +292,12 @@ class ConfigurationReader { } } - auto defaultProxyPort = [&]() -> int { - memory::MonotonicStackResource< 32 > memoryResource; + toLowerCaseOpt(config.proxyType); + toLowerCaseOpt(config.proxyHost); - if(config.proxyType) { - std::pmr::string val{*config.proxyType, &memoryResource}; - std::transform(val.begin(), val.end(), val.begin(), [](auto c) { return std::tolower(c); }); - if(val.find("socks") != std::pmr::string::npos) { - return 1080; - } + auto defaultProxyPort = [&]() -> int { + if(config.proxyType.value_or("").find("socks") != std::pmr::string::npos) { + return 1080; } return 8080; }; diff --git a/PAM/ssh/include/rublon/error_handler.hpp b/PAM/ssh/include/rublon/error_handler.hpp index 132e9d5..b621ea4 100644 --- a/PAM/ssh/include/rublon/error_handler.hpp +++ b/PAM/ssh/include/rublon/error_handler.hpp @@ -44,7 +44,7 @@ class ErrorHandler { } if(error.is< ConnectionError >()) { - if(config.failMode == FailMode::deny) { + if(config.failMode == FailMode::bypass) { pam.print("Incorrect response from the Rublon API, user bypassed"); return AuthenticationStatus::Action::Bypass; } else { diff --git a/PAM/ssh/include/rublon/utils.hpp b/PAM/ssh/include/rublon/utils.hpp index d846fe0..59bece9 100755 --- a/PAM/ssh/include/rublon/utils.hpp +++ b/PAM/ssh/include/rublon/utils.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -7,8 +8,9 @@ #include #include #include -#include +#include #include +#include #include #include @@ -84,12 +86,18 @@ namespace details { return logPath(); } - inline void doLog(LogLevel level, const char * line) noexcept { + inline void doLog(LogLevel level, std::string_view line) noexcept { auto fp = std::unique_ptr< FILE, int (*)(FILE *) >(fopen(initLog(), "a+"), fclose); if(fp) { + auto newl = line.back() == '\n' ? "" : "\n"; /// TODO add transaction ID - fprintf( - fp.get(), "%s %s[%s] %s\n", dateStr().c_str(), application == nullptr ? "" : application, LogLevelNames[( int ) level], line); + fprintf(fp.get(), + "%s %s[%s] %s%s", + dateStr().c_str(), + application == nullptr ? "" : application, + LogLevelNames[( int ) level], + line.data(), + newl); if(syncLogFile) sync(); } @@ -111,33 +119,11 @@ void log(LogLevel level, const char * fmt, Ti &&... ti) noexcept { return; constexpr auto maxEntryLength = 1000; std::array< char, maxEntryLength > line; - snprintf(line.data(), maxEntryLength, fmt, std::forward< Ti >(ti)...); - details::doLog(level, line.data()); + auto len = snprintf(line.data(), maxEntryLength, fmt, std::forward< Ti >(ti)...); + if(len>0) + details::doLog(level, {line.data(), static_cast< std::size_t >(len)}); } -class PrintUser { - public: - template < typename Printer > - PrintUser(Printer & p) : _impl{std::make_unique< ModelImpl >(p)} {} - - private: - struct model { - virtual ~model(); - virtual void print(std::string_view line) const = 0; - }; - - template < typename Printer_T > - struct ModelImpl : public model { - ModelImpl(Printer_T & printer) : _printer{printer} {} - void print(std::string_view line) const override { - _printer.print(line); - } - Printer_T & _printer; - }; - - std::unique_ptr< model > _impl; -}; - namespace conv { enum class Error { OutOfRange, NotANumber }; @@ -157,8 +143,8 @@ namespace conv { constexpr auto max = std::numeric_limits< uint32_t >::digits10 + 1; if(userinput.empty() || userinput.size() >= max) return std::nullopt; // Avoid large or empty inputs - - char buffer[max]={0}; + + char buffer[max] = {0}; std::memcpy(buffer, userinput.data(), userinput.size()); buffer[userinput.size()] = '\0'; // Ensure null termination @@ -167,7 +153,7 @@ namespace conv { long result = std::strtol(buffer, &endptr, 10); - if(errno == ERANGE || endptr != buffer + userinput.size() || result < 0 || result > std::numeric_limits::max()) { + if(errno == ERANGE || endptr != buffer + userinput.size() || result < 0 || result > std::numeric_limits< uint32_t >::max()) { return std::nullopt; } @@ -203,12 +189,12 @@ namespace details { void trimInPlace(StrT & s) { // Remove leading whitespace size_t start = 0; - while(start < s.size() && isspace(static_cast< unsigned char >(s[start]))) + while(start < s.size() && isspace(s[start])) ++start; // Remove trailing whitespace size_t end = s.size(); - while(end > start && isspace(static_cast< unsigned char >(s[end - 1]))) + while(end > start && isspace(s[end - 1])) --end; if(start > 0 || end < s.size()) { diff --git a/PAM/ssh/include/rublon/websockets.hpp b/PAM/ssh/include/rublon/websockets.hpp index 47ffbf9..38328a3 100644 --- a/PAM/ssh/include/rublon/websockets.hpp +++ b/PAM/ssh/include/rublon/websockets.hpp @@ -64,7 +64,7 @@ class WebSocket { }; if(_config.get().logging) { - lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_DEBUG | LLL_HEADER, lws_log_emit); + lws_set_log_level(LLL_ERR | LLL_WARN | LLL_NOTICE | LLL_INFO | LLL_DEBUG, lws_log_emit); } else { lws_set_log_level(LLL_ERR | LLL_WARN, lws_log_emit); }