getpass.c 2.9 KB

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