diff options
author | Nick Mathewson <nickm@torproject.org> | 2015-06-17 11:22:31 -0400 |
---|---|---|
committer | Nick Mathewson <nickm@torproject.org> | 2015-06-25 10:52:47 -0400 |
commit | a64f2d167eab4baefb4fe2471fd2e554a132d37f (patch) | |
tree | 3a81d9dbdc0a62e1bdb49b540ab3dc58f0e4d765 /src | |
parent | b9b658e727520d947e6c14475ee22e8606e9f062 (diff) | |
download | tor-a64f2d167eab4baefb4fe2471fd2e554a132d37f.tar.gz tor-a64f2d167eab4baefb4fe2471fd2e554a132d37f.zip |
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.
Diffstat (limited to 'src')
-rw-r--r-- | src/common/compat.c | 65 |
1 files changed, 64 insertions, 1 deletions
diff --git a/src/common/compat.c b/src/common/compat.c index a931f0a229..4a35183f38 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); |