winmisc.c 14 KB

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