aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--init.c14
-rw-r--r--manage.c16
-rw-r--r--management/management-notes.txt36
-rw-r--r--misc.c48
4 files changed, 81 insertions, 33 deletions
diff --git a/init.c b/init.c
index 97d0660..156be8e 100644
--- a/init.c
+++ b/init.c
@@ -122,6 +122,20 @@ context_init_1 (struct context *c)
}
#endif
+#if 0 /* JYFIXME -- test get_user_pass with GET_USER_PASS_NEED_OK flag */
+ {
+ /*
+ * In the management interface, you can okay the request by entering "needok token-insertion-request ok"
+ */
+ struct user_pass up;
+ CLEAR (up);
+ strcpy (up.username, "Please insert your cryptographic token"); /* put the high-level message in up.username */
+ get_user_pass (&up, NULL, "token-insertion-request", GET_USER_PASS_MANAGEMENT|GET_USER_PASS_NEED_OK);
+ msg (M_INFO, "RET:%s", up.password); /* will return the third argument to management interface
+ 'needok' command, usually 'ok' or 'cancel'. */
+ }
+#endif
+
#if P2MP
/* Auth user/pass input */
if (c->options.auth_user_pass_file)
diff --git a/manage.c b/manage.c
index d17d9ce..89e115e 100644
--- a/manage.c
+++ b/manage.c
@@ -74,8 +74,9 @@ man_help ()
msg (M_CLIENT, "log [on|off] [N|all] : Turn on/off realtime log display");
msg (M_CLIENT, " + show last N lines or 'all' for entire history.");
msg (M_CLIENT, "mute [n] : Set log mute level to n, or show level if n is absent.");
+ msg (M_CLIENT, "needok type action : Enter confirmation for NEED-OK request of 'type',");
+ msg (M_CLIENT, " where action = 'ok' or 'cancel'.");
msg (M_CLIENT, "net : (Windows only) Show network info and routing table.");
- msg (M_CLIENT, "ok type : Enter confirmation for NEED-OK request.");
msg (M_CLIENT, "password type p : Enter password p for a queried OpenVPN password.");
msg (M_CLIENT, "signal s : Send signal s to daemon,");
msg (M_CLIENT, " s = SIGHUP|SIGTERM|SIGUSR1|SIGUSR2.");
@@ -527,10 +528,10 @@ man_query_password (struct management *man, const char *type, const char *string
}
static void
-man_query_need_ok (struct management *man, const char *type)
+man_query_need_ok (struct management *man, const char *type, const char *action)
{
const bool needed = ((man->connection.up_query_mode == UP_QUERY_NEED_OK) && man->connection.up_query_type);
- man_query_user_pass (man, type, "ok", needed, "ok-confirmation", man->connection.up_query.password, USER_PASS_LEN);
+ man_query_user_pass (man, type, action, needed, "needok-confirmation", man->connection.up_query.password, USER_PASS_LEN);
}
static void
@@ -721,10 +722,10 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
if (man_need (man, p, 2, 0))
man_query_password (man, p[1], p[2]);
}
- else if (streq (p[0], "ok"))
+ else if (streq (p[0], "needok"))
{
- if (man_need (man, p, 1, 0))
- man_query_need_ok (man, p[1]);
+ if (man_need (man, p, 2, 0))
+ man_query_need_ok (man, p[1], p[2]);
}
else if (streq (p[0], "net"))
{
@@ -1789,6 +1790,9 @@ management_query_user_pass (struct management *man,
type,
alert_type);
+ if (flags & GET_USER_PASS_NEED_OK)
+ buf_printf (&alert_msg, " MSG:%s", up->username);
+
man_wait_for_client_connection (man, &signal_received, 0, MWCC_PASSWORD_WAIT);
if (signal_received)
ret = false;
diff --git a/management/management-notes.txt b/management/management-notes.txt
index 06fc8c1..1dc2913 100644
--- a/management/management-notes.txt
+++ b/management/management-notes.txt
@@ -370,6 +370,28 @@ Command examples:
auth-retry interact -- Don't exit when bad username/passwords are entered.
Query for new input and retry.
+COMMAND -- needok (OpenVPN 2.1 or higher)
+--------------------------------------
+
+Confirm a ">NEED-OK" real-time notification, normally used by
+OpenVPN to block while waiting for a specific user action.
+
+Example:
+
+ OpenVPN needs the user to insert a cryptographic token,
+ so it sends a real-time notification:
+
+ >NEED-OK:Need 'token-insertion-request' confirmation MSG:Please insert your cryptographic token
+
+ The management client, if it is a GUI, can flash a dialog
+ box containing the text after the "MSG:" marker to the user.
+ When the user acknowledges the dialog box,
+ the management client can issue this command:
+
+ needok token-insertion-request ok
+ or
+ needok token-insertion-request cancel
+
OUTPUT FORMAT
-------------
@@ -381,7 +403,7 @@ OUTPUT FORMAT
(3) Real-time messages will be in the form ">[source]:[text]",
where source is "ECHO", "FATAL", "HOLD", "INFO", "LOG",
- "PASSWORD", or "STATE".
+ "NEED-OK", "PASSWORD", or "STATE".
REAL-TIME MESSAGE FORMAT
------------------------
@@ -408,6 +430,10 @@ INFO -- Informational messages such as the welcome message.
LOG -- Log message output as controlled by the "log" command.
+NEED-OK -- OpenVPN needs the end user to do something, such as
+ insert a cryptographic token. The "needok" command can
+ be used to tell OpenVPN to continue.
+
PASSWORD -- Used to tell the management client that OpenVPN
needs a password, also to indicate password
verification failure.
@@ -418,16 +444,16 @@ STATE -- Shows the current OpenVPN state, as controlled
Command Parsing
---------------
-OpenVPN uses the same command line lexical analyzer as is used
-by the OpenVPN config file parser.
+The management interface uses the same command line lexical analyzer
+as is used by the OpenVPN config file parser.
Whitespace is a parameter separator.
Double quotation characters ("") can be used to enclose
-parameters containing whitespace
+parameters containing whitespace.
Backslash-based shell escaping is performed, using the following
-mappings
+mappings:
\\ Maps to a single backslash character (\).
\" Pass a literal doublequote character ("), don't
diff --git a/misc.c b/misc.c
index 4a79ee5..df40ace 100644
--- a/misc.c
+++ b/misc.c
@@ -1178,38 +1178,42 @@ get_user_pass (struct user_pass *up,
else
#endif
/*
+ * Get NEED_OK confirmation from the console
+ */
+ if (flags & GET_USER_PASS_NEED_OK)
+ {
+ struct buffer user_prompt = alloc_buf_gc (128, &gc);
+
+ buf_printf (&user_prompt, "NEED-OK|%s|%s:", prefix, up->username);
+
+ if (!get_console_input (BSTR (&user_prompt), true, up->password, USER_PASS_LEN))
+ msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix);
+
+ if (!strlen (up->password))
+ strcpy (up->password, "ok");
+ }
+
+ /*
* Get username/password from standard input?
*/
- if (from_stdin || (flags & GET_USER_PASS_NEED_OK))
+ else if (from_stdin)
{
struct buffer user_prompt = alloc_buf_gc (128, &gc);
struct buffer pass_prompt = alloc_buf_gc (128, &gc);
- if (flags & GET_USER_PASS_NEED_OK)
- {
- buf_printf (&pass_prompt, "NEED-OK:%s:", prefix);
- }
- else
+ buf_printf (&user_prompt, "Enter %s Username:", prefix);
+ buf_printf (&pass_prompt, "Enter %s Password:", prefix);
+
+ if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
{
- buf_printf (&user_prompt, "Enter %s Username:", prefix);
- buf_printf (&pass_prompt, "Enter %s Password:", prefix);
-
- if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
- {
- if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
- msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
- if (strlen (up->username) == 0)
- msg (M_FATAL, "ERROR: %s username is empty", prefix);
- }
+ if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
+ msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
+ if (strlen (up->username) == 0)
+ msg (M_FATAL, "ERROR: %s username is empty", prefix);
}
if (!get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
- msg (M_FATAL, "ERROR: could not not read %s %s from stdin",
- prefix,
- (flags & GET_USER_PASS_NEED_OK) ? "ok-confirmation" : "password");
-
- if (flags & GET_USER_PASS_NEED_OK)
- strcpy (up->password, "ok");
+ msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);
}
else
{