[tor-commits] [tor/master] Add a getpass implementation for windows that won't totally suck

nickm at torproject.org nickm at torproject.org
Thu Jun 25 14:53:17 UTC 2015


commit a64f2d167eab4baefb4fe2471fd2e554a132d37f
Author: Nick Mathewson <nickm at 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);





More information about the tor-commits mailing list