summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNick Mathewson <nickm@torproject.org>2015-06-17 11:22:31 -0400
committerNick Mathewson <nickm@torproject.org>2015-06-25 10:52:47 -0400
commita64f2d167eab4baefb4fe2471fd2e554a132d37f (patch)
tree3a81d9dbdc0a62e1bdb49b540ab3dc58f0e4d765 /src
parentb9b658e727520d947e6c14475ee22e8606e9f062 (diff)
downloadtor-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.c65
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);