commit a64f2d167eab4baefb4fe2471fd2e554a132d37f Author: Nick Mathewson nickm@torproject.org Date: Wed Jun 17 11:22:31 2015 -0400
Add a getpass implementation for windows that won't totally suck
The logic here is inspired by Python's win_getpass(), which I'm assuming is better than nothing. --- src/common/compat.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-)
diff --git a/src/common/compat.c b/src/common/compat.c index a931f0a..4a35183 100644 --- a/src/common/compat.c +++ b/src/common/compat.c @@ -71,6 +71,8 @@ #include <readpassphrase.h> #elif !defined(_WIN32) #include "readpassphrase.h" +#else +#include <conio.h> #endif
#ifndef HAVE_GETTIMEOFDAY @@ -3248,16 +3250,77 @@ tor_sleep_msec(int msec) #endif
/** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b> - * characters of passphrase into <b>output</b>. */ + * bytes of passphrase into <b>output</b>. Return the number of bytes in + * the passphrase, excluding terminating NUL. + */ ssize_t tor_getpass(const char *prompt, char *output, size_t buflen) { tor_assert(buflen <= SSIZE_MAX); + tor_assert(buflen >= 1); #if defined(HAVE_READPASSPHRASE) char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF); if (pwd == NULL) return -1; return strlen(pwd); +#elif defined(_WIN32) + int r = -1; + while (*prompt) { + _putch(*prompt++); + } + + tor_assert(buflen <= INT_MAX); + wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t)); + + wchar_t *ptr = buf, *lastch = buf + buflen - 1; + while (ptr < lastch) { + wint_t ch = _getwch(); + switch (ch) { + case '\r': + case '\n': + case WEOF: + goto done_reading; + case 3: + goto done; /* Can't actually read ctrl-c this way. */ + case '\b': + if (ptr > buf) + --ptr; + continue; + case 0: + case 0xe0: + ch = _getwch(); /* Ignore; this is a function or arrow key */ + break; + default: + *ptr++ = ch; + break; + } + } + done_reading: + ; + +#ifndef WC_ERR_INVALID_CHARS +#define WC_ERR_INVALID_CHARS 0x80 +#endif + + /* Now convert it to UTF-8 */ + r = WideCharToMultiByte(CP_UTF8, + WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS, + buf, (int)(ptr-buf), + output, (int)(buflen-1), + NULL, NULL); + if (r <= 0) { + r = -1; + goto done; + } + + tor_assert(r < (int)buflen); + + output[r] = 0; + + done: + SecureZeroMemory(buf, sizeof(wchar_t)*buflen); + tor_free(buf); + return r; #elif defined(HAVE_GETPASS) /* XXX We shouldn't actually use this; it's deprecated to hell and back */ memset(output, 0, buflen);