summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-05-23 19:04:34 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2018-05-23 19:04:34 -0400
commit09fb2d5d3b8f616a81a8b5087e2543143b337c36 (patch)
treea717a9aee9c59b81dd9f0bd4addc8a215f13ed5e
parentd25714d0a344544b4f9d5cee9b83e197e9210cb0 (diff)
Fix simple_prompt() to disable echo on Windows when stdin != terminal.
If echo = false, simple_prompt() is supposed to prevent echoing the input (for password input). However, the Windows implementation applied the mode change to STD_INPUT_HANDLE. That would not have the desired effect if stdin isn't actually the terminal, for instance if the user is piping something into psql. Fix it to apply the mode change to the correct input file, so that passwords do not echo in such cases. In passing, shorten and de-uglify this code by using #elif rather than an #if nest and removing some duplicated code. Back-patch to all supported versions. To simplify that, also back-patch the portions of commit 9daec77e1 that got rid of an unnecessary malloc/free in the same area. Matthew Stickney (cosmetic changes by me) Discussion: https://postgr.es/m/502a1fff-862b-da52-1031-f68df6ed5a2d@gmail.com
-rw-r--r--src/port/sprompt.c48
1 files changed, 19 insertions, 29 deletions
diff --git a/src/port/sprompt.c b/src/port/sprompt.c
index 0e9aca7a7a3..c65a123db02 100644
--- a/src/port/sprompt.c
+++ b/src/port/sprompt.c
@@ -42,14 +42,12 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
FILE *termin,
*termout;
-#ifdef HAVE_TERMIOS_H
+#if defined(HAVE_TERMIOS_H)
struct termios t_orig,
t;
-#else
-#ifdef WIN32
+#elif defined(WIN32)
HANDLE t = NULL;
- LPDWORD t_orig = NULL;
-#endif
+ DWORD t_orig = 0;
#endif
destination = (char *) malloc(maxlen + 1);
@@ -72,8 +70,11 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
*
* XXX fgets() still receives text in the console's input code page. This
* makes non-ASCII credentials unportable.
+ *
+ * Unintuitively, we also open termin in mode "w+", even though we only
+ * read it; that's needed for SetConsoleMode() to succeed.
*/
- termin = fopen("CONIN$", "r");
+ termin = fopen("CONIN$", "w+");
termout = fopen("CONOUT$", "w+");
#else
@@ -105,30 +106,25 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
termout = stderr;
}
-#ifdef HAVE_TERMIOS_H
if (!echo)
{
+#if defined(HAVE_TERMIOS_H)
+ /* disable echo via tcgetattr/tcsetattr */
tcgetattr(fileno(termin), &t);
t_orig = t;
t.c_lflag &= ~ECHO;
tcsetattr(fileno(termin), TCSAFLUSH, &t);
- }
-#else
-#ifdef WIN32
- if (!echo)
- {
- /* get a new handle to turn echo off */
- t_orig = (LPDWORD) malloc(sizeof(DWORD));
- t = GetStdHandle(STD_INPUT_HANDLE);
+#elif defined(WIN32)
+ /* need the file's HANDLE to turn echo off */
+ t = (HANDLE) _get_osfhandle(_fileno(termin));
/* save the old configuration first */
- GetConsoleMode(t, t_orig);
+ GetConsoleMode(t, &t_orig);
/* set to the new mode */
SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
- }
-#endif
#endif
+ }
if (prompt)
{
@@ -158,25 +154,19 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
/* remove trailing newline */
destination[length - 1] = '\0';
-#ifdef HAVE_TERMIOS_H
if (!echo)
{
+ /* restore previous echo behavior, then echo \n */
+#if defined(HAVE_TERMIOS_H)
tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
fputs("\n", termout);
fflush(termout);
- }
-#else
-#ifdef WIN32
- if (!echo)
- {
- /* reset to the original console mode */
- SetConsoleMode(t, *t_orig);
+#elif defined(WIN32)
+ SetConsoleMode(t, t_orig);
fputs("\n", termout);
fflush(termout);
- free(t_orig);
- }
-#endif
#endif
+ }
if (termin != stdin)
{