From e5cc1f619e5f2f90a9332479d347644f80ecf92b Mon Sep 17 00:00:00 2001 From: Bartosz Wieczorek Date: Fri, 30 May 2025 14:22:06 +0200 Subject: [PATCH] rewrite configuration reading module --- PAM/ssh/include/rublon/configuration.hpp | 331 ++++++++++++----------- PAM/ssh/include/rublon/core_handler.hpp | 3 +- PAM/ssh/include/rublon/curl.hpp | 35 ++- PAM/ssh/include/rublon/error.hpp | 2 + PAM/ssh/include/rublon/finish.hpp | 7 +- PAM/ssh/include/rublon/init.hpp | 7 +- PAM/ssh/include/rublon/utils.hpp | 63 ++++- PAM/ssh/include/rublon/websockets.hpp | 23 +- PAM/ssh/lib/pam.cpp | 6 +- 9 files changed, 274 insertions(+), 203 deletions(-) diff --git a/PAM/ssh/include/rublon/configuration.hpp b/PAM/ssh/include/rublon/configuration.hpp index 5c335d0..1001bb1 100644 --- a/PAM/ssh/include/rublon/configuration.hpp +++ b/PAM/ssh/include/rublon/configuration.hpp @@ -1,14 +1,14 @@ #pragma once +#include +#include #include #include #include -#include -template < typename T > -constexpr bool is_static_string_v = std::is_base_of_v< rublon::details::StaticStringBase, T >; - -static_assert(is_static_string_v< rublon::StaticString< 32 > >); +#include +#include +#include namespace rublon { class ConfigurationFactory; @@ -16,11 +16,16 @@ class ConfigurationFactory; enum class FailMode { bypass, deny }; class Configuration { + private: + std::pmr::memory_resource * memoryResource; + public: + Configuration() : memoryResource{memory::default_resource()} {} + // change to StaticString - StaticString< 32 > systemToken{}; - StaticString< 32 > secretKey{}; - StaticString< 4096 > apiServer{}; + std::pmr::string systemToken{memoryResource}; + std::pmr::string secretKey{memoryResource}; + std::pmr::string apiServer{memoryResource}; int prompt{}; bool enablePasswdEmail{}; @@ -29,168 +34,36 @@ class Configuration { FailMode failMode{}; bool nonInteractiveMode{}; - StaticString< 8 > proxyType{}; - StaticString< 4096 > proxyServer{}; - StaticString< 256 > proxyUsername{}; - StaticString< 256 > proxyPass{}; - int proxyPort{}; - bool proxyAuthRequired{}; - bool proxyEnabled{}; + std::optional< std::pmr::string > proxyType{memoryResource}; + std::optional< std::pmr::string > proxyServer{memoryResource}; + std::optional< std::pmr::string > proxyUsername{memoryResource}; + std::optional< std::pmr::string > proxyPass{memoryResource}; + std::optional< int > proxyPort{}; + bool proxyAuthRequired{}; // defaulted + bool proxyEnabled{}; // defaulted }; -namespace { - template < class C, typename T > - T member_ptr_t(T C::*v); - template < typename T > - tl::expected< T, ConfigurationError > to(std::string_view); - - template < class T > - auto to_string(std::string_view arg) -> tl::expected< T, ConfigurationError > { - T value{}; - assert(arg.size() <= (value.size() - 1)); - std::memcpy(value.data(), arg.data(), arg.size()); - return value; - } - - template <> - auto to(std::string_view arg) -> tl::expected< bool, ConfigurationError > { - return conv::to_bool(arg); - } - template <> - auto to(std::string_view arg) -> tl::expected< int, ConfigurationError > { - return conv::to_uint32(arg).value_or(0); - } - - template <> - auto to(std::string_view arg) -> tl::expected< FailMode, ConfigurationError > { - if(arg == "bypass") - return FailMode::bypass; - if(arg == "deny") - return FailMode::deny; - return tl::unexpected{ConfigurationError{ConfigurationError::ErrorClass::BadFailMode}}; - } - - template < typename T > - auto parse(std::string_view arg) -> tl::expected< T, ConfigurationError > { - if(arg.empty()) { - return tl::unexpected{ConfigurationError::ErrorClass::Empty}; - } else { - if constexpr(is_static_string_v< T >) { - return to_string< T >(arg); - } else { - return to< T >(arg); - } - } - } - -} // namespace -struct Entry { - enum class Source { UserInput, DefaultValue }; - template < auto member > - static constexpr auto make_read_function() { - using pType = decltype(member_ptr_t(member)); - - return - [](const Entry * _this, Configuration * configuration, std::string_view userInput) -> tl::expected< Source, ConfigurationError > { - const auto setDefaultValue = [&](const ConfigurationError & error) -> tl::expected< Source, ConfigurationError > { - log(LogLevel::Warning, "applying user provided value for %s parameter, faild with %s", _this->name, error.what()); - if(_this->defaultValue != nullptr) { - configuration->*member = parse< pType >(_this->defaultValue).value(); - return Source::DefaultValue; - } else { - log(LogLevel::Error, "parameter %s has not been found and has no default value", _this->name); - if(userInput.empty()) - return tl::unexpected{ConfigurationError::ErrorClass::RequiredValueNotFound}; - else - return tl::unexpected{ConfigurationError::ErrorClass::BadInput}; - } - }; - - const auto saveValue = [&](const auto & value) -> tl::expected< Source, ConfigurationError > { - configuration->*member = value; - return Source::UserInput; - }; - - return parse< pType >(userInput).and_then(saveValue).or_else(setDefaultValue); - }; - } - - const char * name; - const char * defaultValue; - tl::expected< Source, ConfigurationError > (*_read)(const Entry * _this, Configuration * configuration, std::string_view userInput); - - bool read(Configuration * configuration, std::optional< std::string_view > userInput) const { - constexpr const auto emptyString = ""; - const auto logStored = [&](const auto & source) -> tl::expected< Source, ConfigurationError > { - rublon::log(LogLevel::Debug, - "Configuration parameter '%s' was set to '%s'%s", - this->name, - this->defaultValue, - source == Source::DefaultValue ? " (default)" : ""); - return source; - }; - - const auto logError = [&](const auto & error) -> tl::expected< Source, ConfigurationError > { - rublon::log(LogLevel::Error, - "Configuration parameter '%s' has no default value and is not provided in user configuraion, aborting", - this->name); - return tl::unexpected{error}; - }; - - return _read(this, configuration, userInput.value_or(emptyString)).and_then(logStored).or_else(logError).has_value(); - } -}; - -template < auto member > -constexpr auto make_entry(const char * name, const char * defaultValue) { - return Entry{name, defaultValue, Entry::make_read_function< member >()}; -} - -constexpr static inline std::array< Entry, 16 > configurationVariables = { - make_entry< &Configuration::logging >("logging", "true"), - make_entry< &Configuration::systemToken >("systemToken", nullptr), - make_entry< &Configuration::secretKey >("secretKey", nullptr), - make_entry< &Configuration::apiServer >("rublonApiServer", nullptr), - make_entry< &Configuration::prompt >("prompt", "1"), - make_entry< &Configuration::enablePasswdEmail >("enablePasswdEmail", "true"), - make_entry< &Configuration::autopushPrompt >("autopushPrompt", "false"), - make_entry< &Configuration::failMode >("failMode", "deny"), - make_entry< &Configuration::nonInteractiveMode >("nonInteractiveMode", "false"), - - make_entry< &Configuration::proxyType >("proxyType", nullptr), - make_entry< &Configuration::proxyServer >("proxyServer", nullptr), - make_entry< &Configuration::proxyUsername >("proxyUsername", nullptr), - make_entry< &Configuration::proxyPass >("proxyPass", nullptr), - make_entry< &Configuration::proxyPort >("proxyPort", "8080"), - make_entry< &Configuration::proxyAuthRequired >("proxyAuthRequired", "false"), - make_entry< &Configuration::proxyEnabled >("proxyEnabled", "false") // -}; - -class ConfigurationFactory { +class ConfigurationReader { public: - ConfigurationFactory() = default; + ConfigurationReader(std::pmr::memory_resource * memResource = memory::default_resource()) : memoryResource(memResource) {} - std::optional< Configuration > systemConfig() { - memory::MonotonicStackResource< 16 * 1024 > stackResource; - Configuration configuration{}; - - std::ifstream file(std::filesystem::path{"/etc/rublon.config"}); + // Load config from file path + bool loadFromFile(const std::string & filepath) { + using namespace memory::literals; + memory::MonotonicStackResource< 8_kB > stackResource; + std::ifstream file(filepath); if(not file.good()) - return std::nullopt; + return false; std::pmr::string line{&stackResource}; - line.reserve(100); - std::pmr::map< std::pmr::string, std::pmr::string > parameters{&stackResource}; - - const auto readParameterByName = [&](std::string_view name) -> std::optional< std::string_view > { - return parameters.count(name.data()) ? std::optional< std::string_view >{parameters.at(name.data())} : std::nullopt; - }; + line.reserve(8000); // allocate full stack to line while(std::getline(file, line)) { - std::pmr::string key{&stackResource}; - std::pmr::string value{&stackResource}; + std::pmr::string key{memoryResource}; + std::pmr::string value{memoryResource}; + details::trimInPlace(line); if(!line.length()) continue; @@ -201,15 +74,147 @@ class ConfigurationFactory { key = line.substr(0, posEqual); value = line.substr(posEqual + 1); - parameters[std::move(key)] = std::move(value); + keyValues[std::move(key)] = std::move(value); } - for(const auto & entry : configurationVariables) { - if(not entry.read(&configuration, readParameterByName(entry.name))) + return true; + } + + // Load values into Configuration object, with defaults provided + tl::expected< bool, ConfigurationError > applyTo(Configuration & config) { + // Helper lambdas for conversion + using string = std::pmr::string; + + auto getStringOpt = [&](const string & key) -> std::optional< std::pmr::string > { + auto it = keyValues.find(key); + if(it == keyValues.end()) { return std::nullopt; + } + return string{it->second.data(), it->second.size(), memoryResource}; + }; + + auto getStringReq = [&](const string & key) -> tl::expected< std::pmr::string, ConfigurationError > { + auto val = getStringOpt(key); + if(val.has_value()) + return std::move(val.value()); + return tl::unexpected{ConfigurationError::ErrorClass::RequiredValueNotFound}; + }; + + auto getInt = [&](const string & key) -> std::optional< int > { + auto it = keyValues.find(key); + if(it == keyValues.end()) + return std::nullopt; + return conv::to_uint32opt(it->second); + }; + + auto getBool = [&](const string & key) -> std::optional< bool > { + memory::MonotonicStackResource< 64 > memoryResource; + auto it = keyValues.find(key); + if(it == keyValues.end()) + return std::nullopt; + + if (it->second.size() > 5 ){ + log(LogLevel::Warning, "Configuration value %s is too long, please check", key.c_str()); + return std::nullopt; + } + + 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)); }); + + if(val == "1" || val == "true" || val == "yes" || val == "on") + return true; + if(val == "0" || val == "false" || val == "no" || val == "off") + return false; + return std::nullopt; + }; + + auto getFailMode = [&](const string & key) -> std::optional< FailMode > { + auto it = keyValues.find(key); + if(it == keyValues.end()) + return std::nullopt; + auto val = it->second; + if(val == "bypass") + return FailMode::bypass; + if(val == "deny") + return FailMode::deny; + + return std::nullopt; + }; + + // Reading required fields + if(auto val = getStringReq("systemToken"); not val.has_value()) + return tl::unexpected{val.error()}; + else + config.systemToken = std::move(val.value()); + + if(auto val = getStringReq("secretKey"); not val.has_value()) + return tl::unexpected{val.error()}; + else + config.secretKey = std::move(val.value()); + + if(auto val = getStringReq("rublonApiServer"); not val.has_value()) + return tl::unexpected{val.error()}; + else + config.apiServer = std::move(val.value()); + + // optional + config.prompt = getInt("prompt").value_or(1); + config.enablePasswdEmail = getBool("enablePasswdEmail").value_or(true); + config.logging = getBool("logging").value_or(true); + config.autopushPrompt = getBool("autopushPrompt").value_or(false); + config.nonInteractiveMode = getBool("nonInteractiveMode").value_or(false); + config.failMode = getFailMode("failMode").value_or(FailMode::deny); + + // reading proxy configuration + config.proxyEnabled = getBool("proxyEnabled").value_or(false); + config.proxyType = getStringOpt("proxyType"); + config.proxyServer = getStringOpt("proxyServer"); + if(config.proxyEnabled) { + if(not config.proxyType) { + log(LogLevel::Error, "Proxy is enabled but proxy type is not set"); + return tl::unexpected{ConfigurationError::ErrorClass::BadConfiguration}; + } + if(not config.proxyServer) { + log(LogLevel::Error, "Proxy is enabled but proxy server is not set"); + return tl::unexpected{ConfigurationError::ErrorClass::BadConfiguration}; + } + } + config.proxyAuthRequired = getBool("proxyAuthRequired").value_or(false); + config.proxyUsername = getStringOpt("proxyUsername"); + config.proxyPass = getStringOpt("proxyPass"); + if(config.proxyAuthRequired) { + if(not config.proxyUsername) { + log(LogLevel::Error, "Proxy auth is required but proxy proxy username is not set"); + return tl::unexpected{ConfigurationError::ErrorClass::BadConfiguration}; + } + if(not config.proxyPass) { + log(LogLevel::Error, "Proxy is enabled but proxy password is not set,"); + return tl::unexpected{ConfigurationError::ErrorClass::BadConfiguration}; + } } - return configuration; + config.proxyPort = getInt("proxyPort").value_or(8080); + return true; + } + + private: + std::pmr::memory_resource * memoryResource; + std::pmr::map< std::pmr::string, std::pmr::string > keyValues{memoryResource}; +}; + +class ConfigurationFactory { + public: + ConfigurationFactory() = default; + + std::optional< Configuration > systemConfig() { + std::optional< Configuration > conf{Configuration{}}; + ConfigurationReader reader; + reader.loadFromFile("/etc/rublon.config"); + if(auto ok = reader.applyTo(conf.value()); not ok.has_value()){ + return std::nullopt; + } + return conf.value(); } }; } // namespace rublon diff --git a/PAM/ssh/include/rublon/core_handler.hpp b/PAM/ssh/include/rublon/core_handler.hpp index 46feb55..06ac82d 100755 --- a/PAM/ssh/include/rublon/core_handler.hpp +++ b/PAM/ssh/include/rublon/core_handler.hpp @@ -172,7 +172,8 @@ class CoreHandler : public CoreHandlerInterface< CoreHandler< HttpHandler > > { signRequest(request); std::pmr::string uri{&memoryResource}; - uri += _config.apiServer.c_str(); + uri.reserve(_config.apiServer.size() + path.size() + 1); + uri += _config.apiServer; uri += path.data(); return http diff --git a/PAM/ssh/include/rublon/curl.hpp b/PAM/ssh/include/rublon/curl.hpp index 912aa91..ea70027 100644 --- a/PAM/ssh/include/rublon/curl.hpp +++ b/PAM/ssh/include/rublon/curl.hpp @@ -1,6 +1,7 @@ #pragma once #include "rublon/memory.hpp" +#include #include #include #include @@ -11,6 +12,7 @@ namespace rublon { + namespace { size_t WriteMemoryCallback(void * contents, size_t size, size_t nmemb, void * userp) { const size_t realsize = size * nmemb; @@ -60,7 +62,7 @@ class CURL { tl::expected< std::reference_wrapper< Response >, ConnectionError > request(std::string_view uri, const Request & request, Response & response) const { using namespace memory::literals; - memory::Monotonic_16k_HeapResource memoryResource; + memory::Monotonic_8k_HeapResource memoryResource; std::pmr::string response_data{&memoryResource}; response_data.reserve(4_kB); @@ -73,16 +75,20 @@ class CURL { // Optional: Build full proxy URL if proxy is enabled if (_config.proxyEnabled) { - std::pmr::string proxyUrl{&memoryResource}; - proxyUrl.reserve(4_kB); + // configuration reader check if proxy has needed fields + assert(_config.proxyType.has_value()); + assert(_config.proxyServer.has_value()); + std::pmr::string proxyUrl{&memoryResource}; + proxyUrl.reserve(conservative_estimate(_config.proxyType, _config.proxyServer, _config.proxyPort) + 10); + if (_config.proxyType == "http" || _config.proxyType == "https" || _config.proxyType == "socks4" || _config.proxyType == "socks5") { - proxyUrl = _config.proxyType.c_str(); + proxyUrl = *_config.proxyType; proxyUrl += "://"; - proxyUrl += _config.proxyServer.c_str(); + proxyUrl += *_config.proxyServer; if (_config.proxyPort > 0) { proxyUrl += ":"; - proxyUrl += std::to_string(_config.proxyPort); + proxyUrl += std::to_string(*_config.proxyPort); } curl_easy_setopt(curl.get(), CURLOPT_PROXY, proxyUrl.c_str()); @@ -96,12 +102,19 @@ class CURL { } if (_config.proxyAuthRequired) { + assert(_config.proxyUsername.has_value()); + assert(_config.proxyPass.has_value()); + std::pmr::string proxyAuth{&memoryResource}; - proxyAuth.reserve(1_kB); - _config.proxyUsername.c_str(); - proxyAuth += ":"; - proxyAuth += _config.proxyPass.c_str(); - + proxyAuth.reserve(conservative_estimate(_config.proxyUsername->size() + _config.proxyPass->size())); + + proxyAuth += *_config.proxyUsername; + if(_config.proxyPass->size()) { + // can proxy have name but no pass? + proxyAuth += ":"; + proxyAuth += *_config.proxyPass; + } + curl_easy_setopt(curl.get(), CURLOPT_PROXYUSERPWD, proxyAuth.c_str()); } } diff --git a/PAM/ssh/include/rublon/error.hpp b/PAM/ssh/include/rublon/error.hpp index 21af816..79eee49 100755 --- a/PAM/ssh/include/rublon/error.hpp +++ b/PAM/ssh/include/rublon/error.hpp @@ -15,12 +15,14 @@ class ConfigurationError { RequiredValueNotFound, BadFailMode, BadInput, + BadConfiguration, Empty }; constexpr static auto errorClassPrettyName = make_array< std::string_view >( // "RequiredValueNotFound", "BadFailMode", "BadInput", + "BadConfiguration", "Empty"); constexpr static auto prettyName = "Configurtion Error"; diff --git a/PAM/ssh/include/rublon/finish.hpp b/PAM/ssh/include/rublon/finish.hpp index c943d2f..ad598eb 100644 --- a/PAM/ssh/include/rublon/finish.hpp +++ b/PAM/ssh/include/rublon/finish.hpp @@ -4,16 +4,17 @@ #include #include #include +#include #include namespace rublon { class Finish : public AuthenticationStep { const char * apiPath = "/api/transaction/credentials"; - const std::string _accessToken; + const std::string_view _accessToken; // void addAccessToken(Document & coreRequest) const { auto & alloc = coreRequest.GetAllocator(); - coreRequest.AddMember("accessToken", Value{_accessToken.c_str(), alloc}, alloc); + coreRequest.AddMember("accessToken", Value{_accessToken.data(), alloc}, alloc); } tl::expected< bool, Error > returnOk(const Document & /*coreResponse*/) const { @@ -23,7 +24,7 @@ class Finish : public AuthenticationStep { public: const char * name = "Finalization"; - Finish(Session & session, std::string accessToken) : AuthenticationStep(session), _accessToken{std::move(accessToken)} {} + Finish(Session & session, std::string_view accessToken) : AuthenticationStep(session), _accessToken{accessToken} {} template < typename Hander_t > tl::expected< bool, Error > handle(const CoreHandlerInterface< Hander_t > & coreHandler) const { diff --git a/PAM/ssh/include/rublon/init.hpp b/PAM/ssh/include/rublon/init.hpp index dd524e6..216816f 100644 --- a/PAM/ssh/include/rublon/init.hpp +++ b/PAM/ssh/include/rublon/init.hpp @@ -43,12 +43,11 @@ class Init : public AuthenticationStep { } void addParams(Document & coreRequest, const Pam_t & pam) const { - memory::MonotonicStackResource< 1024 > stackResource; - std::pmr::string releaseInfo{&stackResource}; + memory::MonotonicStackResource< 1024 > memoryResource; auto & alloc = coreRequest.GetAllocator(); - const auto os = details::osName(&stackResource); - const auto host = details::hostname(&stackResource); + const auto os = details::osName(&memoryResource); + const auto host = details::hostname(&memoryResource); if(os == "unknown") { log(LogLevel::Warning, "No OS information available"); diff --git a/PAM/ssh/include/rublon/utils.hpp b/PAM/ssh/include/rublon/utils.hpp index 9078dd4..973584a 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 @@ -158,6 +159,14 @@ namespace conv { return tl::make_unexpected(Error::OutOfRange); } } + + inline std::optional< std::uint32_t> to_uint32opt(std::string_view userinput) noexcept { + try { + return std::stoi(userinput.data()); + } catch(...) { + return std::nullopt; + } + } } // namespace conv namespace details { @@ -176,6 +185,23 @@ namespace details { static inline std::string_view trim(std::string_view s) { return ltrim(rtrim(s)); } + + template + void trimInPlace(StrT & s) { + // Remove leading whitespace + size_t start = 0; + while(start < s.size() && isspace(static_cast< unsigned char >(s[start]))) + ++start; + + // Remove trailing whitespace + size_t end = s.size(); + while(end > start && isspace(static_cast< unsigned char >(s[end - 1]))) + --end; + + if(start > 0 || end < s.size()) { + s = s.substr(start, end - start); + } + } template < typename Headers > inline void headers(std::string_view data, Headers & headers) { @@ -197,7 +223,7 @@ namespace details { } std::pmr::string hostname(std::pmr::memory_resource * mr) { - std::pmr::string hostname{512, '\0', mr}; + std::pmr::string hostname{2048, '\0', mr}; if(gethostname(hostname.data(), hostname.size()) != 0) { log(LogLevel::Warning, "Hostname is not available"); return ""; @@ -207,18 +233,18 @@ namespace details { } std::pmr::string osName(std::pmr::memory_resource * mr) { - memory::MonotonicStackResource< 8 * 1024 > stackResource; + memory::Monotonic_8k_HeapResource memoryResource; std::ifstream file(std::filesystem::path{"/etc/os-release"}); if(not file.good()) return {"unknown", mr}; - std::pmr::string line{&stackResource}; + std::pmr::string line{&memoryResource}; + std::pmr::string _key{&memoryResource}; + std::pmr::string _value{&memoryResource}; line.reserve(100); - + while(std::getline(file, line)) { - std::pmr::string _key{&stackResource}; - std::pmr::string _value{&stackResource}; if(!line.length()) continue; @@ -266,4 +292,29 @@ constexpr std::array< Out, sizeof...(Types) > make_array(Types... names) { return {std::forward< Types >(names)...}; } +template std::size_t size_buffer(const T &item) { + using U = std::decay_t; + if constexpr (std::is_same_v) { + return strlen(item); + } else if constexpr(std::is_same_v< U, std::pmr::string > || std::is_same_v< U, std::string >) { + return item.size(); + } else if constexpr(std::is_integral_v< U > || std::is_floating_point_v< U >) { + return std::numeric_limits::digits; + } + return 0; +} + +template std::size_t size_buffer(const std::optional &item) { + if(item.has_value()) + return size_buffer(*item); + return 0; +} + +// min + 10% +template < typename... Args > +std::size_t conservative_estimate(const Args &... args) { + auto min = (size_buffer(args) + ...); + return min + min * 10 / 100; +} + } // namespace rublon diff --git a/PAM/ssh/include/rublon/websockets.hpp b/PAM/ssh/include/rublon/websockets.hpp index 1ef4758..e54761e 100644 --- a/PAM/ssh/include/rublon/websockets.hpp +++ b/PAM/ssh/include/rublon/websockets.hpp @@ -44,10 +44,8 @@ class WebSocket { RublonEventData * currentEvent{nullptr}; public: - WebSocket(const Configuration & config) : _config{config}, urlv{_config.get().apiServer.c_str(), _config.get().apiServer.size()} { - using namespace memory::literals; - memory::Monotonic_8k_HeapResource memoryResource; - const auto & cfg = _config.get(); + WebSocket(const Configuration & config) : _config{config}, urlv{_config.get().apiServer} { + const auto & cfg = _config.get(); // only a alias to not use _config.get() all the time auto lws_log_emit = [](int level, const char * line) { LogLevel rlevel{}; @@ -77,23 +75,27 @@ class WebSocket { context = lws_create_context(&info); if(cfg.proxyEnabled && (cfg.proxyType == "http" || cfg.proxyType == "https")) { + assert(cfg.proxyType.has_value()); + assert(cfg.proxyServer.has_value()); + + memory::Monotonic_8k_HeapResource memoryResource; std::pmr::string proxyUrl{&memoryResource}; - proxyUrl.reserve(4_kB); + proxyUrl.reserve(conservative_estimate(cfg.proxyUsername, cfg.proxyPass, cfg.proxyServer, cfg.proxyPort) + 10); - proxyUrl += cfg.proxyType.data(); + proxyUrl += cfg.proxyType->data(); proxyUrl += "://"; if(cfg.proxyAuthRequired) { - proxyUrl += cfg.proxyUsername.c_str(); + proxyUrl += *cfg.proxyUsername; proxyUrl += ":"; - proxyUrl += cfg.proxyPass.c_str(); + proxyUrl += *cfg.proxyPass; proxyUrl += "@"; } - proxyUrl += cfg.proxyServer.c_str(); + proxyUrl += *cfg.proxyServer; if(cfg.proxyPort > 0) { proxyUrl += ":"; - proxyUrl += std::to_string(cfg.proxyPort); + proxyUrl += std::to_string(*cfg.proxyPort); } // Set environment variable for libwebsockets to pick up @@ -101,7 +103,6 @@ class WebSocket { } const std::string_view prefix = "https://"; - if(urlv.substr(0, prefix.size()) == prefix) urlv.remove_prefix(prefix.size()); diff --git a/PAM/ssh/lib/pam.cpp b/PAM/ssh/lib/pam.cpp index ee3b197..8f3b8dc 100644 --- a/PAM/ssh/lib/pam.cpp +++ b/PAM/ssh/lib/pam.cpp @@ -83,9 +83,7 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu auto finalizeTransaction = [&](const AuthenticationStatus & status) mutable -> tl::expected< AuthenticationStatus, Error > { if(status.userAuthorized()) { - auto tok = std::string{status.accessToken().data()}; - Finish finish{session.value(), std::move(tok)}; - finish.handle(CH); + Finish{session.value(), status.accessToken()}.handle(CH); } return status; }; @@ -101,7 +99,7 @@ pam_sm_authenticate(pam_handle_t * pamh, [[maybe_unused]] int flags, [[maybe_unu { CheckApplication ca; const auto & config = session.value().config(); - const auto ret = ca.call(CH, {config.systemToken.data(), config.systemToken.size()}).or_else(mapError); + const auto ret = ca.call(CH, config.systemToken).or_else(mapError); if(not ret.has_value()) { log(LogLevel::Error, "Check Application step failed, check configration"); return PAM_MAXTRIES;