Tor  0.4.7.0-alpha-dev
getpass.c
Go to the documentation of this file.
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 }
ssize_t tor_getpass(const char *prompt, char *output, size_t buflen)
Definition: getpass.c:50
Header for getpass.c.
Headers for util_malloc.c.
#define tor_free(p)
Definition: malloc.h:52
Macros to manage assertions, fatal and non-fatal.
#define tor_assert(expr)
Definition: util_bug.h:102