Skip to content

Commit

Permalink
Allow ACC communication before PUSH_REPLY by using auth pending method
Browse files Browse the repository at this point in the history
This is reusing the auth pending method as this is just another method where
the final authentication decision is pending on some results. In this case
custom messages going back and forth. This can be tested using

   client-pending-auth 5 1 "ACC:1000 A:6 cck1:certcheck:cxa1:fortune" 60'

with OpenVPN 2.x servers easily.

Also correctly use ClientEvent::Base::Ptr with the Clientevents to avoid
problems with not correctly using RCPtr

Signed-off-by: Arne Schwabe <[email protected]>
  • Loading branch information
schwabe authored and Jenkins-dev committed Jun 4, 2024
1 parent 8c15ed2 commit 3ceb4ff
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 21 deletions.
57 changes: 37 additions & 20 deletions openvpn/client/cliproto.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -841,25 +841,37 @@ class Session : ProtoContextCallbackInterface,
// race conditions in the client app, if the INFO event
// triggers the client app to perform an operation that
// requires the VPN tunnel to be ready.
ClientEvent::Base::Ptr ev;
std::string info_msg;

if (info_pre)
info_msg = msg.substr(std::string_view{"INFO_PRE,"}.length());
else
info_msg = msg.substr(std::string_view{"INFO,"}.length());

if (string::starts_with(info_msg, "ACC:"))
{
ev = new ClientEvent::Info(msg.substr(std::strlen("INFO_PRE,")));
if ((string::starts_with(ev->render(), "WEB_AUTH:") || string::starts_with(ev->render(), "CR_TEXT:")) && creds)
{
creds->set_need_user_interaction();
}
// We want this to be parsed exactly like the custom-control option.
// That means we replace ACC: with custom-control for the parser.
auto acc_options = OptionList::parse_from_csv_static("custom-control " + info_msg.substr(std::strlen("ACC:")), &pushed_options_limit);
proto_context.conf().parse_custom_app_control(acc_options);
// check if we need to notify about ACC protocols
notify_client_acc_protocols();
}
else
{
ev = new ClientEvent::Info(msg.substr(std::strlen("INFO,")));
}
if ((string::starts_with(info_msg, "WEB_AUTH:") || string::starts_with(info_msg, "CR_TEXT:")) && creds)
{
creds->set_need_user_interaction();
}

// INFO_PRE is like INFO but it is never buffered
if (info_hold && !info_pre)
info_hold->push_back(std::move(ev));
else
cli_events->add_event(std::move(ev));
ClientEvent::Info::Ptr ev = new ClientEvent::Info(std::move(info_msg));

// INFO_PRE is like INFO but it is never buffered
if (info_hold && !info_pre)
info_hold->push_back(std::move(ev));
else
cli_events->add_event(std::move(ev));
}
}

// proto base class calls here for app-level control-channel messages received
Expand Down Expand Up @@ -930,7 +942,7 @@ class Session : ProtoContextCallbackInterface,
}
else if (proto_context.conf().app_control_config.supports_protocol(proto))
{
auto ev = new ClientEvent::AppCustomControlMessage(std::move(proto), std::move(app_proto_msg));
ClientEvent::Base::Ptr ev = new ClientEvent::AppCustomControlMessage(std::move(proto), std::move(app_proto_msg));
cli_events->add_event(std::move(ev));
}
else
Expand Down Expand Up @@ -970,6 +982,16 @@ class Session : ProtoContextCallbackInterface,
}
}

void notify_client_acc_protocols()
{
if (!proto_context.conf().app_control_config.supported_protocols.empty())
{
// Signal support for supported protocols
ClientEvent::Base::Ptr ev = new ClientEvent::AppCustomControlMessage("internal:supported_protocols", string::join(proto_context.conf().app_control_config.supported_protocols, ":"));
cli_events->add_event(std::move(ev));
}
}

void recv_push_reply(const std::string &msg)
{
if (!received_options.complete())
Expand Down Expand Up @@ -1054,12 +1076,7 @@ class Session : ProtoContextCallbackInterface,
cli_events->add_event(connected_);

// send an event for custom app control if present
if (!proto_context.conf().app_control_config.supported_protocols.empty())
{
// Signal support for supported protocols
auto ev = new ClientEvent::AppCustomControlMessage("internal:supported_protocols", string::join(proto_context.conf().app_control_config.supported_protocols, ":"));
cli_events->add_event(std::move(ev));
}
notify_client_acc_protocols();

// check for proto options
check_proto_warnings();
Expand Down
12 changes: 11 additions & 1 deletion test/ovpncli/cli.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,20 +342,30 @@ class Client : public ClientBase
}
}
}

/**
@brief Handles ACC messages
@param acev The current ACC event
*/
virtual void acc_event(const ClientAPI::AppCustomControlMessageEvent &acev) override
{
if (acev.protocol == certcheck_init_verb)
if (acev.protocol == "internal:supported_protocols")
{
std::cout << "Client/server common app custom control protocols: " << acev.payload << std::endl;
}
else if (acev.protocol == certcheck_init_verb)
{
if (string::starts_with(acev.payload, "{\"dpc_certcheck_cert_req\""))
{
std::cout << "ACC CERTCHECK challenge initiated\n";
handle_certcheck_request();
}
}
else
{
std::cout << "received app custom control message for protocol " << acev.protocol
<< " msg payload: " << acev.payload << std::endl;
}
}

/**
Expand Down

0 comments on commit 3ceb4ff

Please sign in to comment.