winmisc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. /*
  2. * winmisc.c: miscellaneous Windows-specific things
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include "putty.h"
  7. #ifndef SECURITY_WIN32
  8. #define SECURITY_WIN32
  9. #endif
  10. #include <security.h>
  11. OSVERSIONINFO osVersion;
  12. char *platform_get_x_display(void) {
  13. /* We may as well check for DISPLAY in case it's useful. */
  14. return dupstr(getenv("DISPLAY"));
  15. }
  16. Filename *filename_from_str(const char *str)
  17. {
  18. Filename *ret = snew(Filename);
  19. ret->path = dupstr(str);
  20. return ret;
  21. }
  22. Filename *filename_copy(const Filename *fn)
  23. {
  24. return filename_from_str(fn->path);
  25. }
  26. const char *filename_to_str(const Filename *fn)
  27. {
  28. return fn->path;
  29. }
  30. int filename_equal(const Filename *f1, const Filename *f2)
  31. {
  32. return !strcmp(f1->path, f2->path);
  33. }
  34. int filename_is_null(const Filename *fn)
  35. {
  36. return !*fn->path;
  37. }
  38. void filename_free(Filename *fn)
  39. {
  40. sfree(fn->path);
  41. sfree(fn);
  42. }
  43. int filename_serialise(const Filename *f, void *vdata)
  44. {
  45. char *data = (char *)vdata;
  46. int len = strlen(f->path) + 1; /* include trailing NUL */
  47. if (data) {
  48. strcpy(data, f->path);
  49. }
  50. return len;
  51. }
  52. Filename *filename_deserialise(void *vdata, int maxsize, int *used)
  53. {
  54. char *data = (char *)vdata;
  55. char *end;
  56. end = memchr(data, '\0', maxsize);
  57. if (!end)
  58. return NULL;
  59. end++;
  60. *used = end - data;
  61. return filename_from_str(data);
  62. }
  63. char filename_char_sanitise(char c)
  64. {
  65. if (strchr("<>:\"/\\|?*", c))
  66. return '.';
  67. return c;
  68. }
  69. #ifndef NO_SECUREZEROMEMORY
  70. /*
  71. * Windows implementation of smemclr (see misc.c) using SecureZeroMemory.
  72. */
  73. void smemclr(void *b, size_t n) {
  74. if (b && n > 0)
  75. SecureZeroMemory(b, n);
  76. }
  77. #endif
  78. char *get_username(void)
  79. {
  80. DWORD namelen;
  81. char *user;
  82. int got_username = FALSE;
  83. DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA,
  84. (EXTENDED_NAME_FORMAT, LPSTR, PULONG));
  85. {
  86. static int tried_usernameex = FALSE;
  87. if (!tried_usernameex) {
  88. /* Not available on Win9x, so load dynamically */
  89. HMODULE secur32 = load_system32_dll("secur32.dll");
  90. GET_WINDOWS_FUNCTION(secur32, GetUserNameExA);
  91. tried_usernameex = TRUE;
  92. }
  93. }
  94. if (p_GetUserNameExA) {
  95. /*
  96. * If available, use the principal -- this avoids the problem
  97. * that the local username is case-insensitive but Kerberos
  98. * usernames are case-sensitive.
  99. */
  100. /* Get the length */
  101. namelen = 0;
  102. (void) p_GetUserNameExA(NameUserPrincipal, NULL, &namelen);
  103. user = snewn(namelen, char);
  104. got_username = p_GetUserNameExA(NameUserPrincipal, user, &namelen);
  105. if (got_username) {
  106. char *p = strchr(user, '@');
  107. if (p) *p = 0;
  108. } else {
  109. sfree(user);
  110. }
  111. }
  112. if (!got_username) {
  113. /* Fall back to local user name */
  114. namelen = 0;
  115. if (GetUserName(NULL, &namelen) == FALSE) {
  116. /*
  117. * Apparently this doesn't work at least on Windows XP SP2.
  118. * Thus assume a maximum of 256. It will fail again if it
  119. * doesn't fit.
  120. */
  121. namelen = 256;
  122. }
  123. user = snewn(namelen, char);
  124. got_username = GetUserName(user, &namelen);
  125. if (!got_username) {
  126. sfree(user);
  127. }
  128. }
  129. return got_username ? user : NULL;
  130. }
  131. void dll_hijacking_protection(void)
  132. {
  133. /*
  134. * If the OS provides it, call SetDefaultDllDirectories() to
  135. * prevent DLLs from being loaded from the directory containing
  136. * our own binary, and instead only load from system32.
  137. *
  138. * This is a protection against hijacking attacks, if someone runs
  139. * PuTTY directly from their web browser's download directory
  140. * having previously been enticed into clicking on an unwise link
  141. * that downloaded a malicious DLL to the same directory under one
  142. * of various magic names that seem to be things that standard
  143. * Windows DLLs delegate to.
  144. *
  145. * It shouldn't break deliberate loading of user-provided DLLs
  146. * such as GSSAPI providers, because those are specified by their
  147. * full pathname by the user-provided configuration.
  148. */
  149. static HMODULE kernel32_module;
  150. DECL_WINDOWS_FUNCTION(static, BOOL, SetDefaultDllDirectories, (DWORD));
  151. if (!kernel32_module) {
  152. kernel32_module = load_system32_dll("kernel32.dll");
  153. GET_WINDOWS_FUNCTION(kernel32_module, SetDefaultDllDirectories);
  154. }
  155. if (p_SetDefaultDllDirectories) {
  156. /* LOAD_LIBRARY_SEARCH_SYSTEM32 only */
  157. p_SetDefaultDllDirectories(0x800);
  158. }
  159. }
  160. BOOL init_winver(void)
  161. {
  162. ZeroMemory(&osVersion, sizeof(osVersion));
  163. osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
  164. return GetVersionEx ( (OSVERSIONINFO *) &osVersion);
  165. }
  166. HMODULE load_system32_dll(const char *libname)
  167. {
  168. /*
  169. * Wrapper function to load a DLL out of c:\windows\system32
  170. * without going through the full DLL search path. (Hence no
  171. * attack is possible by placing a substitute DLL earlier on that
  172. * path.)
  173. */
  174. static char *sysdir = NULL;
  175. char *fullpath;
  176. HMODULE ret;
  177. if (!sysdir) {
  178. int size = 0, len;
  179. do {
  180. size = 3*size/2 + 512;
  181. sysdir = sresize(sysdir, size, char);
  182. len = GetSystemDirectory(sysdir, size);
  183. } while (len >= size);
  184. }
  185. fullpath = dupcat(sysdir, "\\", libname, NULL);
  186. ret = LoadLibrary(fullpath);
  187. sfree(fullpath);
  188. return ret;
  189. }
  190. /*
  191. * A tree234 containing mappings from system error codes to strings.
  192. */
  193. struct errstring {
  194. int error;
  195. char *text;
  196. };
  197. static int errstring_find(void *av, void *bv)
  198. {
  199. int *a = (int *)av;
  200. struct errstring *b = (struct errstring *)bv;
  201. if (*a < b->error)
  202. return -1;
  203. if (*a > b->error)
  204. return +1;
  205. return 0;
  206. }
  207. static int errstring_compare(void *av, void *bv)
  208. {
  209. struct errstring *a = (struct errstring *)av;
  210. return errstring_find(&a->error, bv);
  211. }
  212. static tree234 *errstrings = NULL;
  213. const char *win_strerror(int error)
  214. {
  215. struct errstring *es;
  216. if (!errstrings)
  217. errstrings = newtree234(errstring_compare);
  218. es = find234(errstrings, &error, errstring_find);
  219. if (!es) {
  220. char msgtext[65536]; /* maximum size for FormatMessage is 64K */
  221. es = snew(struct errstring);
  222. es->error = error;
  223. if (!FormatMessage((FORMAT_MESSAGE_FROM_SYSTEM |
  224. FORMAT_MESSAGE_IGNORE_INSERTS), NULL, error,
  225. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  226. msgtext, lenof(msgtext)-1, NULL)) {
  227. sprintf(msgtext,
  228. "(unable to format: FormatMessage returned %u)",
  229. (unsigned int)GetLastError());
  230. } else {
  231. int len = strlen(msgtext);
  232. if (len > 0 && msgtext[len-1] == '\n')
  233. msgtext[len-1] = '\0';
  234. }
  235. es->text = dupprintf("Error %d: %s", error, msgtext);
  236. add234(errstrings, es);
  237. }
  238. return es->text;
  239. }
  240. #ifdef DEBUG
  241. static FILE *debug_fp = NULL;
  242. static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
  243. static int debug_got_console = 0;
  244. void dputs(const char *buf)
  245. {
  246. DWORD dw;
  247. if (!debug_got_console) {
  248. if (AllocConsole()) {
  249. debug_got_console = 1;
  250. debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);
  251. }
  252. }
  253. if (!debug_fp) {
  254. debug_fp = fopen("debug.log", "w");
  255. }
  256. if (debug_hdl != INVALID_HANDLE_VALUE) {
  257. WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);
  258. }
  259. fputs(buf, debug_fp);
  260. fflush(debug_fp);
  261. }
  262. #endif
  263. #ifdef MINEFIELD
  264. /*
  265. * Minefield - a Windows equivalent for Electric Fence
  266. */
  267. #define PAGESIZE 4096
  268. /*
  269. * Design:
  270. *
  271. * We start by reserving as much virtual address space as Windows
  272. * will sensibly (or not sensibly) let us have. We flag it all as
  273. * invalid memory.
  274. *
  275. * Any allocation attempt is satisfied by committing one or more
  276. * pages, with an uncommitted page on either side. The returned
  277. * memory region is jammed up against the _end_ of the pages.
  278. *
  279. * Freeing anything causes instantaneous decommitment of the pages
  280. * involved, so stale pointers are caught as soon as possible.
  281. */
  282. static int minefield_initialised = 0;
  283. static void *minefield_region = NULL;
  284. static long minefield_size = 0;
  285. static long minefield_npages = 0;
  286. static long minefield_curpos = 0;
  287. static unsigned short *minefield_admin = NULL;
  288. static void *minefield_pages = NULL;
  289. static void minefield_admin_hide(int hide)
  290. {
  291. int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;
  292. VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);
  293. }
  294. static void minefield_init(void)
  295. {
  296. int size;
  297. int admin_size;
  298. int i;
  299. for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {
  300. minefield_region = VirtualAlloc(NULL, size,
  301. MEM_RESERVE, PAGE_NOACCESS);
  302. if (minefield_region)
  303. break;
  304. }
  305. minefield_size = size;
  306. /*
  307. * Firstly, allocate a section of that to be the admin block.
  308. * We'll need a two-byte field for each page.
  309. */
  310. minefield_admin = minefield_region;
  311. minefield_npages = minefield_size / PAGESIZE;
  312. admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);
  313. minefield_npages = (minefield_size - admin_size) / PAGESIZE;
  314. minefield_pages = (char *) minefield_region + admin_size;
  315. /*
  316. * Commit the admin region.
  317. */
  318. VirtualAlloc(minefield_admin, minefield_npages * 2,
  319. MEM_COMMIT, PAGE_READWRITE);
  320. /*
  321. * Mark all pages as unused (0xFFFF).
  322. */
  323. for (i = 0; i < minefield_npages; i++)
  324. minefield_admin[i] = 0xFFFF;
  325. /*
  326. * Hide the admin region.
  327. */
  328. minefield_admin_hide(1);
  329. minefield_initialised = 1;
  330. }
  331. static void minefield_bomb(void)
  332. {
  333. div(1, *(int *) minefield_pages);
  334. }
  335. static void *minefield_alloc(int size)
  336. {
  337. int npages;
  338. int pos, lim, region_end, region_start;
  339. int start;
  340. int i;
  341. npages = (size + PAGESIZE - 1) / PAGESIZE;
  342. minefield_admin_hide(0);
  343. /*
  344. * Search from current position until we find a contiguous
  345. * bunch of npages+2 unused pages.
  346. */
  347. pos = minefield_curpos;
  348. lim = minefield_npages;
  349. while (1) {
  350. /* Skip over used pages. */
  351. while (pos < lim && minefield_admin[pos] != 0xFFFF)
  352. pos++;
  353. /* Count unused pages. */
  354. start = pos;
  355. while (pos < lim && pos - start < npages + 2 &&
  356. minefield_admin[pos] == 0xFFFF)
  357. pos++;
  358. if (pos - start == npages + 2)
  359. break;
  360. /* If we've reached the limit, reset the limit or stop. */
  361. if (pos >= lim) {
  362. if (lim == minefield_npages) {
  363. /* go round and start again at zero */
  364. lim = minefield_curpos;
  365. pos = 0;
  366. } else {
  367. minefield_admin_hide(1);
  368. return NULL;
  369. }
  370. }
  371. }
  372. minefield_curpos = pos - 1;
  373. /*
  374. * We have npages+2 unused pages starting at start. We leave
  375. * the first and last of these alone and use the rest.
  376. */
  377. region_end = (start + npages + 1) * PAGESIZE;
  378. region_start = region_end - size;
  379. /* FIXME: could align here if we wanted */
  380. /*
  381. * Update the admin region.
  382. */
  383. for (i = start + 2; i < start + npages + 1; i++)
  384. minefield_admin[i] = 0xFFFE; /* used but no region starts here */
  385. minefield_admin[start + 1] = region_start % PAGESIZE;
  386. minefield_admin_hide(1);
  387. VirtualAlloc((char *) minefield_pages + region_start, size,
  388. MEM_COMMIT, PAGE_READWRITE);
  389. return (char *) minefield_pages + region_start;
  390. }
  391. static void minefield_free(void *ptr)
  392. {
  393. int region_start, i, j;
  394. minefield_admin_hide(0);
  395. region_start = (char *) ptr - (char *) minefield_pages;
  396. i = region_start / PAGESIZE;
  397. if (i < 0 || i >= minefield_npages ||
  398. minefield_admin[i] != region_start % PAGESIZE)
  399. minefield_bomb();
  400. for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {
  401. minefield_admin[j] = 0xFFFF;
  402. }
  403. VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);
  404. minefield_admin_hide(1);
  405. }
  406. static int minefield_get_size(void *ptr)
  407. {
  408. int region_start, i, j;
  409. minefield_admin_hide(0);
  410. region_start = (char *) ptr - (char *) minefield_pages;
  411. i = region_start / PAGESIZE;
  412. if (i < 0 || i >= minefield_npages ||
  413. minefield_admin[i] != region_start % PAGESIZE)
  414. minefield_bomb();
  415. for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);
  416. minefield_admin_hide(1);
  417. return j * PAGESIZE - region_start;
  418. }
  419. void *minefield_c_malloc(size_t size)
  420. {
  421. if (!minefield_initialised)
  422. minefield_init();
  423. return minefield_alloc(size);
  424. }
  425. void minefield_c_free(void *p)
  426. {
  427. if (!minefield_initialised)
  428. minefield_init();
  429. minefield_free(p);
  430. }
  431. /*
  432. * realloc _always_ moves the chunk, for rapid detection of code
  433. * that assumes it won't.
  434. */
  435. void *minefield_c_realloc(void *p, size_t size)
  436. {
  437. size_t oldsize;
  438. void *q;
  439. if (!minefield_initialised)
  440. minefield_init();
  441. q = minefield_alloc(size);
  442. oldsize = minefield_get_size(p);
  443. memcpy(q, p, (oldsize < size ? oldsize : size));
  444. minefield_free(p);
  445. return q;
  446. }
  447. #endif /* MINEFIELD */
  448. FontSpec *fontspec_new(const char *name,
  449. int bold, int height, int charset)
  450. {
  451. FontSpec *f = snew(FontSpec);
  452. f->name = dupstr(name);
  453. f->isbold = bold;
  454. f->height = height;
  455. f->charset = charset;
  456. return f;
  457. }
  458. FontSpec *fontspec_copy(const FontSpec *f)
  459. {
  460. return fontspec_new(f->name, f->isbold, f->height, f->charset);
  461. }
  462. void fontspec_free(FontSpec *f)
  463. {
  464. sfree(f->name);
  465. sfree(f);
  466. }
  467. int fontspec_serialise(FontSpec *f, void *vdata)
  468. {
  469. char *data = (char *)vdata;
  470. int len = strlen(f->name) + 1; /* include trailing NUL */
  471. if (data) {
  472. strcpy(data, f->name);
  473. PUT_32BIT_MSB_FIRST(data + len, f->isbold);
  474. PUT_32BIT_MSB_FIRST(data + len + 4, f->height);
  475. PUT_32BIT_MSB_FIRST(data + len + 8, f->charset);
  476. }
  477. return len + 12; /* also include three 4-byte ints */
  478. }
  479. FontSpec *fontspec_deserialise(void *vdata, int maxsize, int *used)
  480. {
  481. char *data = (char *)vdata;
  482. char *end;
  483. if (maxsize < 13)
  484. return NULL;
  485. end = memchr(data, '\0', maxsize-12);
  486. if (!end)
  487. return NULL;
  488. end++;
  489. *used = end - data + 12;
  490. return fontspec_new(data,
  491. GET_32BIT_MSB_FIRST(end),
  492. GET_32BIT_MSB_FIRST(end + 4),
  493. GET_32BIT_MSB_FIRST(end + 8));
  494. }