Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Allow reading stdin on Windows instead of forcibly opening console
This was filed against Ľubomír Carik's github project for openconnect-gui;
openconnect/openconnect-gui#101

It isn't perfect, as the ANSI code page on Windows can be different
from the OEM code page used for the console, so fgetws() is likely
to do the wrong thing — which is why we force-opened the console and
used ReadConsoleW() in the first place. But perfect is the enemy of
good in this case, as reading from something other than stdin is
*definitely* wrong. We still use ReadConsoleW() when stdin does happen
to be the console, so that part shouldn't regress.

I hate Windows...

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
  • Loading branch information
dwmw2 committed Aug 14, 2017
1 parent 0b103e8 commit d298a8b
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 31 deletions.
55 changes: 24 additions & 31 deletions main.c
Expand Up @@ -367,36 +367,37 @@ static char *convert_arg_to_utf8(char **argv, char *arg)
static void read_stdin(char **string, int hidden, int allow_fail)
{
CONSOLE_READCONSOLE_CONTROL rcc = { sizeof(rcc), 0, 13, 0 };
HANDLE conh, stdinh = GetStdHandle(STD_INPUT_HANDLE);
HANDLE stdinh = GetStdHandle(STD_INPUT_HANDLE);
DWORD cmode, nr_read;
wchar_t wbuf[1024];
char *buf;

conh = stdinh;
if (!GetConsoleMode(conh, &cmode)) {
/* STDIN is not a console? Try opening it explicitly */
conh = CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ,
0,OPEN_EXISTING, 0, 0);
if (conh == INVALID_HANDLE_VALUE || !GetConsoleMode(conh, &cmode)) {
if (GetConsoleMode(stdinh, &cmode)) {
if (hidden)
SetConsoleMode(stdinh, cmode & (~ENABLE_ECHO_INPUT));

if (!ReadConsoleW(stdinh, wbuf, sizeof(wbuf)/2, &nr_read, &rcc)) {
char *errstr = openconnect__win32_strerror(GetLastError());
fprintf(stderr, _("Failed to open CONIN$: %s\n"), errstr);
fprintf(stderr, _("ReadConsole() failed: %s\n"), errstr);
free(errstr);
*string = NULL;
goto out;
if (hidden)
SetConsoleMode(stdinh, cmode);
return;
}
if (hidden)
SetConsoleMode(stdinh, cmode);
} else {
/* Not a console; maybe reading from a piped stdin? */
if (!fgetws(wbuf, sizeof(wbuf)/2, stdin)) {
char *errstr = openconnect__win32_strerror(GetLastError());
fprintf(stderr, _("fgetws() failed: %s\n"), errstr);
free(errstr);
*string = NULL;
return;
}
nr_read = wcslen(wbuf);
}
if (hidden) {
SetConsoleMode(conh, cmode & (~ENABLE_ECHO_INPUT));
}

if (!ReadConsoleW(conh, wbuf, sizeof(wbuf)/2, &nr_read, &rcc)) {
char *errstr = openconnect__win32_strerror(GetLastError());
fprintf(stderr, _("ReadConsole() failed: %s\n"), errstr);
free(errstr);
*string = NULL;
goto out;
}

if (nr_read >= 2 && wbuf[nr_read - 1] == 10 && wbuf[nr_read - 2] == 13) {
wbuf[nr_read - 2] = 0;
nr_read -= 2;
Expand All @@ -408,7 +409,7 @@ static void read_stdin(char **string, int hidden, int allow_fail)
fprintf(stderr, _("Error converting console input: %s\n"),
errstr);
free(errstr);
goto out;
return;
}
buf = malloc(nr_read);
if (!buf) {
Expand All @@ -422,18 +423,10 @@ static void read_stdin(char **string, int hidden, int allow_fail)
errstr);
free(errstr);
free(buf);
goto out;
return;
}

*string = buf;

out:
if (hidden) {
SetConsoleMode(conh, cmode);
fprintf(stderr, "\n");
}
if (conh != stdinh && conh != INVALID_HANDLE_VALUE)
CloseHandle(conh);
}

#elif defined(HAVE_ICONV)
Expand Down
1 change: 1 addition & 0 deletions www/changelog.xml
Expand Up @@ -15,6 +15,7 @@
<ul>
<li><b>OpenConnect HEAD</b>
<ul>
<li>Fix <tt>--passwd-on-stdin</tt> for Windows to not forcibly open console.</li>
<li>Fix portability of shell scripts in test suite.</li>
<li>Add Google Authenticator TOTP support for Juniper.</li>
<li>Add RFC7469 key PIN support for cert hashes.</li>
Expand Down

0 comments on commit d298a8b

Please sign in to comment.