@@ -806,6 +806,20 @@ To accept connecting to the host and port directly, use this command:
proxy NONE
+COMMAND -- cr-response (OpenVPN 2.5 or higher)
+-------------------------------------------------
+Provides support for sending responses a challenge/response
+query via INFOMSG,CR_TEXT. The response should be base64 encoded:
+
+ cr-response SGFsbG8gV2VsdCE=
+
+The document is intended to be used after the client received a
+CR_TEXT challenge (see send-pending-auth section). The answer is
+the answer to the challenge and depends on the challenge itself
+for a TOTP challenge this would the number encoded as base64 or
+just a string for a challenge like what "day is it today?".
+
+
COMMAND -- pk-sig (OpenVPN 2.5 or higher, management version > 1)
COMMAND -- rsa-sig (OpenVPN 2.3 or higher, management version <= 1)
-----------------------------------------------------------------
@@ -291,6 +291,44 @@ ce_management_query_proxy(struct context *c)
return ret;
}
+/**
+ * This method sends a custom control channel message
+ *
+ * This will write the control message
+ *
+ * command parm1,parm2,..
+ * .
+ * to the control channel.
+ *
+ * @param arg The context struct
+ * @param command The command being sent
+ * @param parameters the parameters to the command
+ * @return if sending was successful
+ */
+static bool
+management_callback_send_cc_message(void *arg,
+ const char *command,
+ const char *parameters)
+{
+ struct context *c = (struct context *) arg;
+ size_t len = strlen(command) + 1 + sizeof(parameters) + 1;
+ if (len > PUSH_BUNDLE_SIZE)
+ {
+ return false;
+ }
+
+ struct gc_arena gc = gc_new();
+ struct buffer buf = alloc_buf_gc(len, &gc);
+ ASSERT(buf_printf(&buf, "%s", command));
+ if (parameters)
+ {
+ ASSERT(buf_printf(&buf, ",%s", parameters));
+ }
+ bool status = send_control_channel_string(c, BSTR(&buf), D_PUSH);
+
+ gc_free(&gc);
+ return status;
+}
static bool
management_callback_remote_cmd(void *arg, const char **p)
@@ -3973,6 +4011,7 @@ init_management_callback_p2p(struct context *c)
cb.show_net = management_show_net_callback;
cb.proxy_cmd = management_callback_proxy_cmd;
cb.remote_cmd = management_callback_remote_cmd;
+ cb.send_cc_message = management_callback_send_cc_message;
#ifdef TARGET_ANDROID
cb.network_change = management_callback_network_change;
#endif
@@ -75,6 +75,7 @@ man_help(void)
msg(M_CLIENT, "auth-retry t : Auth failure retry mode (none,interact,nointeract).");
msg(M_CLIENT, "bytecount n : Show bytes in/out, update every n secs (0=off).");
msg(M_CLIENT, "echo [on|off] [N|all] : Like log, but only show messages in echo buffer.");
+ msg(M_CLIENT, "cr-response response : Send a challenge response answer via CR_RESPONSE to server");
msg(M_CLIENT, "exit|quit : Close management session.");
msg(M_CLIENT, "forget-passwords : Forget passwords entered so far.");
msg(M_CLIENT, "help : Print this message.");
@@ -779,6 +780,27 @@ man_net(struct management *man)
}
}
+static void
+man_send_cc_message(struct management *man, const char *message, const char *parameters)
+{
+ if (man->persist.callback.send_cc_message)
+ {
+ const bool status = (*man->persist.callback.send_cc_message)
+ (man->persist.callback.arg, message, parameters);
+ if (status)
+ {
+ msg(M_CLIENT, "SUCCESS: command succeeded");
+ }
+ else
+ {
+ msg(M_CLIENT, "ERROR: command failed");
+ }
+ }
+ else
+ {
+ msg(M_CLIENT, "ERROR: This command is not supported by the current daemon mode");
+ }
+}
#ifdef ENABLE_PKCS11
static void
@@ -1144,7 +1166,15 @@ man_load_stats(struct management *man)
}
#define MN_AT_LEAST (1<<0)
-
+/**
+ * Checks if the correct number of arguments to a management command are present
+ * and otherwise prints an error and returns false.
+ *
+ * @param p pointer to the parameter array
+ * @param n number of arguments required
+ * @param flags if MN_AT_LEAST require at least n parameters and not exactly n
+ * @return Return whether p has n (or at least n) parameters
+ */
static bool
man_need(struct management *man, const char **p, const int n, unsigned int flags)
{
@@ -1460,6 +1490,13 @@ man_dispatch_command(struct management *man, struct status_output *so, const cha
man_query_need_str(man, p[1], p[2]);
}
}
+ else if (streq(p[0], "cr-response"))
+ {
+ if (man_need(man, p, 1, 0))
+ {
+ man_send_cc_message(man, "CR_RESPONSE", p[1]);
+ }
+ }
else if (streq(p[0], "net"))
{
man_net(man);
@@ -164,6 +164,7 @@ struct management_callback
int (*kill_by_addr) (void *arg, const in_addr_t addr, const int port);
void (*delete_event) (void *arg, event_t event);
int (*n_clients) (void *arg);
+ bool (*send_cc_message) (void *arg, const char *message, const char *parameter);
#ifdef MANAGEMENT_DEF_AUTH
bool (*kill_by_cid)(void *arg, const unsigned long cid, const char *kill_msg);
bool (*client_auth) (void *arg,
When a client announces its support to support text based challenge/response via IV_SSO=crtext,the client needs to also be able to reply to that response. This adds the "cr-response" management function to be able to do this. The answer should be base64 encoded. Signed-off-by: Arne Schwabe <arne@rfc2549.org> --- doc/management-notes.txt | 14 ++++++++++++++ src/openvpn/init.c | 39 +++++++++++++++++++++++++++++++++++++++ src/openvpn/manage.c | 39 ++++++++++++++++++++++++++++++++++++++- src/openvpn/manage.h | 1 + 4 files changed, 92 insertions(+), 1 deletion(-)