compat.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  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_SYS_STATVFS_H
  60. #include <sys/statvfs.h>
  61. #endif
  62. #ifdef HAVE_SYS_CAPABILITY_H
  63. #include <sys/capability.h>
  64. #endif
  65. #ifdef _WIN32
  66. #include <conio.h>
  67. #include <wchar.h>
  68. /* Some mingw headers lack these. :p */
  69. #if defined(HAVE_DECL__GETWCH) && !HAVE_DECL__GETWCH
  70. wint_t _getwch(void);
  71. #endif
  72. #ifndef WEOF
  73. #define WEOF (wchar_t)(0xFFFF)
  74. #endif
  75. #if defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY
  76. static inline void
  77. SecureZeroMemory(PVOID ptr, SIZE_T cnt)
  78. {
  79. volatile char *vcptr = (volatile char*)ptr;
  80. while (cnt--)
  81. *vcptr++ = 0;
  82. }
  83. #endif /* defined(HAVE_DECL_SECUREZEROMEMORY) && !HAVE_DECL_SECUREZEROMEMORY */
  84. #elif defined(HAVE_READPASSPHRASE_H)
  85. #include <readpassphrase.h>
  86. #else
  87. #include "tor_readpassphrase.h"
  88. #endif /* defined(_WIN32) || ... */
  89. /* Includes for the process attaching prevention */
  90. #if defined(HAVE_SYS_PRCTL_H) && defined(__linux__)
  91. /* Only use the linux prctl; the IRIX prctl is totally different */
  92. #include <sys/prctl.h>
  93. #elif defined(__APPLE__)
  94. #include <sys/ptrace.h>
  95. #endif /* defined(HAVE_SYS_PRCTL_H) && defined(__linux__) || ... */
  96. #ifdef HAVE_NETDB_H
  97. #include <netdb.h>
  98. #endif
  99. #ifdef HAVE_SYS_PARAM_H
  100. #include <sys/param.h> /* FreeBSD needs this to know what version it is */
  101. #endif
  102. #include <stdio.h>
  103. #include <stdlib.h>
  104. #ifdef HAVE_SIGNAL_H
  105. #include <signal.h>
  106. #endif
  107. #ifdef HAVE_MMAP
  108. #include <sys/mman.h>
  109. #endif
  110. #ifdef HAVE_SYS_SYSLIMITS_H
  111. #include <sys/syslimits.h>
  112. #endif
  113. #ifdef HAVE_SYS_FILE_H
  114. #include <sys/file.h>
  115. #endif
  116. #include "lib/log/torlog.h"
  117. #include "common/util.h"
  118. #include "lib/container/smartlist.h"
  119. #include "lib/wallclock/tm_cvt.h"
  120. #include "lib/net/address.h"
  121. #include "lib/sandbox/sandbox.h"
  122. /** Hold the result of our call to <b>uname</b>. */
  123. static char uname_result[256];
  124. /** True iff uname_result is set. */
  125. static int uname_result_is_set = 0;
  126. /** Return a pointer to a description of our platform.
  127. */
  128. MOCK_IMPL(const char *,
  129. get_uname,(void))
  130. {
  131. #ifdef HAVE_UNAME
  132. struct utsname u;
  133. #endif
  134. if (!uname_result_is_set) {
  135. #ifdef HAVE_UNAME
  136. if (uname(&u) != -1) {
  137. /* (Linux says 0 is success, Solaris says 1 is success) */
  138. strlcpy(uname_result, u.sysname, sizeof(uname_result));
  139. } else
  140. #endif /* defined(HAVE_UNAME) */
  141. {
  142. #ifdef _WIN32
  143. OSVERSIONINFOEX info;
  144. int i;
  145. const char *plat = NULL;
  146. static struct {
  147. unsigned major; unsigned minor; const char *version;
  148. } win_version_table[] = {
  149. { 6, 2, "Windows 8" },
  150. { 6, 1, "Windows 7" },
  151. { 6, 0, "Windows Vista" },
  152. { 5, 2, "Windows Server 2003" },
  153. { 5, 1, "Windows XP" },
  154. { 5, 0, "Windows 2000" },
  155. /* { 4, 0, "Windows NT 4.0" }, */
  156. { 4, 90, "Windows Me" },
  157. { 4, 10, "Windows 98" },
  158. /* { 4, 0, "Windows 95" } */
  159. { 3, 51, "Windows NT 3.51" },
  160. { 0, 0, NULL }
  161. };
  162. memset(&info, 0, sizeof(info));
  163. info.dwOSVersionInfoSize = sizeof(info);
  164. if (! GetVersionEx((LPOSVERSIONINFO)&info)) {
  165. strlcpy(uname_result, "Bizarre version of Windows where GetVersionEx"
  166. " doesn't work.", sizeof(uname_result));
  167. uname_result_is_set = 1;
  168. return uname_result;
  169. }
  170. if (info.dwMajorVersion == 4 && info.dwMinorVersion == 0) {
  171. if (info.dwPlatformId == VER_PLATFORM_WIN32_NT)
  172. plat = "Windows NT 4.0";
  173. else
  174. plat = "Windows 95";
  175. } else {
  176. for (i=0; win_version_table[i].major>0; ++i) {
  177. if (win_version_table[i].major == info.dwMajorVersion &&
  178. win_version_table[i].minor == info.dwMinorVersion) {
  179. plat = win_version_table[i].version;
  180. break;
  181. }
  182. }
  183. }
  184. if (plat) {
  185. strlcpy(uname_result, plat, sizeof(uname_result));
  186. } else {
  187. if (info.dwMajorVersion > 6 ||
  188. (info.dwMajorVersion==6 && info.dwMinorVersion>2))
  189. tor_snprintf(uname_result, sizeof(uname_result),
  190. "Very recent version of Windows [major=%d,minor=%d]",
  191. (int)info.dwMajorVersion,(int)info.dwMinorVersion);
  192. else
  193. tor_snprintf(uname_result, sizeof(uname_result),
  194. "Unrecognized version of Windows [major=%d,minor=%d]",
  195. (int)info.dwMajorVersion,(int)info.dwMinorVersion);
  196. }
  197. #ifdef VER_NT_SERVER
  198. if (info.wProductType == VER_NT_SERVER ||
  199. info.wProductType == VER_NT_DOMAIN_CONTROLLER) {
  200. strlcat(uname_result, " [server]", sizeof(uname_result));
  201. }
  202. #endif /* defined(VER_NT_SERVER) */
  203. #else /* !(defined(_WIN32)) */
  204. /* LCOV_EXCL_START -- can't provoke uname failure */
  205. strlcpy(uname_result, "Unknown platform", sizeof(uname_result));
  206. /* LCOV_EXCL_STOP */
  207. #endif /* defined(_WIN32) */
  208. }
  209. uname_result_is_set = 1;
  210. }
  211. return uname_result;
  212. }
  213. /*
  214. * Process control
  215. */
  216. /** Emit the password prompt <b>prompt</b>, then read up to <b>buflen</b>
  217. * bytes of passphrase into <b>output</b>. Return the number of bytes in
  218. * the passphrase, excluding terminating NUL.
  219. */
  220. ssize_t
  221. tor_getpass(const char *prompt, char *output, size_t buflen)
  222. {
  223. tor_assert(buflen <= SSIZE_MAX);
  224. tor_assert(buflen >= 1);
  225. #if defined(HAVE_READPASSPHRASE)
  226. char *pwd = readpassphrase(prompt, output, buflen, RPP_ECHO_OFF);
  227. if (pwd == NULL)
  228. return -1;
  229. return strlen(pwd);
  230. #elif defined(_WIN32)
  231. int r = -1;
  232. while (*prompt) {
  233. _putch(*prompt++);
  234. }
  235. tor_assert(buflen <= INT_MAX);
  236. wchar_t *buf = tor_calloc(buflen, sizeof(wchar_t));
  237. wchar_t *ptr = buf, *lastch = buf + buflen - 1;
  238. while (ptr < lastch) {
  239. wint_t ch = _getwch();
  240. switch (ch) {
  241. case '\r':
  242. case '\n':
  243. case WEOF:
  244. goto done_reading;
  245. case 3:
  246. goto done; /* Can't actually read ctrl-c this way. */
  247. case '\b':
  248. if (ptr > buf)
  249. --ptr;
  250. continue;
  251. case 0:
  252. case 0xe0:
  253. ch = _getwch(); /* Ignore; this is a function or arrow key */
  254. break;
  255. default:
  256. *ptr++ = ch;
  257. break;
  258. }
  259. }
  260. done_reading:
  261. ;
  262. #ifndef WC_ERR_INVALID_CHARS
  263. #define WC_ERR_INVALID_CHARS 0x80
  264. #endif
  265. /* Now convert it to UTF-8 */
  266. r = WideCharToMultiByte(CP_UTF8,
  267. WC_NO_BEST_FIT_CHARS|WC_ERR_INVALID_CHARS,
  268. buf, (int)(ptr-buf),
  269. output, (int)(buflen-1),
  270. NULL, NULL);
  271. if (r <= 0) {
  272. r = -1;
  273. goto done;
  274. }
  275. tor_assert(r < (int)buflen);
  276. output[r] = 0;
  277. done:
  278. SecureZeroMemory(buf, sizeof(wchar_t)*buflen);
  279. tor_free(buf);
  280. return r;
  281. #else
  282. #error "No implementation for tor_getpass found!"
  283. #endif /* defined(HAVE_READPASSPHRASE) || ... */
  284. }