From d7b316bd11380aa7940f9016d95b43da1dda5ac8 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 15 Dec 2021 13:01:32 +0100 Subject: [PATCH] Move helper function from OpenVPNClient int OpenVPNClientHelper This also makes most of them non-static to avoid the problem that these functions depend on Initprocess::Init being instantiated before being called. Rename the local variables eval to eval_cfg to avoid shadowing the class field of the same name. --- client/ovpncli.cpp | 37 ++++++++++++------- client/ovpncli.hpp | 87 +++++++++++++++++++++++++++++--------------- javacli/ovpncli.i | 1 + test/ovpncli/cli.cpp | 43 ++++++++++++---------- 4 files changed, 105 insertions(+), 63 deletions(-) diff --git a/client/ovpncli.cpp b/client/ovpncli.cpp index bf7cf91f..09902f64 100644 --- a/client/ovpncli.cpp +++ b/client/ovpncli.cpp @@ -619,7 +619,7 @@ namespace openvpn { state->proto_context_options.reset(new ProtoContextOptions()); } - OPENVPN_CLIENT_EXPORT void OpenVPNClient::parse_config(const Config& config, EvalConfig& eval, OptionList& options) + OPENVPN_CLIENT_EXPORT void OpenVPNClientHelper::parse_config(const Config& config, EvalConfig& eval, OptionList& options) { try { // validate proto_override @@ -740,27 +740,37 @@ namespace openvpn { } } - OPENVPN_CLIENT_EXPORT long OpenVPNClient::max_profile_size() + OpenVPNClientHelper::OpenVPNClientHelper() : init(new InitProcess::Init()) + { + + } + + OpenVPNClientHelper::~OpenVPNClientHelper() + { + delete init; + } + + OPENVPN_CLIENT_EXPORT long OpenVPNClientHelper::max_profile_size() { return ProfileParseLimits::MAX_PROFILE_SIZE; } - OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::merge_config_static(const std::string& path, - bool follow_references) + OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClientHelper::merge_config(const std::string& path, + bool follow_references) { ProfileMerge pm(path, "ovpn", "", follow_references ? ProfileMerge::FOLLOW_PARTIAL : ProfileMerge::FOLLOW_NONE, ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE); return build_merge_config(pm); } - OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::merge_config_string_static(const std::string& config_content) + OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClientHelper::merge_config_string(const std::string& config_content) { ProfileMergeFromString pm(config_content, "", ProfileMerge::FOLLOW_NONE, ProfileParseLimits::MAX_LINE_SIZE, ProfileParseLimits::MAX_PROFILE_SIZE); return build_merge_config(pm); } - OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClient::build_merge_config(const ProfileMerge& pm) + OPENVPN_CLIENT_EXPORT MergeConfig OpenVPNClientHelper::build_merge_config(const ProfileMerge& pm) { MergeConfig ret; ret.status = pm.status_string(); @@ -777,7 +787,7 @@ namespace openvpn { return ret; } - OPENVPN_CLIENT_EXPORT EvalConfig OpenVPNClient::eval_config_static(const Config& config) + OPENVPN_CLIENT_EXPORT EvalConfig OpenVPNClientHelper::eval_config(const Config& config) { EvalConfig eval; OptionList options; @@ -790,7 +800,7 @@ namespace openvpn { { // parse and validate configuration file EvalConfig eval; - parse_config(config, eval, state->options); + OpenVPNClientHelper::parse_config(config, eval, state->options); if (eval.error) return eval; @@ -826,7 +836,7 @@ namespace openvpn { return true; } - OPENVPN_CLIENT_EXPORT bool OpenVPNClient::parse_dynamic_challenge(const std::string& cookie, DynamicChallenge& dc) + OPENVPN_CLIENT_EXPORT bool OpenVPNClientHelper::parse_dynamic_challenge(const std::string& cookie, DynamicChallenge& dc) { try { ChallengeResponse cr(cookie); @@ -888,7 +898,7 @@ namespace openvpn { Log::Context log_context(this); #endif - OPENVPN_LOG(ClientAPI::OpenVPNClient::platform()); + OPENVPN_LOG(ClientAPI::OpenVPNClientHelper::platform()); return do_connect(); } @@ -1372,18 +1382,17 @@ namespace openvpn { state->on_disconnect(); } - OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::crypto_self_test() + OPENVPN_CLIENT_EXPORT std::string OpenVPNClientHelper::crypto_self_test() { return SelfTest::crypto_self_test(); } - - OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::copyright() + OPENVPN_CLIENT_EXPORT std::string OpenVPNClientHelper::copyright() { return openvpn_copyright; } - OPENVPN_CLIENT_EXPORT std::string OpenVPNClient::platform() + OPENVPN_CLIENT_EXPORT std::string OpenVPNClientHelper::platform() { std::string ret = platform_string(); #ifdef PRIVATE_TUNNEL_PROXY diff --git a/client/ovpncli.hpp b/client/ovpncli.hpp index be6fa542..b9e7ee90 100644 --- a/client/ovpncli.hpp +++ b/client/ovpncli.hpp @@ -38,6 +38,10 @@ namespace openvpn { class ProfileMerge; class Stop; + namespace InitProcess { + class Init; + }; + namespace ClientAPI { // Represents an OpenVPN server and its friendly name // (client reads) @@ -461,6 +465,60 @@ namespace openvpn { class ClientState; }; + /** + * Helper class for OpenVPN clients. Provider helper method to be used with + * the \sa OpenVPNClient class. + */ + class OpenVPNClientHelper { + /* To call parse_config */ + friend class OpenVPNClient; + public: + OpenVPNClientHelper(); + + ~OpenVPNClientHelper(); + + OpenVPNClientHelper(OpenVPNClientHelper &) = delete; + + // Read an OpenVPN profile that might contain external + // file references, returning a unified profile. + MergeConfig merge_config(const std::string& path, bool follow_references); + + // Read an OpenVPN profile that might contain external + // file references, returning a unified profile. + MergeConfig merge_config_string(const std::string& config_content); + + // Parse profile and determine needed credentials statically. + EvalConfig eval_config(const Config& config); + + // Maximum size of profile that should be allowed + static long max_profile_size(); + + // Parse a dynamic challenge cookie, placing the result in dc. + // Return true on success or false if parse error. + static bool parse_dynamic_challenge(const std::string& cookie, DynamicChallenge& dc); + + // Do a crypto library self test + std::string crypto_self_test(); + + // Returns platform description string + static std::string platform(); + + // Returns core copyright + static std::string copyright(); + private: + static MergeConfig build_merge_config(const ProfileMerge&); + + static void parse_config(const Config&, EvalConfig&, OptionList&); + + /* including initprocess.hpp here break since it pulls in logging + * (OPENVPN_LOG) which not setup when including this header, so break that + * cycle here with a pointer instead a normal member, std::unique_ptr + * and std::unique_ptr because they still need to have the initprocess.hpp + * included in the same compilation unit which breaks in the swig wrapped + * class, so we use a plain pointer and new/delete in constructor/destructor */ + InitProcess::Init* init; + }; + // Top-level OpenVPN client class. class OpenVPNClient : public TunBuilderBase, // expose tun builder virtual methods public LogReceiver, // log message notification @@ -472,24 +530,6 @@ namespace openvpn { OpenVPNClient(); virtual ~OpenVPNClient(); - // Read an OpenVPN profile that might contain external - // file references, returning a unified profile. - static MergeConfig merge_config_static(const std::string& path, bool follow_references); - - // Read an OpenVPN profile that might contain external - // file references, returning a unified profile. - static MergeConfig merge_config_string_static(const std::string& config_content); - - // Parse profile and determine needed credentials statically. - static EvalConfig eval_config_static(const Config& config); - - // Maximum size of profile that should be allowed - static long max_profile_size(); - - // Parse a dynamic challenge cookie, placing the result in dc. - // Return true on success or false if parse error. - static bool parse_dynamic_challenge(const std::string& cookie, DynamicChallenge& dc); - // Parse OpenVPN configuration file. EvalConfig eval_config(const Config&); @@ -584,15 +624,6 @@ namespace openvpn { // Periodic convenience clock tick, controlled by Config::clockTickMS virtual void clock_tick(); - // Do a crypto library self test - static std::string crypto_self_test(); - - // Returns platform description string - static std::string platform(); - - // Returns core copyright - static std::string copyright(); - // Hide protected methods/data from SWIG #ifdef SWIGJAVA private: @@ -615,11 +646,9 @@ namespace openvpn { void connect_setup(Status&, bool&); void do_connect_async(); static Status status_from_exception(const std::exception&); - static void parse_config(const Config&, EvalConfig&, OptionList&); void parse_extras(const Config&, EvalConfig&); void external_pki_error(const ExternalPKIRequestBase&, const size_t); void process_epki_cert_chain(const ExternalPKICertRequest&); - static MergeConfig build_merge_config(const ProfileMerge&); friend class MyClientEvents; void on_disconnect(); diff --git a/javacli/ovpncli.i b/javacli/ovpncli.i index 0671a6d2..0c084f8b 100644 --- a/javacli/ovpncli.i +++ b/javacli/ovpncli.i @@ -19,6 +19,7 @@ // modify exported C++ class names to incorporate their enclosing namespace %rename(ClientAPI_OpenVPNClient) OpenVPNClient; +%rename(ClientAPI_OpenVPNClientHelper) OpenVPNClientHelper; %rename(ClientAPI_TunBuilderBase) TunBuilderBase; %rename(ClientAPI_ExternalPKIBase) ExternalPKIBase; %rename(ClientAPI_ServerEntry) ServerEntry; diff --git a/test/ovpncli/cli.cpp b/test/ovpncli/cli.cpp index a9c4fe4b..8ba11877 100644 --- a/test/ovpncli/cli.cpp +++ b/test/ovpncli/cli.cpp @@ -280,7 +280,7 @@ private: dc_cookie = ev.info; ClientAPI::DynamicChallenge dc; - if (ClientAPI::OpenVPNClient::parse_dynamic_challenge(ev.info, dc)) { + if (ClientAPI::OpenVPNClientHelper::parse_dynamic_challenge(ev.info, dc)) { std::cout << "DYNAMIC CHALLENGE" << std::endl; std::cout << "challenge: " << dc.challenge << std::endl; std::cout << "echo: " << dc.echo << std::endl; @@ -947,12 +947,13 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content) if (version) { std::cout << "OpenVPN cli 1.0" << std::endl; - std::cout << ClientAPI::OpenVPNClient::platform() << std::endl; - std::cout << ClientAPI::OpenVPNClient::copyright() << std::endl; + std::cout << ClientAPI::OpenVPNClientHelper::platform() << std::endl; + std::cout << ClientAPI::OpenVPNClientHelper::copyright() << std::endl; } else if (self_test) { - std::cout << ClientAPI::OpenVPNClient::crypto_self_test(); + ClientAPI::OpenVPNClientHelper clihelper; + std::cout << clihelper.crypto_self_test(); } else if (merge) { @@ -1027,8 +1028,9 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content) // setenv SERVER / if (!config.serverOverride.empty()) { - const ClientAPI::EvalConfig eval = ClientAPI::OpenVPNClient::eval_config_static(config); - for (auto &se : eval.serverList) + ClientAPI::OpenVPNClientHelper clihelper; + const ClientAPI::EvalConfig cfg_eval = clihelper.eval_config(config); + for (auto &se : cfg_eval.serverList) { if (config.serverOverride == se.friendlyName) { @@ -1040,26 +1042,27 @@ int openvpn_client(int argc, char *argv[], const std::string* profile_content) if (eval) { - const ClientAPI::EvalConfig eval = ClientAPI::OpenVPNClient::eval_config_static(config); + ClientAPI::OpenVPNClientHelper clihelper; + const ClientAPI::EvalConfig cfg_eval = clihelper.eval_config(config); std::cout << "EVAL PROFILE" << std::endl; - std::cout << "error=" << eval.error << std::endl; - std::cout << "message=" << eval.message << std::endl; - std::cout << "userlockedUsername=" << eval.userlockedUsername << std::endl; - std::cout << "profileName=" << eval.profileName << std::endl; - std::cout << "friendlyName=" << eval.friendlyName << std::endl; - std::cout << "autologin=" << eval.autologin << std::endl; - std::cout << "externalPki=" << eval.externalPki << std::endl; - std::cout << "staticChallenge=" << eval.staticChallenge << std::endl; - std::cout << "staticChallengeEcho=" << eval.staticChallengeEcho << std::endl; - std::cout << "privateKeyPasswordRequired=" << eval.privateKeyPasswordRequired << std::endl; - std::cout << "allowPasswordSave=" << eval.allowPasswordSave << std::endl; + std::cout << "error=" << cfg_eval.error << std::endl; + std::cout << "message=" << cfg_eval.message << std::endl; + std::cout << "userlockedUsername=" << cfg_eval.userlockedUsername << std::endl; + std::cout << "profileName=" << cfg_eval.profileName << std::endl; + std::cout << "friendlyName=" << cfg_eval.friendlyName << std::endl; + std::cout << "autologin=" << cfg_eval.autologin << std::endl; + std::cout << "externalPki=" << cfg_eval.externalPki << std::endl; + std::cout << "staticChallenge=" << cfg_eval.staticChallenge << std::endl; + std::cout << "staticChallengeEcho=" << cfg_eval.staticChallengeEcho << std::endl; + std::cout << "privateKeyPasswordRequired=" << cfg_eval.privateKeyPasswordRequired << std::endl; + std::cout << "allowPasswordSave=" << cfg_eval.allowPasswordSave << std::endl; if (!config.serverOverride.empty()) std::cout << "server=" << config.serverOverride << std::endl; - for (size_t i = 0; i < eval.serverList.size(); ++i) + for (size_t i = 0; i < cfg_eval.serverList.size(); ++i) { - const ClientAPI::ServerEntry& se = eval.serverList[i]; + const ClientAPI::ServerEntry& se = cfg_eval.serverList[i]; std::cout << '[' << i << "] " << se.server << '/' << se.friendlyName << std::endl; } }