Browse code

Rework the user input interface to make it more modular

This is will provide an interface for other mechanisms to be used to
query the user for information, such as usernames, passwords, etc.

It has also been a goal to make it possible to query for all the
information in one call and not do it sequencially as before.

[v5 - Ensure password prompt is only displayed if we should read
from stdin ]

[v4 - add a simple wrapper combining query_user_{init,add,exec}()
- change disapproved &= syntax ]

[v3 - Avoid the dynamic list, use a static list of QUERY_USER_NUMSLOTS
- The list of query_user data is now a global variable
- Replaced query_user_init() with query_user_clear()
- Make query_user_add() a void function
- Rebased against master/600dd9a16fc61 ]

[v2 - Removed the QUERY_USER_FOREACH macro
- Avoided using underscore prefix in function names
- Make query_user_init() do M_FATAL and become a void function
instead of returning false in these unlikely situations ]

Signed-off-by: David Sommerseth <davids@openvpn.net>
Acked-by: Selva Nair <selva.nair@gmail.com>
Message-Id: 1472233732-27074-1-git-send-email-davids@openvpn.net
URL: https://www.mail-archive.com/openvpn-devel@lists.sourceforge.net/msg00137.html

David Sommerseth authored on 2016/08/27 02:48:52
Showing 6 changed files
... ...
@@ -68,7 +68,7 @@ openvpn_SOURCES = \
68 68
 	memdbg.h \
69 69
 	misc.c misc.h \
70 70
 	platform.c platform.h \
71
-	console.c console.h \
71
+	console.c console.h console_builtin.c \
72 72
 	mroute.c mroute.h \
73 73
 	mss.c mss.h \
74 74
 	mstats.c mstats.h \
... ...
@@ -6,6 +6,8 @@
6 6
  *             packet compression.
7 7
  *
8 8
  *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9
+ *  Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
10
+ *  Copyright (C) 2016      David Sommerseth <davids@openvpn.net>
9 11
  *
10 12
  *  This program is free software; you can redistribute it and/or modify
11 13
  *  it under the terms of the GNU General Public License version 2
... ...
@@ -38,219 +40,43 @@
38 38
 #include <systemd/sd-daemon.h>
39 39
 #endif
40 40
 
41
-#ifdef WIN32
42 41
 
43
-#include "win32.h"
42
+struct _query_user query_user[QUERY_USER_NUMSLOTS];  /* GLOBAL */
44 43
 
