tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

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 }