compat.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. /**
  6. * \file compat.c
  7. * \brief Wrappers to make calls more portable. This code defines
  8. * functions such as tor_snprintf, get/set various data types,
  9. * renaming, setting socket options, switching user IDs. It is basically
  10. * where the non-portable items are conditionally included depending on
  11. * the platform.
  12. **/
  13. #define COMPAT_PRIVATE
  14. #include "common/compat.h"
  15. #ifdef _WIN32
  16. #include <winsock2.h>
  17. #include <windows.h>
  18. #include <sys/locking.h>
  19. #endif
  20. #ifdef HAVE_UNAME
  21. #include <sys/utsname.h>
  22. #endif
  23. #ifdef HAVE_SYS_TYPES_H
  24. #include <sys/types.h>
  25. #endif
  26. #ifdef HAVE_SYS_SYSCTL_H
  27. #include <sys/sysctl.h>
  28. #endif
  29. #ifdef HAVE_SYS_STAT_H
  30. #include <sys/stat.h>
  31. #endif
  32. #ifdef HAVE_UTIME_H
  33. #include <utime.h>
  34. #endif
  35. #ifdef HAVE_SYS_UTIME_H
  36. #include <sys/utime.h>
  37. #endif
  38. #ifdef HAVE_UNISTD_H
  39. #include <unistd.h>
  40. #endif
  41. #ifdef HAVE_SYS_FCNTL_H
  42. #include <sys/fcntl.h>
  43. #endif
  44. #ifdef HAVE_PWD_H
  45. #include <pwd.h>
  46. #endif
  47. #ifdef HAVE_GRP_H
  48. #include <grp.h>
  49. #endif
  50. #ifdef HAVE_FCNTL_H
  51. #include <fcntl.h>
  52. #endif
  53. #ifdef HAVE_ERRNO_H
  54. #include <errno.h>
  55. #endif
  56. #ifdef HAVE_ARPA_INET_H
  57. #include <arpa/inet.h>
  58. #endif
  59. #ifdef HAVE_CRT_EXTERNS_H
  60. #include <crt_externs.h>
  61. #endif
  62. #ifdef HAVE_SYS_STATVFS_H
  63. #include <sys/statvfs.h>
  64. #endif
  65. #ifdef HAVE_SYS_CAPABILITY_H
  66. #include <sys/capability.h>
  67. #endif
  68. #ifdef _WIN32
  69. #include <conio.h>
  70. #include <wchar.h>
  71. /* Some mingw headers lack these. :p */
  72. #if defined(HAVE_DECL__GETWCH) && !HAVE_DECL__GETWCH
  73. wint_t _getwch(void);
  74. #endif
  75. #ifndef WEOF
  76. #define WEOF (wchar_t)(0xFFFF)
  77. #endif
  78. #if defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY
  79. static inline void
  80. SecureZeroMemory(PVOID ptr, SIZE_T cnt)
  81. {
  82. volatile char *vcptr = (volatile char*)ptr;
  83. while (cnt--)
  84. *vcptr++ = 0;
  85. }
  86. #endif /* defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY */
  87. #elif defined(HAVE_READPASSPHRASE_H)
  88. #include <readpassphrase.h>
  89. #else
  90. #include "tor_readpassphrase.h"
  91. #endif /* defined(_WIN32) || ... */
  92. /* Includes for the process attaching prevention */
  93. #if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
  94. /* Only use the linux prctl; the IRIX prctl is totally different */
  95. #include <sys/prctl.h>
  96. #elif defined(__APPLE__)
  97. #include <sys/ptrace.h>
  98. #endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) || ... */
  99. #ifdef HAVE_NETDB_H
  100. #include <netdb.h>
  101. #endif
  102. #ifdef HAVE_SYS_PARAM_H
  103. #include <sys/param.h> /* FreeBSD needs this to know what version it is */
  104. #endif
  105. #include <stdio.h>
  106. #include <stdlib.h>
  107. #ifdef HAVE_SIGNAL_H
  108. #include <signal.h>
  109. #endif
  110. #ifdef HAVE_MMAP
  111. #include <sys/mman.h>
  112. #endif
  113. #ifdef HAVE_SYS_SYSLIMITS_H
  114. #include <sys/syslimits.h>
  115. #endif
  116. #ifdef HAVE_SYS_FILE_H
  117. #include <sys/file.h>
  118. #endif
  119. #include "lib/log/torlog.h"
  120. #include "common/util.h"
  121. #include "lib/container/smartlist.h"
  122. #include "lib/wallclock/tm_cvt.h"
  123. #include "lib/net/address.h"
  124. #include "lib/sandbox/sandbox.h"
  125. /** Number of extra file descriptors to keep in reserve beyond those that we
  126. * tell Tor it's allowed to use. */
  127. #define ULIMIT_BUFFER 32 /* keep 32 extra fd's beyond ConnLimit_ */
  128. /** Learn the maximum allowed number of file descriptors, and tell the
  129. * system we want to use up to that number. (Some systems have a low soft
  130. * limit, and let us set it higher.) We compute this by finding the largest
  131. * number that we can use.
  132. *
  133. * If the limit is below the reserved file descriptor value (ULIMIT_BUFFER),
  134. * return -1 and <b>max_out</b> is untouched.
  135. *
  136. * If we can't find a number greater than or equal to <b>limit</b>, then we
  137. * fail by returning -1 and <b>max_out</b> is untouched.
  138. *
  139. * If we are unable to set the limit value because of setrlimit() failing,
  140. * return 0 and <b>max_out</b> is set to the current maximum value returned
  141. * by getrlimit().
  142. *
  143. * Otherwise, return 0 and store the maximum we found inside <b>max_out</b>
  144. * and set <b>max_sockets</b> with that value as well.*/
  145. int
  146. set_max_file_descriptors(rlim_t limit, int *max_out)
  147. {
  148. if (limit < ULIMIT_BUFFER) {
  149. log_warn(LD_CONFIG,
  150. "ConnLimit must be at least %d. Failing.", ULIMIT_BUFFER);
  151. return -1;
  152. }
  153. /* Define some maximum connections values for systems where we cannot
  154. * automatically determine a limit. Re Cygwin, see
  155. * http://archives.seul.org/or/talk/Aug-2006/msg00210.html
  156. * For an iPhone, 9999 should work. For Windows and all other unknown
  157. * systems we use 15000 as the default. */
  158. #ifndef HAVE_GETRLIMIT
  159. #if defined(CYGWIN) || defined(__CYGWIN__)
  160. const char *platform = "Cygwin";
  161. const unsigned long MAX_CONNECTIONS = 3200;
  162. #elif defined(_WIN32)
  163. const char *platform = "Windows";
  164. const unsigned long MAX_CONNECTIONS = 15000;
  165. #else
  166. const char *platform = "unknown platforms with no getrlimit()";
  167. const unsigned long MAX_CONNECTIONS = 15000;
  168. #endif /* defined(CYGWIN) || defined(__CYGWIN__) || ... */
  169. log_fn(LOG_INFO, LD_NET,
  170. "This platform is missing getrlimit(). Proceeding.");
  171. if (limit > MAX_CONNECTIONS) {
  172. log_warn(LD_CONFIG,
  173. "We do not support more than %lu file descriptors "
  174. "on %s. Tried to raise to %lu.",
  175. (unsigned long)MAX_CONNECTIONS, platform, (unsigned long)limit);
  176. return -1;
  177. }
  178. limit = MAX_CONNECTIONS;
  179. #else /* !(!defined(HAVE_GETRLIMIT)) */
  180. struct rlimit rlim;
  181. if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
  182. log_warn(LD_NET, "Could not get maximum number of file descriptors: %s",
  183. strerror(errno));
  184. return -1;
  185. }
  186. if (rlim.rlim_max < limit) {
  187. log_warn(LD_CONFIG,"We need %lu file descriptors available, and we're "
  188. "limited to %lu. Please change your ulimit -n.",
  189. (unsigned long)limit, (unsigned long)rlim.rlim_max);
  190. return -1;
  191. }
  192. if (rlim.rlim_max > rlim.rlim_cur) {
  193. log_info(LD_NET,"Raising max file descriptors from %lu to %lu.",
  194. (unsigned long)rlim.rlim_cur, (unsigned long)rlim.rlim_max);
  195. }
  196. /* Set the current limit value so if the attempt to set the limit to the
  197. * max fails at least we'll have a valid value of maximum sockets. */
  198. *max_out = (int)rlim.rlim_cur - ULIMIT_BUFFER;
  199. set_max_sockets(*max_out);
  200. rlim.rlim_cur = rlim.rlim_max;
  201. if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
  202. int couldnt_set = 1;
  203. const int setrlimit_errno = errno;
  204. #ifdef OPEN_MAX
  205. uint64_t try_limit = OPEN_MAX - ULIMIT_BUFFER;
  206. if (errno == EINVAL && try_limit < (uint64_t) rlim.rlim_cur) {
  207. /* On some platforms, OPEN_MAX is the real limit, and getrlimit() is
  208. * full of nasty lies. I'm looking at you, OSX 10.5.... */
  209. rlim.rlim_cur = MIN((rlim_t) try_limit, rlim.rlim_cur);
  210. if (setrlimit(RLIMIT_NOFILE, &rlim) == 0) {
  211. if (rlim.rlim_cur < (rlim_t)limit) {
  212. log_warn(LD_CONFIG, "We are limited to %lu file descriptors by "
  213. "OPEN_MAX (%lu), and ConnLimit is %lu. Changing "
  214. "ConnLimit; sorry.",
  215. (unsigned long)try_limit, (unsigned long)OPEN_MAX,
  216. (unsigned long)limit);
  217. } else {
  218. log_info(LD_CONFIG, "Dropped connection limit to %lu based on "
  219. "OPEN_MAX (%lu); Apparently, %lu was too high and rlimit "
  220. "lied to us.",
  221. (unsigned long)try_limit, (unsigned long)OPEN_MAX,
  222. (unsigned long)rlim.rlim_max);
  223. }
  224. couldnt_set = 0;
  225. }
  226. }
  227. #endif /* defined(OPEN_MAX) */
  228. if (couldnt_set) {
  229. log_warn(LD_CONFIG,"Couldn't set maximum number of file descriptors: %s",
  230. strerror(setrlimit_errno));
  231. }
  232. }
  233. /* leave some overhead for logs, etc, */
  234. limit = rlim.rlim_cur;
  235. #endif /* !defined(HAVE_GETRLIMIT) */
  236. if (limit > INT_MAX)
  237. limit = INT_MAX;
  238. tor_assert(max_out);
  239. *max_out = (int)limit - ULIMIT_BUFFER;
  240. set_max_sockets(*max_out);
  241. return 0;
  242. }
  243. /** Hold the result of our call to <b>uname</b>. */
  244. static char uname_result[256];
  245. /** True iff uname_result is set. */
  246. static int uname_result_is_set = 0;
  247. /** Return a pointer to a description of our platform.
  248. */
  249. MOCK_IMPL(const char *,
  250. get_uname,(void))
  251. {
  252. #ifdef HAVE_UNAME
  253. struct utsname u;
  254. #endif
  255. if (!uname_result_is_set) {
  256. #ifdef HAVE_UNAME
  257. if (uname(&u) != -1) {
  258. /* (Linux says 0 is success, Solaris says 1 is success) */
  259. strlcpy(uname_result, u.sysname, sizeof(uname_result));
  260. } else
  261. #endif /* defined(HAVE_UNAME) */
  262. {
  263. #ifdef _WIN32
  264. OSVERSIONINFOEX info;
  265. int i;
  266. const char *plat = NULL;
  267. static struct {
  268. unsigned major; unsigned minor; const char *version;
  269. } win_version_table[] = {
  270. { 6, 2, "Windows 8" },
  271. { 6, 1, "Windows 7" },
  272. { 6, 0, "Windows Vista" },
  273. { 5, 2, "Windows Server 2003" },
  274. { 5, 1, "Windows XP" },
  275. { 5, 0, "Windows 2000" },
  276. /* { 4, 0, "Windows NT 4.0" }, */
  277. { 4, 90, "Windows Me" },
  278. { 4, 10, "Windows 98" },
  279. /* { 4, 0, "Windows 95" } */
  280. { 3, 51, "Windows NT 3.51" },
  281. { 0, 0, NULL }
  282. };
  283. memset(&info, 0, sizeof(info));
  284. info.dwOSVersionInfoSize = sizeof(info);
  285. if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
  286. strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx"
  287. " doesn't work.", sizeof(uname_result));
  288. uname_result_is_set = 1;
  289. return uname_result;
  290. }
  291. if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
  292. if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
  293. plat = "Windows NT 4.0";
  294. else
  295. plat = "Windows 95";
  296. } else {
  297. for (i=0; win_version_table[i].major>0; ++i) {
  298. if (win_version_table[i].major == info.dwMajorVersion &&
  299. win_version_table[i].minor == info.dwMinorVersion) {
  300. plat = win_version_table[i].version;
  301. break;
  302. }
  303. }
  304. }
  305. if (plat) {
  306. strlcpy(uname_result, plat, sizeof(uname_result));
  307. } else {
  308. if (info.dwMajorVersion > 6 ||
  309. (info.dwMajorVersion==6 && info.dwMinorVersion>2))
  310. tor_snprintf(uname_result, sizeof(uname_result),
  311. "Very recent version of Windows [major=%d,minor=%d]",
  312. (int)info.dwMajorVersion,(int)info.dwMinorVersion);
  313. else
  314. tor_snprintf(uname_result, sizeof(uname_result),
  315. "Unrecognized version of Windows [major=%d,minor=%d]",
  316. (int)info.dwMajorVersion,(int)info.dwMinorVersion);
  317. }
  318. #ifdef VER_NT_SERVER
  319. if (info.wProductType == VER_NT_SERVER ||
  320. info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
  321. strlcat(uname_result, " [server]", sizeof(uname_result));
  322. }
  323. #endif /* defined(VER_NT_SERVER) */
  324. #else /* !(defined(_WIN32)) */
  325. /* LCOV_EXCL_START -- can't provoke uname failure */
  326. strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
  327. /* LCOV_EXCL_STOP */
  328. #endif /* defined(_WIN32) */
  329. }
  330. uname_result_is_set = 1;
  331. }
  332. return uname_result;
  333. }
  334. /*
  335. * Process control
  336. */
  337. /** Implementation logic for compute_num_cpus(). */
  338. static int
  339. compute_num_cpus_impl(void)
  340. {
  341. #ifdef _WIN32
  342. SYSTEM_INFO info;
  343. memset(&info, 0, sizeof(info));
  344. GetSystemInfo(&info);
  345. if (info.dwNumberOfProcessors >= 1 && info.dwNumberOfProcessors < INT_MAX)
  346. return (int)info.dwNumberOfProcessors;
  347. else
  348. return -1;
  349. #elif defined(HAVE_SYSCONF)
  350. #ifdef _SC_NPROCESSORS_CONF
  351. long cpus_conf = sysconf(_SC_NPROCESSORS_CONF);
  352. #else
  353. long cpus_conf = -1;
  354. #endif
  355. #ifdef _SC_NPROCESSORS_ONLN
  356. long cpus_onln = sysconf(_SC_NPROCESSORS_ONLN);
  357. #else
  358. long cpus_onln = -1;
  359. #endif
  360. long cpus = -1;
  361. if (cpus_conf > 0 && cpus_onln < 0) {
  362. cpus = cpus_conf;
  363. } else if (cpus_onln > 0 && cpus_conf < 0) {
  364. cpus = cpus_onln;
  365. } else if (cpus_onln > 0 && cpus_conf > 0) {
  366. if (cpus_onln < cpus_conf) {
  367. log_notice(LD_GENERAL, "I think we have %ld CPUS, but only %ld of them "
  368. "are available. Telling Tor to only use %ld. You can over"
  369. "ride this with the NumCPUs option",
  370. cpus_conf, cpus_onln, cpus_onln);
  371. }
  372. cpus = cpus_onln;
  373. }
  374. if (cpus >= 1 && cpus < INT_MAX)
  375. return (int)cpus;
  376. else
  377. return -1;
  378. #else
  379. return -1;
  380. #endif /* defined(_WIN32) || ... */
  381. }
  382. #define MAX_DETECTABLE_CPUS 16
  383. /** Return how many CPUs we are running with. We assume that nobody is
  384. * using hot-swappable CPUs, so we don't recompute this after the first
  385. * time. Return -1 if we don't know how to tell the number of CPUs on this
  386. * system.
  387. */
  388. int
  389. compute_num_cpus(void)
  390. {
  391. static int num_cpus = -2;
  392. if (num_cpus == -2) {
  393. num_cpus = compute_num_cpus_impl();
  394. tor_assert(num_cpus != -2);
  395. if (num_cpus > MAX_DETECTABLE_CPUS) {
  396. /* LCOV_EXCL_START */
  397. log_notice(LD_GENERAL, "Wow! I detected that you have %d CPUs. I "
  398. "will not autodetect any more than %d, though. If you "
  399. "want to configure more, set NumCPUs in your torrc",
  400. num_cpus, MAX_DETECTABLE_CPUS);
  401. num_cpus = MAX_DETECTABLE_CPUS;
  402. /* LCOV_EXCL_STOP */
  403. }
  404. }
  405. return num_cpus;
  406. }
  407. #if defined(HW_PHYSMEM64)
  408. /* This appears to be an OpenBSD thing */
  409. #define INT64_HW_MEM HW_PHYSMEM64
  410. #elif defined(HW_MEMSIZE)
  411. /* OSX defines this one */
  412. #define INT64_HW_MEM HW_MEMSIZE
  413. #endif /* defined(HW_PHYSMEM64) || ... */
  414. /**
  415. * Helper: try to detect the total system memory, and return it. On failure,
  416. * return 0.
  417. */
  418. static uint64_t
  419. get_total_system_memory_impl(void)
  420. {
  421. #if defined(__linux__)
  422. /* On linux, sysctl is deprecated. Because proc is so awesome that you
  423. * shouldn't _want_ to write portable code, I guess? */
  424. unsigned long long result=0;
  425. int fd = -1;
  426. char *s = NULL;
  427. const char *cp;
  428. size_t file_size=0;
  429. if (-1 == (fd = tor_open_cloexec("/proc/meminfo",O_RDONLY,0)))
  430. return 0;
  431. s = read_file_to_str_until_eof(fd, 65536, &file_size);
  432. if (!s)
  433. goto err;
  434. cp = strstr(s, "MemTotal:");
  435. if (!cp)
  436. goto err;
  437. /* Use the system sscanf so that space will match a wider number of space */
  438. if (sscanf(cp, "MemTotal: %llu kB\n", &result) != 1)
  439. goto err;
  440. close(fd);
  441. tor_free(s);
  442. return result * 1024;
  443. /* LCOV_EXCL_START Can't reach this unless proc is broken. */
  444. err:
  445. tor_free(s);
  446. close(fd);
  447. return 0;
  448. /* LCOV_EXCL_STOP */
  449. #elif defined (_WIN32)
  450. /* Windows has MEMORYSTATUSEX; pretty straightforward. */
  451. MEMORYSTATUSEX ms;
  452. memset(&ms, 0, sizeof(ms));
  453. ms.dwLength = sizeof(ms);
  454. if (! GlobalMemoryStatusEx(&ms))
  455. return 0;
  456. return ms.ullTotalPhys;
  457. #elif defined(HAVE_SYSCTL) && defined(INT64_HW_MEM)
  458. /* On many systems, HW_PYHSMEM is clipped to 32 bits; let's use a better
  459. * variant if we know about it. */
  460. uint64_t memsize = 0;
  461. size_t len = sizeof(memsize);
  462. int mib[2] = {CTL_HW, INT64_HW_MEM};
  463. if (sysctl(mib,2,&memsize,&len,NULL,0))
  464. return 0;
  465. return memsize;
  466. #elif defined(HAVE_SYSCTL) && defined(HW_PHYSMEM)
  467. /* On some systems (like FreeBSD I hope) you can use a size_t with
  468. * HW_PHYSMEM. */
  469. size_t memsize=0;
  470. size_t len = sizeof(memsize);
  471. int mib[2] = {CTL_HW, HW_USERMEM};
  472. if (sysctl(mib,2,&memsize,&len,NULL,0))
  473. return 0;
  474. return memsize;
  475. #else
  476. /* I have no clue. */
  477. return 0;
  478. #endif /* defined(__linux__) || ... */
  479. }
  480. /**
  481. * Try to find out how much physical memory the system has. On success,
  482. * return 0 and set *<b>mem_out</b> to that value. On failure, return -1.
  483. */
  484. MOCK_IMPL(int,
  485. get_total_system_memory, (size_t *mem_out))
  486. {
  487. static size_t mem_cached=0;
  488. uint64_t m = get_total_system_memory_impl();
  489. if (0 == m) {
  490. /* LCOV_EXCL_START -- can't make this happen without mocking. */
  491. /* We couldn't find our memory total */
  492. if (0 == mem_cached) {
  493. /* We have no cached value either */
  494. *mem_out = 0;
  495. return -1;
  496. }
  497. *mem_out = mem_cached;
  498. return 0;
  499. /* LCOV_EXCL_STOP */
  500. }
  501. #if SIZE_MAX != UINT64_MAX
  502. if (m > SIZE_MAX) {
  503. /* I think this could happen if we're a 32-bit Tor running on a 64-bit
  504. * system: we could have more system memory than would fit in a
  505. * size_t. */
  506. m = SIZE_MAX;
  507. }
  508. #endif /* SIZE_MAX != UINT64_MAX */
  509. *mem_out = mem_cached = (size_t) m;
  510. return 0;
  511. }
  512. /** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
  513. * bytes of passphrase into <b>output</b>. Return the number of bytes in
  514. * the passphrase, excluding terminating NUL.
  515. */
  516. ssize_t
  517. tor_getpass(const char *prompt, char *output, size_t buflen)
  518. {
  519. tor_assert(buflen <= SSIZE_MAX);
  520. tor_assert(buflen >= 1);
  521. #if defined(HAVE_READPASSPHRASE)
  522. char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF);
  523. if (pwd == NULL)
  524. return -1;
  525. return strlen(pwd);
  526. #elif defined(_WIN32)
  527. int r = -1;
  528. while (*prompt) {
  529. _putch(*prompt++);
  530. }
  531. tor_assert(buflen <= INT_MAX);
  532. wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t));
  533. wchar_t *ptr = buf, *lastch = buf + buflen - 1;
  534. while (ptr < lastch) {
  535. wint_t ch = _getwch();
  536. switch (ch) {
  537. case '\r':
  538. case '\n':
  539. case WEOF:
  540. goto done_reading;
  541. case 3:
  542. goto done; /* Can't actually read ctrl-c this way. */
  543. case '\b':
  544. if (ptr > buf)
  545. --ptr;
  546. continue;
  547. case 0:
  548. case 0xe0:
  549. ch = _getwch(); /* Ignore; this is a function or arrow key */
  550. break;
  551. default:
  552. *ptr++ = ch;
  553. break;
  554. }
  555. }
  556. done_reading:
  557. ;
  558. #ifndef WC_ERR_INVALID_CHARS
  559. #define WC_ERR_INVALID_CHARS 0x80
  560. #endif
  561. /* Now convert it to UTF-8 */
  562. r = WideCharToMultiByte(CP_UTF8,
  563. WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS,
  564. buf, (int)(ptr-buf),
  565. output, (int)(buflen-1),
  566. NULL, NULL);
  567. if (r <= 0) {
  568. r = -1;
  569. goto done;
  570. }
  571. tor_assert(r < (int)buflen);
  572. output[r] = 0;
  573. done:
  574. SecureZeroMemory(buf, sizeof(wchar_t)*buflen);
  575. tor_free(buf);
  576. return r;
  577. #else
  578. #error "No implementation for tor_getpass found!"
  579. #endif /* defined(HAVE_READPASSPHRASE) || ... */
  580. }
  581. /** Return the amount of free disk space we have permission to use, in
  582. * bytes. Return -1 if the amount of free space can't be determined. */
  583. int64_t
  584. tor_get_avail_disk_space(const char *path)
  585. {
  586. #ifdef HAVE_STATVFS
  587. struct statvfs st;
  588. int r;
  589. memset(&st, 0, sizeof(st));
  590. r = statvfs(path, &st);
  591. if (r < 0)
  592. return -1;
  593. int64_t result = st.f_bavail;
  594. if (st.f_frsize) {
  595. result *= st.f_frsize;
  596. } else if (st.f_bsize) {
  597. result *= st.f_bsize;
  598. } else {
  599. return -1;
  600. }
  601. return result;
  602. #elif defined(_WIN32)
  603. ULARGE_INTEGER freeBytesAvail;
  604. BOOL ok;
  605. ok = GetDiskFreeSpaceEx(path, &freeBytesAvail, NULL, NULL);
  606. if (!ok) {
  607. return -1;
  608. }
  609. return (int64_t)freeBytesAvail.QuadPart;
  610. #else
  611. (void)path;
  612. errno = ENOSYS;
  613. return -1;
  614. #endif /* defined(HAVE_STATVFS) || ... */
  615. }