source: filezilla/trunk/fuentes/src/putty/windows/winmisc.c @ 3185

Last change on this file since 3185 was 3185, checked in by jrpelegrina, 2 years ago

Update new version: 3.15.02

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