getpass.c (2963B)
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 tor_getpass(const char *prompt, char *output, size_t buflen) 51 { 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++); 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 }