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