45
-/*
46
- * Get input from console.
47
- *
48
- * Return false on input error, or if service
49
- * exit event is signaled.
50
- */
51
-
52
-static bool
53
-get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity)
54
-{
55
-  HANDLE in = INVALID_HANDLE_VALUE;
56
-  HANDLE err = INVALID_HANDLE_VALUE;
57
-  DWORD len = 0;
58
-
59
-  ASSERT (prompt);
60
-  ASSERT (input);
61
-  ASSERT (capacity > 0);
62
-
63
-  input[0] = '\0';
64
-
65
-  in = GetStdHandle (STD_INPUT_HANDLE);
66
-  err = get_orig_stderr ();
67
-
68
-  if (in != INVALID_HANDLE_VALUE
69
-      && err != INVALID_HANDLE_VALUE
70
-      && !win32_service_interrupt (&win32_signal)
71
-      && WriteFile (err, prompt, strlen (prompt), &len, NULL))
72
-    {
73
-      bool is_console = (GetFileType (in) == FILE_TYPE_CHAR);
74
-      DWORD flags_save = 0;
75
-      int status = 0;
76
-      WCHAR *winput;
77
-
78
-      if (is_console)
79
-	{
80
-	  if (GetConsoleMode (in, &flags_save))
81
-	    {
82
-	      DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
83
-	      if (echo)
84
-		flags |= ENABLE_ECHO_INPUT;
85
-	      SetConsoleMode (in, flags);
86
-	    }
87
-	  else
88
-	    is_console = 0;
89
-	}
90
-
91
-      if (is_console)
92
-        {
93
-          winput = malloc (capacity * sizeof (WCHAR));
94
-          if (winput == NULL)
95
-            return false;
96
-
97
-          status = ReadConsoleW (in, winput, capacity, &len, NULL);
98
-          WideCharToMultiByte (CP_UTF8, 0, winput, len, input, capacity, NULL, NULL);
99
-          free (winput);
100
-        }
101
-      else
102
-        status = ReadFile (in, input, capacity, &len, NULL);
103
-
104
-      string_null_terminate (input, (int)len, capacity);
105
-      chomp (input);
106
-
107
-      if (!echo)
108
-	WriteFile (err, "\r\n", 2, &len, NULL);
109
-      if (is_console)
110
-	SetConsoleMode (in, flags_save);
111
-      if (status && !win32_service_interrupt (&win32_signal))
112
-	return true;
113
-    }
114
-
115
-  return false;
116
-}
117
-
118
-#endif
119
-
120
-#ifdef HAVE_GETPASS
121
-
122
-static FILE *
123
-open_tty (const bool write)
124
-{
125
-  FILE *ret;
126
-  ret = fopen ("/dev/tty", write ? "w" : "r");
127
-  if (!ret)
128
-    ret = write ? stderr : stdin;
129
-  return ret;
130
-}
131
-
132
-static void
133
-close_tty (FILE *fp)
134
-{
135
-  if (fp != stderr && fp != stdin)
136
-    fclose (fp);
137
-}
138
-
139
-#endif
140 44
 
