Upgrade tortoiseplink to putty 9002
[TortoiseGit.git] / src / TortoisePlink / Windows / WINMISC.C
blobe70e77efa1c3ac20a7e1aa609c172a65c0dd1dd1
1 /*\r
2  * winmisc.c: miscellaneous Windows-specific things\r
3  */\r
4 \r
5 #include <stdio.h>\r
6 #include <stdlib.h>\r
7 #include "putty.h"\r
8 #include <security.h>\r
9 \r
10 OSVERSIONINFO osVersion;\r
12 char *platform_get_x_display(void) {\r
13     /* We may as well check for DISPLAY in case it's useful. */\r
14     return dupstr(getenv("DISPLAY"));\r
15 }\r
17 Filename filename_from_str(const char *str)\r
18 {\r
19     Filename ret;\r
20     strncpy(ret.path, str, sizeof(ret.path));\r
21     ret.path[sizeof(ret.path)-1] = '\0';\r
22     return ret;\r
23 }\r
25 const char *filename_to_str(const Filename *fn)\r
26 {\r
27     return fn->path;\r
28 }\r
30 int filename_equal(Filename f1, Filename f2)\r
31 {\r
32     return !strcmp(f1.path, f2.path);\r
33 }\r
35 int filename_is_null(Filename fn)\r
36 {\r
37     return !*fn.path;\r
38 }\r
40 char *get_username(void)\r
41 {\r
42     DWORD namelen;\r
43     char *user;\r
44     int got_username = FALSE;\r
45     DECL_WINDOWS_FUNCTION(static, BOOLEAN, GetUserNameExA,\r
46                           (EXTENDED_NAME_FORMAT, LPSTR, PULONG));\r
48     {\r
49         static int tried_usernameex = FALSE;\r
50         if (!tried_usernameex) {\r
51             /* Not available on Win9x, so load dynamically */\r
52             HMODULE secur32 = load_system32_dll("secur32.dll");\r
53             GET_WINDOWS_FUNCTION(secur32, GetUserNameExA);\r
54             tried_usernameex = TRUE;\r
55         }\r
56     }\r
58     if (p_GetUserNameExA) {\r
59         /*\r
60          * If available, use the principal -- this avoids the problem\r
61          * that the local username is case-insensitive but Kerberos\r
62          * usernames are case-sensitive.\r
63          */\r
65         /* Get the length */\r
66         namelen = 0;\r
67         (void) p_GetUserNameExA(NameUserPrincipal, NULL, &namelen);\r
69         user = snewn(namelen, char);\r
70         got_username = p_GetUserNameExA(NameUserPrincipal, user, &namelen);\r
71         if (got_username) {\r
72             char *p = strchr(user, '@');\r
73             if (p) *p = 0;\r
74         } else {\r
75             sfree(user);\r
76         }\r
77     }\r
79     if (!got_username) {\r
80         /* Fall back to local user name */\r
81         namelen = 0;\r
82         if (GetUserName(NULL, &namelen) == FALSE) {\r
83             /*\r
84              * Apparently this doesn't work at least on Windows XP SP2.\r
85              * Thus assume a maximum of 256. It will fail again if it\r
86              * doesn't fit.\r
87              */\r
88             namelen = 256;\r
89         }\r
91         user = snewn(namelen, char);\r
92         got_username = GetUserName(user, &namelen);\r
93         if (!got_username) {\r
94             sfree(user);\r
95         }\r
96     }\r
98     return got_username ? user : NULL;\r
99 }\r
101 BOOL init_winver(void)\r
103     ZeroMemory(&osVersion, sizeof(osVersion));\r
104     osVersion.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);\r
105     return GetVersionEx ( (OSVERSIONINFO *) &osVersion);\r
108 HMODULE load_system32_dll(const char *libname)\r
110     /*\r
111      * Wrapper function to load a DLL out of c:\windows\system32\r
112      * without going through the full DLL search path. (Hence no\r
113      * attack is possible by placing a substitute DLL earlier on that\r
114      * path.)\r
115      */\r
116     static char *sysdir = NULL;\r
117     char *fullpath;\r
118     HMODULE ret;\r
120     if (!sysdir) {\r
121         int size = 0, len;\r
122         do {\r
123             size = 3*size/2 + 512;\r
124             sysdir = sresize(sysdir, size, char);\r
125             len = GetSystemDirectory(sysdir, size);\r
126         } while (len >= size);\r
127     }\r
129     fullpath = dupcat(sysdir, "\\", libname, NULL);\r
130     ret = LoadLibrary(fullpath);\r
131     sfree(fullpath);\r
132     return ret;\r
135 #ifdef DEBUG\r
136 static FILE *debug_fp = NULL;\r
137 static HANDLE debug_hdl = INVALID_HANDLE_VALUE;\r
138 static int debug_got_console = 0;\r
140 void dputs(char *buf)\r
142     DWORD dw;\r
144     if (!debug_got_console) {\r
145         if (AllocConsole()) {\r
146             debug_got_console = 1;\r
147             debug_hdl = GetStdHandle(STD_OUTPUT_HANDLE);\r
148         }\r
149     }\r
150     if (!debug_fp) {\r
151         debug_fp = fopen("debug.log", "w");\r
152     }\r
154     if (debug_hdl != INVALID_HANDLE_VALUE) {\r
155         WriteFile(debug_hdl, buf, strlen(buf), &dw, NULL);\r
156     }\r
157     fputs(buf, debug_fp);\r
158     fflush(debug_fp);\r
160 #endif\r
162 #ifdef MINEFIELD\r
163 /*\r
164  * Minefield - a Windows equivalent for Electric Fence\r
165  */\r
167 #define PAGESIZE 4096\r
169 /*\r
170  * Design:\r
171  * \r
172  * We start by reserving as much virtual address space as Windows\r
173  * will sensibly (or not sensibly) let us have. We flag it all as\r
174  * invalid memory.\r
175  * \r
176  * Any allocation attempt is satisfied by committing one or more\r
177  * pages, with an uncommitted page on either side. The returned\r
178  * memory region is jammed up against the _end_ of the pages.\r
179  * \r
180  * Freeing anything causes instantaneous decommitment of the pages\r
181  * involved, so stale pointers are caught as soon as possible.\r
182  */\r
184 static int minefield_initialised = 0;\r
185 static void *minefield_region = NULL;\r
186 static long minefield_size = 0;\r
187 static long minefield_npages = 0;\r
188 static long minefield_curpos = 0;\r
189 static unsigned short *minefield_admin = NULL;\r
190 static void *minefield_pages = NULL;\r
192 static void minefield_admin_hide(int hide)\r
194     int access = hide ? PAGE_NOACCESS : PAGE_READWRITE;\r
195     VirtualProtect(minefield_admin, minefield_npages * 2, access, NULL);\r
198 static void minefield_init(void)\r
200     int size;\r
201     int admin_size;\r
202     int i;\r
204     for (size = 0x40000000; size > 0; size = ((size >> 3) * 7) & ~0xFFF) {\r
205         minefield_region = VirtualAlloc(NULL, size,\r
206                                         MEM_RESERVE, PAGE_NOACCESS);\r
207         if (minefield_region)\r
208             break;\r
209     }\r
210     minefield_size = size;\r
212     /*\r
213      * Firstly, allocate a section of that to be the admin block.\r
214      * We'll need a two-byte field for each page.\r
215      */\r
216     minefield_admin = minefield_region;\r
217     minefield_npages = minefield_size / PAGESIZE;\r
218     admin_size = (minefield_npages * 2 + PAGESIZE - 1) & ~(PAGESIZE - 1);\r
219     minefield_npages = (minefield_size - admin_size) / PAGESIZE;\r
220     minefield_pages = (char *) minefield_region + admin_size;\r
222     /*\r
223      * Commit the admin region.\r
224      */\r
225     VirtualAlloc(minefield_admin, minefield_npages * 2,\r
226                  MEM_COMMIT, PAGE_READWRITE);\r
228     /*\r
229      * Mark all pages as unused (0xFFFF).\r
230      */\r
231     for (i = 0; i < minefield_npages; i++)\r
232         minefield_admin[i] = 0xFFFF;\r
234     /*\r
235      * Hide the admin region.\r
236      */\r
237     minefield_admin_hide(1);\r
239     minefield_initialised = 1;\r
242 static void minefield_bomb(void)\r
244     div(1, *(int *) minefield_pages);\r
247 static void *minefield_alloc(int size)\r
249     int npages;\r
250     int pos, lim, region_end, region_start;\r
251     int start;\r
252     int i;\r
254     npages = (size + PAGESIZE - 1) / PAGESIZE;\r
256     minefield_admin_hide(0);\r
258     /*\r
259      * Search from current position until we find a contiguous\r
260      * bunch of npages+2 unused pages.\r
261      */\r
262     pos = minefield_curpos;\r
263     lim = minefield_npages;\r
264     while (1) {\r
265         /* Skip over used pages. */\r
266         while (pos < lim && minefield_admin[pos] != 0xFFFF)\r
267             pos++;\r
268         /* Count unused pages. */\r
269         start = pos;\r
270         while (pos < lim && pos - start < npages + 2 &&\r
271                minefield_admin[pos] == 0xFFFF)\r
272             pos++;\r
273         if (pos - start == npages + 2)\r
274             break;\r
275         /* If we've reached the limit, reset the limit or stop. */\r
276         if (pos >= lim) {\r
277             if (lim == minefield_npages) {\r
278                 /* go round and start again at zero */\r
279                 lim = minefield_curpos;\r
280                 pos = 0;\r
281             } else {\r
282                 minefield_admin_hide(1);\r
283                 return NULL;\r
284             }\r
285         }\r
286     }\r
288     minefield_curpos = pos - 1;\r
290     /*\r
291      * We have npages+2 unused pages starting at start. We leave\r
292      * the first and last of these alone and use the rest.\r
293      */\r
294     region_end = (start + npages + 1) * PAGESIZE;\r
295     region_start = region_end - size;\r
296     /* FIXME: could align here if we wanted */\r
298     /*\r
299      * Update the admin region.\r
300      */\r
301     for (i = start + 2; i < start + npages + 1; i++)\r
302         minefield_admin[i] = 0xFFFE;   /* used but no region starts here */\r
303     minefield_admin[start + 1] = region_start % PAGESIZE;\r
305     minefield_admin_hide(1);\r
307     VirtualAlloc((char *) minefield_pages + region_start, size,\r
308                  MEM_COMMIT, PAGE_READWRITE);\r
309     return (char *) minefield_pages + region_start;\r
312 static void minefield_free(void *ptr)\r
314     int region_start, i, j;\r
316     minefield_admin_hide(0);\r
318     region_start = (char *) ptr - (char *) minefield_pages;\r
319     i = region_start / PAGESIZE;\r
320     if (i < 0 || i >= minefield_npages ||\r
321         minefield_admin[i] != region_start % PAGESIZE)\r
322         minefield_bomb();\r
323     for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++) {\r
324         minefield_admin[j] = 0xFFFF;\r
325     }\r
327     VirtualFree(ptr, j * PAGESIZE - region_start, MEM_DECOMMIT);\r
329     minefield_admin_hide(1);\r
332 static int minefield_get_size(void *ptr)\r
334     int region_start, i, j;\r
336     minefield_admin_hide(0);\r
338     region_start = (char *) ptr - (char *) minefield_pages;\r
339     i = region_start / PAGESIZE;\r
340     if (i < 0 || i >= minefield_npages ||\r
341         minefield_admin[i] != region_start % PAGESIZE)\r
342         minefield_bomb();\r
343     for (j = i; j < minefield_npages && minefield_admin[j] != 0xFFFF; j++);\r
345     minefield_admin_hide(1);\r
347     return j * PAGESIZE - region_start;\r
350 void *minefield_c_malloc(size_t size)\r
352     if (!minefield_initialised)\r
353         minefield_init();\r
354     return minefield_alloc(size);\r
357 void minefield_c_free(void *p)\r
359     if (!minefield_initialised)\r
360         minefield_init();\r
361     minefield_free(p);\r
364 /*\r
365  * realloc _always_ moves the chunk, for rapid detection of code\r
366  * that assumes it won't.\r
367  */\r
368 void *minefield_c_realloc(void *p, size_t size)\r
370     size_t oldsize;\r
371     void *q;\r
372     if (!minefield_initialised)\r
373         minefield_init();\r
374     q = minefield_alloc(size);\r
375     oldsize = minefield_get_size(p);\r
376     memcpy(q, p, (oldsize < size ? oldsize : size));\r
377     minefield_free(p);\r
378     return q;\r
381 #endif                          /* MINEFIELD */\r