getpass.c 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. #include "lib/term/getpass.h"
  6. #include "lib/log/util_bug.h"
  7. #include "lib/malloc/util_malloc.h"
  8. #ifdef _WIN32
  9. #include <windows.h>
  10. #include <conio.h>
  11. #include <wchar.h>
  12. /* Some mingw headers lack these. :p */
  13. #if defined(HAVE_DECL__GETWCH) && !HAVE_DECL__GETWCH
  14. wint_t _getwch(void);
  15. #endif
  16. #ifndef WEOF
  17. #define WEOF (wchar_t)(0xFFFF)
  18. #endif
  19. #if defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY
  20. static inline void
  21. SecureZeroMemory(PVOID ptr, SIZE_T cnt)
  22. {
  23. volatile char *vcptr = (volatile char*)ptr;
  24. while (cnt--)
  25. *vcptr++ = 0;
  26. }
  27. #endif /* defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY */
  28. #elif defined(HAVE_READPASSPHRASE_H)
  29. #include <readpassphrase.h>
  30. #else
  31. #include "tor_readpassphrase.h"
  32. #endif /* defined(_WIN32) || ... */
  33. #include <stdlib.h>
  34. #include <string.h>
  35. /** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
  36. * bytes of passphrase into <b>output</b>. Return the number of bytes in
  37. * the passphrase, excluding terminating NUL.
  38. */
  39. ssize_t
  40. tor_getpass(const char *prompt, char *output, size_t buflen)
  41. {
  42. tor_assert(buflen <= SSIZE_MAX);
  43. tor_assert(buflen >= 1);
  44. #if defined(HAVE_READPASSPHRASE)
  45. char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF);
  46. if (pwd == NULL)
  47. return -1;
  48. return strlen(pwd);
  49. #elif defined(_WIN32)
  50. int r = -1;
  51. while (*prompt) {
  52. _putch(*prompt++);
  53. }
  54. tor_assert(buflen <= INT_MAX);
  55. wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t));
  56. wchar_t *ptr = buf, *lastch = buf + buflen - 1;
  57. while (ptr < lastch) {
  58. wint_t ch = _getwch();
  59. switch (ch) {
  60. case '\r':
  61. case '\n':
  62. case WEOF:
  63. goto done_reading;
  64. case 3:
  65. goto done; /* Can't actually read ctrl-c this way. */
  66. case '\b':
  67. if (ptr > buf)
  68. --ptr;
  69. continue;
  70. case 0:
  71. case 0xe0:
  72. ch = _getwch(); /* Ignore; this is a function or arrow key */
  73. break;
  74. default:
  75. *ptr++ = ch;
  76. break;
  77. }
  78. }
  79. done_reading:
  80. ;
  81. #ifndef WC_ERR_INVALID_CHARS
  82. #define WC_ERR_INVALID_CHARS 0x80
  83. #endif
  84. /* Now convert it to UTF-8 */
  85. r = WideCharToMultiByte(CP_UTF8,
  86. WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS,
  87. buf, (int)(ptr-buf),
  88. output, (int)(buflen-1),
  89. NULL, NULL);
  90. if (r <= 0) {
  91. r = -1;
  92. goto done;
  93. }
  94. tor_assert(r < (int)buflen);
  95. output[r] = 0;
  96. done:
  97. SecureZeroMemory(buf, sizeof(wchar_t)*buflen);
  98. tor_free(buf);
  99. return r;
  100. #else
  101. #error "No implementation for tor_getpass found!"
  102. #endif /* defined(HAVE_READPASSPHRASE) || ... */
  103. }