141
-#ifdef ENABLE_SYSTEMD
142
-
143
-/*
144
- * is systemd running
145
- */
146
-
147
-static bool
148
-check_systemd_running ()
45
+void query_user_clear()
149 46
 {
150
-  struct stat c;
151
-
152
-  /* We simply test whether the systemd cgroup hierarchy is
153
-   * mounted, as well as the systemd-ask-password executable
154
-   * being available */
47
+    int i;
155 48
 
156
-  return (sd_booted() > 0)
157
-	  && (stat(SYSTEMD_ASK_PASSWORD_PATH, &c) == 0);
158
-
159
-}
160
-
161
-static bool
162
-get_console_input_systemd (const char *prompt, const bool echo, char *input, const int capacity)
163
-{
164
-  int std_out;
165
-  bool ret = false;
166
-  struct argv argv;
167
-
168
-  argv_init (&argv);
169
-  argv_printf (&argv, SYSTEMD_ASK_PASSWORD_PATH);
170
-  argv_printf_cat (&argv, "%s", prompt);
171
-
172
-  if ((std_out = openvpn_popen (&argv, NULL)) < 0) {
173
-	  return false;
174
-  }
175
-
176
-  memset (input, 0, capacity);
177
-  if (read (std_out, input, capacity-1) > 0)
178
-    {
179
-       chomp (input);
180
-       ret = true;
49
+    for( i = 0; i < QUERY_USER_NUMSLOTS; i++ ) {
50
+	CLEAR(query_user[i]);
181 51
     }
182
-  close (std_out);
183
-
184
-  argv_reset (&argv);
185
-
186
-  return ret;
187 52
 }
188 53
 
189 54
 
190
-#endif
191
-
192
-/*
193
- * Get input from console
194
- */
195
-bool
196
-get_console_input (const char *prompt, const bool echo, char *input, const int capacity)
55
+void query_user_add(char *prompt, size_t prompt_len,
56
+                    char *resp, size_t resp_len,
57
+                    bool echo)
197 58
 {
198
-  bool ret = false;
199
-  ASSERT (prompt);
200
-  ASSERT (input);
201
-  ASSERT (capacity > 0);
202
-  input[0] = '\0';
203
-
204
-#ifdef ENABLE_SYSTEMD
205
-  if (check_systemd_running ())
206
-    return get_console_input_systemd (prompt, echo, input, capacity);
207
-#endif
59
+    int i;
208 60
 
209
-#if defined(WIN32)
210
-  return get_console_input_win32 (prompt, echo, input, capacity);
211
-#elif defined(HAVE_GETPASS)
61
+    /* Ensure input is sane.  All these must be present otherwise it is
62
+     * a programming error.
63
+     */
64
+    ASSERT( prompt_len > 0 && prompt != NULL && resp_len > 0 && resp != NULL );
212 65
 
213
-  /* did we --daemon'ize before asking for passwords?
214
-   * (in which case neither stdin or stderr are connected to a tty and
215
-   * /dev/tty can not be open()ed anymore)
216
-   */
217
-  if ( !isatty(0) && !isatty(2) )
218
-    {
219
-      int fd = open( "/dev/tty", O_RDWR );
220
-      if ( fd < 0 )
221
-	{ msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a controlling tty nor systemd - can't ask for '%s'.  If you used --daemon, you need to use --askpass to make passphrase-protected keys work, and you can not use --auth-nocache.", prompt ); }
222
-      close(fd);
223
-    }
224
-
225
-  if (echo)
226
-    {
227
-      FILE *fp;
228
-
229
-      fp = open_tty (true);
230
-      fprintf (fp, "%s", prompt);
231
-      fflush (fp);
232
-      close_tty (fp);
233
-
234
-      fp = open_tty (false);
235
-      if (fgets (input, capacity, fp) != NULL)
236
-	{
237
-	  chomp (input);
238
-	  ret = true;
66
+    /* Seek to the last unused slot */
67
+    for (i = 0; i < QUERY_USER_NUMSLOTS; i++) {
68
+	if( query_user[i].prompt == NULL ) {
69
+	    break;
239 70
 	}
240
-      close_tty (fp);
241 71
     }
242
-  else
243
-    {
244
-      char *gp = getpass (prompt);
245
-      if (gp)
246
-	{
247
-	  strncpynt (input, gp, capacity);
248
-	  memset (gp, 0, strlen (gp));
249
-	  ret = true;
250
-	}
251
-    }
252
-#else
253
-  msg (M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt);
254
-#endif
255
-  return ret;
72
+    ASSERT( i < QUERY_USER_NUMSLOTS );  /* Unlikely, but we want to panic if it happens */
73
+
74
+    /* Save the information needed for the user interaction */
75
+    query_user[i].prompt = prompt;
76
+    query_user[i].prompt_len = prompt_len;
77
+    query_user[i].response = resp;
78
+    query_user[i].response_len = resp_len;
79
+    query_user[i].echo = echo;
256 80
 }
... ...
@@ -6,6 +6,8 @@
6 6
  *             packet compression.
7 7
  *
8 8
  *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9
+ *  Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
10
+ *  Copyright (C) 2016      David Sommerseth <davids@openvpn.net>
9 11
  *
10 12
  *  This program is free software; you can redistribute it and/or modify
11 13
  *  it under the terms of the GNU General Public License version 2
... ...
@@ -27,7 +29,90 @@
27 27
 
28 28
 #include "basic.h"
29 29
 
30
-bool
31
-get_console_input (const char *prompt, const bool echo, char *input, const int capacity);
30
+/**
31
+ *  Configuration setup for declaring what kind of information to ask a user for
32
+ */
33
+struct _query_user {
34
+    char *prompt;             /**< Prompt to present to the user */
35
+    size_t prompt_len;        /**< Lenght of the prompt string */
36
+    char *response;           /**< The user's response */
37
+    size_t response_len;      /**< Lenght the of the user reposone */
38
+    bool echo;                /**< True: The user should see what is being typed, otherwise mask it */
39
+};
40
+
41
+#define QUERY_USER_NUMSLOTS 10
42
+extern struct _query_user query_user[];  /**< Global variable, declared in console.c */
43
+
44
+/**
45
+ * Wipes all data put into all of the query_user structs
46
+ *
47
+ */
48
+void query_user_clear ();
49
+
50
+
51
+/**
52
+ * Adds an item to ask the user for
53
+ *
54
+ * @param prompt     Prompt to display to the user
55
+ * @param prompt_len Length of the prompt string
56
+ * @param resp       String containing the user response
57
+ * @param resp_len   Lenght of the response string
58
+ * @param echo       Should the user input be echoed to the user?  If False, input will be masked
59
+ *
60
+ */
61
+void query_user_add (char *prompt, size_t prompt_len,
62
+                     char *resp, size_t resp_len,
63
+                     bool echo);
64
+
65
+
66
+/**
67
+ * Executes a configured setup, using the built-in method for querying the user.
68
+ * This method uses the console/TTY directly.
69
+ *
70
+ * @param setup    Pointer to the setup defining what to ask the user
71
+ *
72
+ * @return True if executing all the defined steps completed successfully
73
+ */
74
+bool query_user_exec_builtin ();
75
+
76
+
77
+#ifdef QUERY_USER_EXEC_ALTERNATIVE
78
+/**
79
+ * Executes a configured setup, using the compiled method for querying the user
80
+ *
81
+ * @param setup    Pointer to the setup defining what to ask the user
82
+ *
83
+ * @return True if executing all the defined steps completed successfully
84
+ */
85
+bool query_user_exec ();
86
+
87
+#else  /* QUERY_USER_EXEC_ALTERNATIVE not defined*/
88
+/**
89
+ * Wrapper function enabling query_user_exec() if no alternative methods have
90
+ * been enabled
91
+ *
92
+ */
93
+static bool query_user_exec ()
94
+{
95
+    return query_user_exec_builtin();
96
+}
97
+#endif  /* QUERY_USER_EXEC_ALTERNATIVE */
98
+
99
+
100
+/**
101
+ * A plain "make Gert happy" wrapper.  Same arguments as @query_user_add
102
+ *
103
+ * FIXME/TODO: Remove this when refactoring the complete user query process
104
+ *             to be called at start-up initialization of OpenVPN.
105
+ *
106
+ */
107
+static bool query_user_SINGLE (char *prompt, size_t prompt_len,
108
+                     char *resp, size_t resp_len,
109
+                     bool echo)
110
+{
111
+    query_user_clear();
112
+    query_user_add(prompt, prompt_len, resp, resp_len, echo);
113
+    return query_user_exec();
114
+}
32 115
 
33 116
 #endif
34 117
new file mode 100644
... ...
@@ -0,0 +1,261 @@
0
+/*
1
+ *  OpenVPN -- An application to securely tunnel IP networks
2
+ *             over a single UDP port, with support for SSL/TLS-based
3
+ *             session authentication and key exchange,
4
+ *             packet encryption, packet authentication, and
5
+ *             packet compression.
6
+ *
7
+ *  Copyright (C) 2002-2016  OpenVPN Technologies, Inc. <sales@openvpn.net>
8
+ *  Copyright (C) 2014-2015  David Sommerseth <davids@redhat.com>
9
+ *  Copyright (C) 2016       David Sommerseth <davids@openvpn.net>
10
+ *
11
+ *  This program is free software; you can redistribute it and/or modify
12
+ *  it under the terms of the GNU General Public License version 2
13
+ *  as published by the Free Software Foundation.
14
+ *
15
+ *  This program is distributed in the hope that it will be useful,
16
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
17
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
+ *  GNU General Public License for more details.
19
+ *
20
+ *  You should have received a copy of the GNU General Public License
21
+ *  along with this program (see the file COPYING included with this
22
+ *  distribution); if not, write to the Free Software Foundation, Inc.,
23
+ *  59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24
+ */
25
+
26
+/*
27
+ *  These functions covers handing user input/output using the default consoles
28
+ *
29
+ */
30
+
31
+#ifdef HAVE_CONFIG_H
32
+#include "config.h"
33
+#elif defined(_MSC_VER)
34
+#include "config-msvc.h"
35
+#endif
36
+
37
+#include "syshead.h"
38
+#include "console.h"
39
+#include "error.h"
40
+#include "buffer.h"
41
+#include "misc.h"
42
+
43
+#ifdef WIN32
44
+
45
+#include "win32.h"
46
+
47
+/**
48
+ * Get input from a Windows console.
49
+ *
50
+ * @param prompt    Prompt to display to the user
51
+ * @param echo      Should the user input be displayed in the console
52
+ * @param input     Pointer to the buffer the user input will be saved
53
+ * @param capacity  Size of the buffer for the user input
54
+ *
55
+ * @return Return false on input error, or if service
56
+ *         exit event is signaled.
57
+ */
58
+static bool get_console_input_win32 (const char *prompt, const bool echo, char *input, const int capacity)
59
+{
60
+    HANDLE in = INVALID_HANDLE_VALUE;
61
+    HANDLE err = INVALID_HANDLE_VALUE;
62
+    DWORD len = 0;
63
+
64
+    ASSERT (prompt);
65
+    ASSERT (input);
66
+    ASSERT (capacity > 0);
67
+
68
+    input[0] = '\0';
69
+
70
+    in = GetStdHandle (STD_INPUT_HANDLE);
71
+    err = get_orig_stderr ();
72
+
73
+    if (in != INVALID_HANDLE_VALUE
74
+        && err != INVALID_HANDLE_VALUE
75
+        && !win32_service_interrupt (&win32_signal)
76
+        && WriteFile (err, prompt, strlen (prompt), &len, NULL))
77
+    {
78
+        bool is_console = (GetFileType (in) == FILE_TYPE_CHAR);
79
+        DWORD flags_save = 0;
80
+        int status = 0;
81
+        WCHAR *winput;
82
+
83
+        if (is_console)
84
+	{
85
+            if (GetConsoleMode (in, &flags_save))
86
+	    {
87
+                DWORD flags = ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT;
88
+                if (echo)
89
+                    flags |= ENABLE_ECHO_INPUT;
90
+                SetConsoleMode (in, flags);
91
+	    } else
92
+                is_console = 0;
93
+	}
94
+
95
+        if (is_console)
96
+        {
97
+            winput = malloc (capacity * sizeof (WCHAR));
98
+            if (winput == NULL)
99
+                return false;
100
+
101
+            status = ReadConsoleW (in, winput, capacity, &len, NULL);
102
+            WideCharToMultiByte (CP_UTF8, 0, winput, len, input, capacity, NULL, NULL);
103
+            free (winput);
104
+        } else
105
+            status = ReadFile (in, input, capacity, &len, NULL);
106
+
107
+        string_null_terminate (input, (int)len, capacity);
108
+        chomp (input);
109
+
110
+        if (!echo)
111
+            WriteFile (err, "\r\n", 2, &len, NULL);
112
+        if (is_console)
113
+            SetConsoleMode (in, flags_save);
114
+        if (status && !win32_service_interrupt (&win32_signal))
115
+            return true;
116
+    }
117
+
118
+    return false;
119
+}
120
+
121
+#endif   /* WIN32 */
122
+
123
+
124
+#ifdef HAVE_GETPASS
125
+
126
+/**
127
+ * Open the current console TTY for read/write operations
128
+ *
129
+ * @params write   If true, the user wants to write to the console
130
+ *                 otherwise read from the console
131
+ *
132
+ * @returns Returns a FILE pointer to either the TTY in read or write mode
133
+ *          or stdin/stderr, depending on the write flag
134
+ *
135
+ */
136
+static FILE * open_tty (const bool write)
137
+{
138
+    FILE *ret;
139
+    ret = fopen ("/dev/tty", write ? "w" : "r");
140
+    if (!ret)
141
+        ret = write ? stderr : stdin;
142
+    return ret;
143
+}
144
+
145
+/**
146
+ * Closes the TTY FILE pointer, but only if it is not a stdin/stderr FILE object.
147
+ *
148
+ * @params fp     FILE pointer to close
149
+ *
150
+ */
151
+static void close_tty (FILE *fp)
152
+{
153
+    if (fp != stderr && fp != stdin)
154
+        fclose (fp);
155
+}
156
+
157
+#endif   /* HAVE_GETPASS */
158
+
159
+
160
+/**
161
+ *  Core function for getting input from console
162
+ *
163
+ *  @params prompt    The prompt to present to the user
164
+ *  @params echo      Should the user see what is being typed
165
+ *  @params input     Pointer to the buffer used to save the user input
166
+ *  @params capacity  Size of the input buffer
167
+ *
168
+ *  @returns Returns True if user input was gathered
169
+ */
170
+static bool get_console_input (const char *prompt, const bool echo, char *input, const int capacity)
171
+{
172
+    bool ret = false;
173
+    ASSERT (prompt);
174
+    ASSERT (input);
175
+    ASSERT (capacity > 0);
176
+    input[0] = '\0';
177
+
178
+#if defined(WIN32)
179
+    return get_console_input_win32 (prompt, echo, input, capacity);
180
+#elif defined(HAVE_GETPASS)
181
+
182
+    /* did we --daemon'ize before asking for passwords?
183
+     * (in which case neither stdin or stderr are connected to a tty and
184
+     * /dev/tty can not be open()ed anymore)
185
+     */
186
+    if ( !isatty(0) && !isatty(2) )
187
+    {
188
+        int fd = open( "/dev/tty", O_RDWR );
189
+        if ( fd < 0 )
190
+        {
191
+            msg(M_FATAL, "neither stdin nor stderr are a tty device and you have neither a "
192
+                "controlling tty nor systemd - can't ask for '%s'.  If you used --daemon, "
193
+                "you need to use --askpass to make passphrase-protected keys work, and you "
194
+                "can not use --auth-nocache.", prompt );
195
+        }
196
+        close(fd);
197
+    }
198
+
199
+    if (echo)
200
+    {
201
+        FILE *fp;
202
+
203
+        fp = open_tty (true);
204
+        fprintf (fp, "%s", prompt);
205
+        fflush (fp);
206
+        close_tty (fp);
207
+
208
+        fp = open_tty (false);
209
+        if (fgets (input, capacity, fp) != NULL)
210
+        {
211
+            chomp (input);
212
+            ret = true;
213
+        }
214
+        close_tty (fp);
215
+    } else {
216
+        char *gp = getpass (prompt);
217
+        if (gp)
218
+        {
219
+            strncpynt (input, gp, capacity);
220
+            memset (gp, 0, strlen (gp));
221
+            ret = true;
222
+        }
223
+    }
224
+#else
225
+    msg (M_FATAL, "Sorry, but I can't get console input on this OS (%s)", prompt);
226
+#endif
227
+    return ret;
228
+}
229
+
230
+
231
+/**
232
+ * @copydoc query_user_exec()
233
+ *
234
+ * Default method for querying user using default stdin/stdout on a console.
235
+ * This needs to be available as a backup interface for the alternative
236
+ * implementations in case they cannot query through their implementation
237
+ * specific methods.
238
+ *
239
+ * If no alternative implementation is declared, a wrapper in console.h will ensure
240
+ * query_user_exec() will call this function instead.
241
+ *
242
+ */
243
+bool query_user_exec_builtin()
244
+{
245
+    bool ret = true; /* Presume everything goes okay */
246
+    int i;
247
+
248
+    /* Loop through configured query_user slots */
249
+    for (i = 0; i < QUERY_USER_NUMSLOTS && query_user[i].response != NULL; i++)
250
+    {
251
+	if (!get_console_input(query_user[i].prompt, query_user[i].echo,
252
+			      query_user[i].response, query_user[i].response_len) )
253
+	{
254
+	    /* Force the final result state to failed on failure */
255
+	    ret = false;
256
+	}
257
+    }
258
+
259
+    return ret;
260
+}
... ...
@@ -6,6 +6,8 @@
6 6
  *             packet compression.
7 7
  *
8 8
  *  Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
9
+ *  Copyright (C) 2014-2015 David Sommerseth <davids@redhat.com>
10
+ *  Copyright (C) 2016      David Sommerseth <davids@openvpn.net>
9 11
  *
10 12
  *  This program is free software; you can redistribute it and/or modify
11 13
  *  it under the terms of the GNU General Public License version 2
... ...
@@ -1085,9 +1087,11 @@ get_user_pass_cr (struct user_pass *up,
1085 1085
 	  struct buffer user_prompt = alloc_buf_gc (128, &gc);
1086 1086
 
1087 1087
 	  buf_printf (&user_prompt, "NEED-OK|%s|%s:", prefix, up->username);
1088
-	  
1089
-	  if (!get_console_input (BSTR (&user_prompt), true, up->password, USER_PASS_LEN))
1090
-	    msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix);
1088
+	  if (!query_user_SINGLE (BSTR(&user_prompt), BLEN(&user_prompt),
1089
+                                  up->password, USER_PASS_LEN, false))
1090
+            {
1091
+              msg (M_FATAL, "ERROR: could not read %s ok-confirmation from stdin", prefix);
1092
+            }
1091 1093
 	  
1092 1094
 	  if (!strlen (up->password))
1093 1095
 	    strcpy (up->password, "ok");
... ...
@@ -1163,13 +1167,17 @@ get_user_pass_cr (struct user_pass *up,
1163 1163
 	      if (ac)
1164 1164
 		{
1165 1165
 		  char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc);
1166
-		  struct buffer packed_resp;
1166
+		  struct buffer packed_resp, challenge;
1167 1167
 
1168
+		  challenge = alloc_buf_gc (14+strlen(ac->challenge_text), &gc);
1169
+		  buf_printf (&challenge, "CHALLENGE: %s", ac->challenge_text);
1168 1170
 		  buf_set_write (&packed_resp, (uint8_t*)up->password, USER_PASS_LEN);
1169
-		  msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", ac->challenge_text);
1170
-                  if (!get_console_input (ac->challenge_text, BOOL_CAST(ac->flags&CR_ECHO),
1171
-                                          response, USER_PASS_LEN))
1172
-		    msg (M_FATAL, "ERROR: could not read challenge response from stdin");
1171
+
1172
+		  if (!query_user_SINGLE (BSTR(&challenge), BLEN(&challenge),
1173
+                                          response, USER_PASS_LEN, BOOL_CAST(ac->flags&CR_ECHO)))
1174
+		    {
1175
+		      msg (M_FATAL, "ERROR: could not read challenge response from stdin");
1176
+		    }
1173 1177
 		  strncpynt (up->username, ac->user, USER_PASS_LEN);
1174 1178
 		  buf_printf (&packed_resp, "CRV1::%s::%s", ac->state_id, response);
1175 1179
 		}
... ...
@@ -1184,32 +1192,49 @@ get_user_pass_cr (struct user_pass *up,
1184 1184
 	      struct buffer user_prompt = alloc_buf_gc (128, &gc);
1185 1185
 	      struct buffer pass_prompt = alloc_buf_gc (128, &gc);
1186 1186
 
1187
+	      query_user_clear ();
1187 1188
 	      buf_printf (&user_prompt, "Enter %s Username:", prefix);
1188 1189
 	      buf_printf (&pass_prompt, "Enter %s Password:", prefix);
1189 1190
 
1190 1191
 	      if (username_from_stdin && !(flags & GET_USER_PASS_PASSWORD_ONLY))
1191 1192
 		{
1192
-		  if (!get_console_input (BSTR (&user_prompt), true, up->username, USER_PASS_LEN))
1193
-		    msg (M_FATAL, "ERROR: could not read %s username from stdin", prefix);
1193
+		  query_user_add (BSTR(&user_prompt), BLEN(&user_prompt),
1194
+                                  up->username, USER_PASS_LEN, true);
1195
+		}
1196
+
1197
+	      if (password_from_stdin)
1198
+                {
1199
+                  query_user_add (BSTR(&pass_prompt), BLEN(&pass_prompt),
1200
+                                  up->password, USER_PASS_LEN, false);
1201
+                }
1202
+
1203
+	      if( !query_user_exec () )
1204
+		{
1205
+		  msg(M_FATAL, "ERROR: Failed retrieving username or password");
1206
+		}
1207
+
1208
+	      if (!(flags & GET_USER_PASS_PASSWORD_ONLY))
1209
+		{
1194 1210
 		  if (strlen (up->username) == 0)
1195 1211
 		    msg (M_FATAL, "ERROR: %s username is empty", prefix);
1196 1212
 		}
1197 1213
 
1198
-	      if (password_from_stdin && !get_console_input (BSTR (&pass_prompt), false, up->password, USER_PASS_LEN))
1199
-		msg (M_FATAL, "ERROR: could not not read %s password from stdin", prefix);
1200
-
1201 1214
 #ifdef ENABLE_CLIENT_CR
1202 1215
               if (auth_challenge && (flags & GET_USER_PASS_STATIC_CHALLENGE) && response_from_stdin)
1203 1216
 		{
1204 1217
 		  char *response = (char *) gc_malloc (USER_PASS_LEN, false, &gc);
1205
-		  struct buffer packed_resp;
1218
+		  struct buffer packed_resp, challenge;
1206 1219
 		  char *pw64=NULL, *resp64=NULL;
1207 1220
 
1208
-		  msg (M_INFO|M_NOPREFIX, "CHALLENGE: %s", auth_challenge);
1221
+		  challenge = alloc_buf_gc (14+strlen(auth_challenge), &gc);
1222
+		  buf_printf (&challenge, "CHALLENGE: %s", auth_challenge);
1209 1223
 
1210
-                  if (!get_console_input (auth_challenge, BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO),
1211
-                                          response, USER_PASS_LEN))
1212
-		    msg (M_FATAL, "ERROR: could not read static challenge response from stdin");
1224
+		  if (!query_user_SINGLE (BSTR(&challenge), BLEN(&challenge),
1225
+                                          response, USER_PASS_LEN,
1226
+                                          BOOL_CAST(flags & GET_USER_PASS_STATIC_CHALLENGE_ECHO)))
1227
+		    {
1228
+		      msg (M_FATAL, "ERROR: could not retrieve static challenge response");
1229
+		    }
1213 1230
 		  if (openvpn_base64_encode(up->password, strlen(up->password), &pw64) == -1
1214 1231
 		      || openvpn_base64_encode(response, strlen(response), &resp64) == -1)
1215 1232
 		    msg (M_FATAL, "ERROR: could not base64-encode password/static_response");
... ...
@@ -744,9 +744,10 @@ _pkcs11_openvpn_show_pkcs11_ids_pin_prompt (
744 744
 	ASSERT (token!=NULL);
745 745
 
746 746
 	buf_printf (&pass_prompt, "Please enter '%s' token PIN or 'cancel': ", token->display);
747
-
748
-	if (!get_console_input (BSTR (&pass_prompt), false, pin, pin_max)) {
749
-		msg (M_FATAL, "Cannot read password from stdin");
747
+	if (!query_user_SINGLE(BSTR(&pass_prompt), BLEN(&pass_prompt),
748
+		       pin, pin_max, false))
749
+	{
750
+	    msg (M_FATAL, "Could not retrieve the PIN");
750 751
 	}
751 752
 
752 753
 	gc_free (&gc);