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