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.
This commit is contained in:
Nick Mathewson 2015-06-17 11:22:31 -04:00
parent b9b658e727
commit a64f2d167e

View File

@ -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);