Line data Source code
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 */ 5 : 6 : /** 7 : * \file getpass.c 8 : * \brief Cross-platform wrapper to read passphrases from the terminal. 9 : **/ 10 : 11 : #include "lib/term/getpass.h" 12 : 13 : #include "lib/log/util_bug.h" 14 : #include "lib/malloc/malloc.h" 15 : 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) 30 : { 31 : volatile char *vcptr = (volatile char*)ptr; 32 : while (cnt--) 33 : *vcptr++ = 0; 34 : } 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) || ... */ 41 : 42 : #include <stdlib.h> 43 : #include <string.h> 44 : 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. 48 : */ 49 : ssize_t 50 0 : tor_getpass(const char *prompt, char *output, size_t buflen) 51 : { 52 0 : tor_assert(buflen <= SSIZE_MAX); 53 0 : tor_assert(buflen >= 1); 54 : #if defined(HAVE_READPASSPHRASE) 55 0 : char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF); 56 0 : if (pwd == NULL) 57 : return -1; 58 0 : return strlen(pwd); 59 : #elif defined(_WIN32) 60 : int r = -1; 61 : while (*prompt) { 62 : _putch(*prompt++); 63 : } 64 : 65 : tor_assert(buflen <= INT_MAX); 66 : wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t)); 67 : 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; 89 : } 90 : } 91 : done_reading: 92 : ; 93 : 94 : #ifndef WC_ERR_INVALID_CHARS 95 : #define WC_ERR_INVALID_CHARS 0x80 96 : #endif 97 : 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; 107 : } 108 : 109 : tor_assert(r < (int)buflen); 110 : 111 : output[r] = 0; 112 : 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) || ... */ 120 : }