From dd1047f52119bbe78bd0f2c9452c9965c4bdf0dc Mon Sep 17 00:00:00 2001 From: james Date: Thu, 20 Oct 2005 10:16:41 +0000 Subject: [PATCH] Some changes to GET_USER_PASS_NEED_OK flag to get_user_pass. (1) Allow an additional longer prompt string to be passed to the management interface client, in addition to the request type string. (2) Allow the management interface client to return a string, usually "ok" or "cancel" as the third argument to "needok" command. (3) Renamed "ok" command in management interface to "needok". (4) Edited management-notes.txt to reflect new needok feature. (5) See init.c:125 for new code example. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@694 e7ae566f-a301-0410-adde-c780ea21d3b5 --- init.c | 14 ++++++++++ manage.c | 16 ++++++----- management/management-notes.txt | 36 +++++++++++++++++++++---- misc.c | 48 ++++++++++++++++++--------------- 4 files changed, 81 insertions(+), 33 deletions(-) diff --git a/init.c b/init.c index 97d06608..156be8e1 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 d17d9ce7..89e115e9 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 06fc8c16..1dc29134 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 4a79ee5d..df40ace3 100644 --- a/misc.c +++ b/misc.c @@ -1177,39 +1177,43 @@ 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); + 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 (!(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 (&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 {