Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit bbaf75e

Browse files
committed
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 9daec77 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
1 parent 588edd8 commit bbaf75e

File tree

1 file changed

+19
-29
lines changed

1 file changed

+19
-29
lines changed

src/port/sprompt.c

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -42,14 +42,12 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
4242
FILE *termin,
4343
*termout;
4444

45-
#ifdef HAVE_TERMIOS_H
45+
#if defined(HAVE_TERMIOS_H)
4646
struct termios t_orig,
4747
t;
48-
#else
49-
#ifdef WIN32
48+
#elif defined(WIN32)
5049
HANDLE t = NULL;
51-
LPDWORD t_orig = NULL;
52-
#endif
50+
DWORD t_orig = 0;
5351
#endif
5452

5553
destination = (char *) malloc(maxlen + 1);
@@ -72,8 +70,11 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
7270
*
7371
* XXX fgets() still receives text in the console's input code page. This
7472
* makes non-ASCII credentials unportable.
73+
*
74+
* Unintuitively, we also open termin in mode "w+", even though we only
75+
* read it; that's needed for SetConsoleMode() to succeed.
7576
*/
76-
termin = fopen("CONIN$", "r");
77+
termin = fopen("CONIN$", "w+");
7778
termout = fopen("CONOUT$", "w+");
7879
#else
7980

@@ -105,30 +106,25 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
105106
termout = stderr;
106107
}
107108

108-
#ifdef HAVE_TERMIOS_H
109109
if (!echo)
110110
{
111+
#if defined(HAVE_TERMIOS_H)
112+
/* disable echo via tcgetattr/tcsetattr */
111113
tcgetattr(fileno(termin), &t);
112114
t_orig = t;
113115
t.c_lflag &= ~ECHO;
114116
tcsetattr(fileno(termin), TCSAFLUSH, &t);
115-
}
116-
#else
117-
#ifdef WIN32
118-
if (!echo)
119-
{
120-
/* get a new handle to turn echo off */
121-
t_orig = (LPDWORD) malloc(sizeof(DWORD));
122-
t = GetStdHandle(STD_INPUT_HANDLE);
117+
#elif defined(WIN32)
118+
/* need the file's HANDLE to turn echo off */
119+
t = (HANDLE) _get_osfhandle(_fileno(termin));
123120

124121
/* save the old configuration first */
125-
GetConsoleMode(t, t_orig);
122+
GetConsoleMode(t, &t_orig);
126123

127124
/* set to the new mode */
128125
SetConsoleMode(t, ENABLE_LINE_INPUT | ENABLE_PROCESSED_INPUT);
129-
}
130-
#endif
131126
#endif
127+
}
132128

133129
if (prompt)
134130
{
@@ -158,25 +154,19 @@ simple_prompt(const char *prompt, int maxlen, bool echo)
158154
/* remove trailing newline */
159155
destination[length - 1] = '\0';
160156

161-
#ifdef HAVE_TERMIOS_H
162157
if (!echo)
163158
{
159+
/* restore previous echo behavior, then echo \n */
160+
#if defined(HAVE_TERMIOS_H)
164161
tcsetattr(fileno(termin), TCSAFLUSH, &t_orig);
165162
fputs("\n", termout);
166163
fflush(termout);
167-
}
168-
#else
169-
#ifdef WIN32
170-
if (!echo)
171-
{
172-
/* reset to the original console mode */
173-
SetConsoleMode(t, *t_orig);
164+
#elif defined(WIN32)
165+
SetConsoleMode(t, t_orig);
174166
fputs("\n", termout);
175167
fflush(termout);
176-
free(t_orig);
177-
}
178-
#endif
179168
#endif
169+
}
180170

181171
if (termin != stdin)
182172
{

0 commit comments

Comments
 (0)