CPatch: New memory management
[TortoiseGit.git] / src / TortoisePlink / MISC.C
blob492741e7252bb196078d898d9919954fcd54ff2d
1 /*\r
2  * Platform-independent routines shared between all PuTTY programs.\r
3  */\r
4 \r
5 #include <stdio.h>\r
6 #include <stdlib.h>\r
7 #include <stdarg.h>\r
8 #include <limits.h>\r
9 #include <ctype.h>\r
10 #include <assert.h>\r
11 #include "putty.h"\r
12 #include "misc.h"\r
14 /*\r
15  * Parse a string block size specification. This is approximately a\r
16  * subset of the block size specs supported by GNU fileutils:\r
17  *  "nk" = n kilobytes\r
18  *  "nM" = n megabytes\r
19  *  "nG" = n gigabytes\r
20  * All numbers are decimal, and suffixes refer to powers of two.\r
21  * Case-insensitive.\r
22  */\r
23 unsigned long parse_blocksize(const char *bs)\r
24 {\r
25     char *suf;\r
26     unsigned long r = strtoul(bs, &suf, 10);\r
27     if (*suf != '\0') {\r
28         while (*suf && isspace((unsigned char)*suf)) suf++;\r
29         switch (*suf) {\r
30           case 'k': case 'K':\r
31             r *= 1024ul;\r
32             break;\r
33           case 'm': case 'M':\r
34             r *= 1024ul * 1024ul;\r
35             break;\r
36           case 'g': case 'G':\r
37             r *= 1024ul * 1024ul * 1024ul;\r
38             break;\r
39           case '\0':\r
40           default:\r
41             break;\r
42         }\r
43     }\r
44     return r;\r
45 }\r
47 /*\r
48  * Parse a ^C style character specification.\r
49  * Returns NULL in `next' if we didn't recognise it as a control character,\r
50  * in which case `c' should be ignored.\r
51  * The precise current parsing is an oddity inherited from the terminal\r
52  * answerback-string parsing code. All sequences start with ^; all except\r
53  * ^<123> are two characters. The ones that are worth keeping are probably:\r
54  *   ^?             127\r
55  *   ^@A-Z[\]^_     0-31\r
56  *   a-z            1-26\r
57  *   <num>          specified by number (decimal, 0octal, 0xHEX)\r
58  *   ~              ^ escape\r
59  */\r
60 char ctrlparse(char *s, char **next)\r
61 {\r
62     char c = 0;\r
63     if (*s != '^') {\r
64         *next = NULL;\r
65     } else {\r
66         s++;\r
67         if (*s == '\0') {\r
68             *next = NULL;\r
69         } else if (*s == '<') {\r
70             s++;\r
71             c = (char)strtol(s, next, 0);\r
72             if ((*next == s) || (**next != '>')) {\r
73                 c = 0;\r
74                 *next = NULL;\r
75             } else\r
76                 (*next)++;\r
77         } else if (*s >= 'a' && *s <= 'z') {\r
78             c = (*s - ('a' - 1));\r
79             *next = s+1;\r
80         } else if ((*s >= '@' && *s <= '_') || *s == '?' || (*s & 0x80)) {\r
81             c = ('@' ^ *s);\r
82             *next = s+1;\r
83         } else if (*s == '~') {\r
84             c = '^';\r
85             *next = s+1;\r
86         }\r
87     }\r
88     return c;\r
89 }\r
91 /*\r
92  * Find a character in a string, unless it's a colon contained within\r
93  * square brackets. Used for untangling strings of the form\r
94  * 'host:port', where host can be an IPv6 literal.\r
95  *\r
96  * We provide several variants of this function, with semantics like\r
97  * various standard string.h functions.\r
98  */\r
99 static const char *host_strchr_internal(const char *s, const char *set,\r
100                                         int first)\r
102     int brackets = 0;\r
103     const char *ret = NULL;\r
105     while (1) {\r
106         if (!*s)\r
107             return ret;\r
109         if (*s == '[')\r
110             brackets++;\r
111         else if (*s == ']' && brackets > 0)\r
112             brackets--;\r
113         else if (brackets && *s == ':')\r
114             /* never match */ ;\r
115         else if (strchr(set, *s)) {\r
116             ret = s;\r
117             if (first)\r
118                 return ret;\r
119         }\r
121         s++;\r
122     }\r
124 size_t host_strcspn(const char *s, const char *set)\r
126     const char *answer = host_strchr_internal(s, set, TRUE);\r
127     if (answer)\r
128         return answer - s;\r
129     else\r
130         return strlen(s);\r
132 char *host_strchr(const char *s, int c)\r
134     char set[2];\r
135     set[0] = c;\r
136     set[1] = '\0';\r
137     return (char *) host_strchr_internal(s, set, TRUE);\r
139 char *host_strrchr(const char *s, int c)\r
141     char set[2];\r
142     set[0] = c;\r
143     set[1] = '\0';\r
144     return (char *) host_strchr_internal(s, set, FALSE);\r
147 #ifdef TEST_HOST_STRFOO\r
148 int main(void)\r
150     int passes = 0, fails = 0;\r
152 #define TEST1(func, string, arg2, suffix, result) do                    \\r
153     {                                                                   \\r
154         const char *str = string;                                       \\r
155         unsigned ret = func(string, arg2) suffix;                       \\r
156         if (ret == result) {                                            \\r
157             passes++;                                                   \\r
158         } else {                                                        \\r
159             printf("fail: %s(%s,%s)%s = %u, expected %u\n",             \\r
160                    #func, #string, #arg2, #suffix, ret,                 \\r
161                    (unsigned)result);                                   \\r
162             fails++;                                                    \\r
163         }                                                               \\r
164 } while (0)\r
166     TEST1(host_strchr, "[1:2:3]:4:5", ':', -str, 7);\r
167     TEST1(host_strrchr, "[1:2:3]:4:5", ':', -str, 9);\r
168     TEST1(host_strcspn, "[1:2:3]:4:5", "/:",, 7);\r
169     TEST1(host_strchr, "[1:2:3]", ':', == NULL, 1);\r
170     TEST1(host_strrchr, "[1:2:3]", ':', == NULL, 1);\r
171     TEST1(host_strcspn, "[1:2:3]", "/:",, 7);\r
172     TEST1(host_strcspn, "[1:2/3]", "/:",, 4);\r
173     TEST1(host_strcspn, "[1:2:3]/", "/:",, 7);\r
175     printf("passed %d failed %d total %d\n", passes, fails, passes+fails);\r
176     return fails != 0 ? 1 : 0;\r
178 /* Stubs to stop the rest of this module causing compile failures. */\r
179 void modalfatalbox(const char *fmt, ...) {}\r
180 int conf_get_int(Conf *conf, int primary) { return 0; }\r
181 char *conf_get_str(Conf *conf, int primary) { return NULL; }\r
182 #endif /* TEST_HOST_STRFOO */\r
184 /*\r
185  * Trim square brackets off the outside of an IPv6 address literal.\r
186  * Leave all other strings unchanged. Returns a fresh dynamically\r
187  * allocated string.\r
188  */\r
189 char *host_strduptrim(const char *s)\r
191     if (s[0] == '[') {\r
192         const char *p = s+1;\r
193         int colons = 0;\r
194         while (*p && *p != ']') {\r
195             if (isxdigit((unsigned char)*p))\r
196                 /* OK */;\r
197             else if (*p == ':')\r
198                 colons++;\r
199             else\r
200                 break;\r
201             p++;\r
202         }\r
203         if (*p == ']' && !p[1] && colons > 1) {\r
204             /*\r
205              * This looks like an IPv6 address literal (hex digits and\r
206              * at least two colons, contained in square brackets).\r
207              * Trim off the brackets.\r
208              */\r
209             return dupprintf("%.*s", (int)(p - (s+1)), s+1);\r
210         }\r
211     }\r
213     /*\r
214      * Any other shape of string is simply duplicated.\r
215      */\r
216     return dupstr(s);\r
219 prompts_t *new_prompts(void *frontend)\r
221     prompts_t *p = snew(prompts_t);\r
222     p->prompts = NULL;\r
223     p->n_prompts = 0;\r
224     p->frontend = frontend;\r
225     p->data = NULL;\r
226     p->to_server = TRUE; /* to be on the safe side */\r
227     p->name = p->instruction = NULL;\r
228     p->name_reqd = p->instr_reqd = FALSE;\r
229     return p;\r
231 void add_prompt(prompts_t *p, char *promptstr, int echo)\r
233     prompt_t *pr = snew(prompt_t);\r
234     pr->prompt = promptstr;\r
235     pr->echo = echo;\r
236     pr->result = NULL;\r
237     pr->resultsize = 0;\r
238     p->n_prompts++;\r
239     p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *);\r
240     p->prompts[p->n_prompts-1] = pr;\r
242 void prompt_ensure_result_size(prompt_t *pr, int newlen)\r
244     if ((int)pr->resultsize < newlen) {\r
245         char *newbuf;\r
246         newlen = newlen * 5 / 4 + 512; /* avoid too many small allocs */\r
248         /*\r
249          * We don't use sresize / realloc here, because we will be\r
250          * storing sensitive stuff like passwords in here, and we want\r
251          * to make sure that the data doesn't get copied around in\r
252          * memory without the old copy being destroyed.\r
253          */\r
254         newbuf = snewn(newlen, char);\r
255         memcpy(newbuf, pr->result, pr->resultsize);\r
256         smemclr(pr->result, pr->resultsize);\r
257         sfree(pr->result);\r
258         pr->result = newbuf;\r
259         pr->resultsize = newlen;\r
260     }\r
262 void prompt_set_result(prompt_t *pr, const char *newstr)\r
264     prompt_ensure_result_size(pr, strlen(newstr) + 1);\r
265     strcpy(pr->result, newstr);\r
267 void free_prompts(prompts_t *p)\r
269     size_t i;\r
270     for (i=0; i < p->n_prompts; i++) {\r
271         prompt_t *pr = p->prompts[i];\r
272         smemclr(pr->result, pr->resultsize); /* burn the evidence */\r
273         sfree(pr->result);\r
274         sfree(pr->prompt);\r
275         sfree(pr);\r
276     }\r
277     sfree(p->prompts);\r
278     sfree(p->name);\r
279     sfree(p->instruction);\r
280     sfree(p);\r
283 /* ----------------------------------------------------------------------\r
284  * String handling routines.\r
285  */\r
287 char *dupstr(const char *s)\r
289     char *p = NULL;\r
290     if (s) {\r
291         int len = strlen(s);\r
292         p = snewn(len + 1, char);\r
293         strcpy(p, s);\r
294     }\r
295     return p;\r
298 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */\r
299 char *dupcat(const char *s1, ...)\r
301     int len;\r
302     char *p, *q, *sn;\r
303     va_list ap;\r
305     len = strlen(s1);\r
306     va_start(ap, s1);\r
307     while (1) {\r
308         sn = va_arg(ap, char *);\r
309         if (!sn)\r
310             break;\r
311         len += strlen(sn);\r
312     }\r
313     va_end(ap);\r
315     p = snewn(len + 1, char);\r
316     strcpy(p, s1);\r
317     q = p + strlen(p);\r
319     va_start(ap, s1);\r
320     while (1) {\r
321         sn = va_arg(ap, char *);\r
322         if (!sn)\r
323             break;\r
324         strcpy(q, sn);\r
325         q += strlen(q);\r
326     }\r
327     va_end(ap);\r
329     return p;\r
332 void burnstr(char *string)             /* sfree(str), only clear it first */\r
334     if (string) {\r
335         smemclr(string, strlen(string));\r
336         sfree(string);\r
337     }\r
340 int toint(unsigned u)\r
342     /*\r
343      * Convert an unsigned to an int, without running into the\r
344      * undefined behaviour which happens by the strict C standard if\r
345      * the value overflows. You'd hope that sensible compilers would\r
346      * do the sensible thing in response to a cast, but actually I\r
347      * don't trust modern compilers not to do silly things like\r
348      * assuming that _obviously_ you wouldn't have caused an overflow\r
349      * and so they can elide an 'if (i < 0)' test immediately after\r
350      * the cast.\r
351      *\r
352      * Sensible compilers ought of course to optimise this entire\r
353      * function into 'just return the input value'!\r
354      */\r
355     if (u <= (unsigned)INT_MAX)\r
356         return (int)u;\r
357     else if (u >= (unsigned)INT_MIN)   /* wrap in cast _to_ unsigned is OK */\r
358         return INT_MIN + (int)(u - (unsigned)INT_MIN);\r
359     else\r
360         return INT_MIN; /* fallback; should never occur on binary machines */\r
363 /*\r
364  * Do an sprintf(), but into a custom-allocated buffer.\r
365  * \r
366  * Currently I'm doing this via vsnprintf. This has worked so far,\r
367  * but it's not good, because vsnprintf is not available on all\r
368  * platforms. There's an ifdef to use `_vsnprintf', which seems\r
369  * to be the local name for it on Windows. Other platforms may\r
370  * lack it completely, in which case it'll be time to rewrite\r
371  * this function in a totally different way.\r
372  * \r
373  * The only `properly' portable solution I can think of is to\r
374  * implement my own format string scanner, which figures out an\r
375  * upper bound for the length of each formatting directive,\r
376  * allocates the buffer as it goes along, and calls sprintf() to\r
377  * actually process each directive. If I ever need to actually do\r
378  * this, some caveats:\r
379  * \r
380  *  - It's very hard to find a reliable upper bound for\r
381  *    floating-point values. %f, in particular, when supplied with\r
382  *    a number near to the upper or lower limit of representable\r
383  *    numbers, could easily take several hundred characters. It's\r
384  *    probably feasible to predict this statically using the\r
385  *    constants in <float.h>, or even to predict it dynamically by\r
386  *    looking at the exponent of the specific float provided, but\r
387  *    it won't be fun.\r
388  * \r
389  *  - Don't forget to _check_, after calling sprintf, that it's\r
390  *    used at most the amount of space we had available.\r
391  * \r
392  *  - Fault any formatting directive we don't fully understand. The\r
393  *    aim here is to _guarantee_ that we never overflow the buffer,\r
394  *    because this is a security-critical function. If we see a\r
395  *    directive we don't know about, we should panic and die rather\r
396  *    than run any risk.\r
397  */\r
398 static char *dupvprintf_inner(char *buf, int oldlen, int *oldsize,\r
399                               const char *fmt, va_list ap)\r
401     int len, size, newsize;\r
403     assert(*oldsize >= oldlen);\r
404     size = *oldsize - oldlen;\r
405     if (size == 0) {\r
406         size = 512;\r
407         newsize = oldlen + size;\r
408         buf = sresize(buf, newsize, char);\r
409     } else {\r
410         newsize = *oldsize;\r
411     }\r
413     while (1) {\r
414 #if defined _WINDOWS && !defined __WINE__ && _MSC_VER < 1900 /* 1900 == VS2015 has real snprintf */\r
415 #define vsnprintf _vsnprintf\r
416 #endif\r
417 #ifdef va_copy\r
418         /* Use the `va_copy' macro mandated by C99, if present.\r
419          * XXX some environments may have this as __va_copy() */\r
420         va_list aq;\r
421         va_copy(aq, ap);\r
422         len = vsnprintf(buf + oldlen, size, fmt, aq);\r
423         va_end(aq);\r
424 #else\r
425         /* Ugh. No va_copy macro, so do something nasty.\r
426          * Technically, you can't reuse a va_list like this: it is left\r
427          * unspecified whether advancing a va_list pointer modifies its\r
428          * value or something it points to, so on some platforms calling\r
429          * vsnprintf twice on the same va_list might fail hideously\r
430          * (indeed, it has been observed to).\r
431          * XXX the autoconf manual suggests that using memcpy() will give\r
432          *     "maximum portability". */\r
433         len = vsnprintf(buf + oldlen, size, fmt, ap);\r
434 #endif\r
435         if (len >= 0 && len < size) {\r
436             /* This is the C99-specified criterion for snprintf to have\r
437              * been completely successful. */\r
438             *oldsize = newsize;\r
439             return buf;\r
440         } else if (len > 0) {\r
441             /* This is the C99 error condition: the returned length is\r
442              * the required buffer size not counting the NUL. */\r
443             size = len + 1;\r
444         } else {\r
445             /* This is the pre-C99 glibc error condition: <0 means the\r
446              * buffer wasn't big enough, so we enlarge it a bit and hope. */\r
447             size += 512;\r
448         }\r
449         newsize = oldlen + size;\r
450         buf = sresize(buf, newsize, char);\r
451     }\r
454 char *dupvprintf(const char *fmt, va_list ap)\r
456     int size = 0;\r
457     return dupvprintf_inner(NULL, 0, &size, fmt, ap);\r
459 char *dupprintf(const char *fmt, ...)\r
461     char *ret;\r
462     va_list ap;\r
463     va_start(ap, fmt);\r
464     ret = dupvprintf(fmt, ap);\r
465     va_end(ap);\r
466     return ret;\r
469 struct strbuf {\r
470     char *s;\r
471     int len, size;\r
472 };\r
473 strbuf *strbuf_new(void)\r
475     strbuf *buf = snew(strbuf);\r
476     buf->len = 0;\r
477     buf->size = 512;\r
478     buf->s = snewn(buf->size, char);\r
479     *buf->s = '\0';\r
480     return buf;\r
482 void strbuf_free(strbuf *buf)\r
484     sfree(buf->s);\r
485     sfree(buf);\r
487 char *strbuf_str(strbuf *buf)\r
489     return buf->s;\r
491 char *strbuf_to_str(strbuf *buf)\r
493     char *ret = buf->s;\r
494     sfree(buf);\r
495     return ret;\r
497 void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap)\r
499     buf->s = dupvprintf_inner(buf->s, buf->len, &buf->size, fmt, ap);\r
500     buf->len += strlen(buf->s + buf->len);\r
502 void strbuf_catf(strbuf *buf, const char *fmt, ...)\r
504     va_list ap;\r
505     va_start(ap, fmt);\r
506     strbuf_catfv(buf, fmt, ap);\r
507     va_end(ap);\r
510 /*\r
511  * Read an entire line of text from a file. Return a buffer\r
512  * malloced to be as big as necessary (caller must free).\r
513  */\r
514 char *fgetline(FILE *fp)\r
516     char *ret = snewn(512, char);\r
517     int size = 512, len = 0;\r
518     while (fgets(ret + len, size - len, fp)) {\r
519         len += strlen(ret + len);\r
520         if (len > 0 && ret[len-1] == '\n')\r
521             break;                     /* got a newline, we're done */\r
522         size = len + 512;\r
523         ret = sresize(ret, size, char);\r
524     }\r
525     if (len == 0) {                    /* first fgets returned NULL */\r
526         sfree(ret);\r
527         return NULL;\r
528     }\r
529     ret[len] = '\0';\r
530     return ret;\r
533 /*\r
534  * Perl-style 'chomp', for a line we just read with fgetline. Unlike\r
535  * Perl chomp, however, we're deliberately forgiving of strange\r
536  * line-ending conventions. Also we forgive NULL on input, so you can\r
537  * just write 'line = chomp(fgetline(fp));' and not bother checking\r
538  * for NULL until afterwards.\r
539  */\r
540 char *chomp(char *str)\r
542     if (str) {\r
543         int len = strlen(str);\r
544         while (len > 0 && (str[len-1] == '\r' || str[len-1] == '\n'))\r
545             len--;\r
546         str[len] = '\0';\r
547     }\r
548     return str;\r
551 /* ----------------------------------------------------------------------\r
552  * Core base64 encoding and decoding routines.\r
553  */\r
555 void base64_encode_atom(const unsigned char *data, int n, char *out)\r
557     static const char base64_chars[] =\r
558         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\r
560     unsigned word;\r
562     word = data[0] << 16;\r
563     if (n > 1)\r
564         word |= data[1] << 8;\r
565     if (n > 2)\r
566         word |= data[2];\r
567     out[0] = base64_chars[(word >> 18) & 0x3F];\r
568     out[1] = base64_chars[(word >> 12) & 0x3F];\r
569     if (n > 1)\r
570         out[2] = base64_chars[(word >> 6) & 0x3F];\r
571     else\r
572         out[2] = '=';\r
573     if (n > 2)\r
574         out[3] = base64_chars[word & 0x3F];\r
575     else\r
576         out[3] = '=';\r
579 int base64_decode_atom(const char *atom, unsigned char *out)\r
581     int vals[4];\r
582     int i, v, len;\r
583     unsigned word;\r
584     char c;\r
586     for (i = 0; i < 4; i++) {\r
587         c = atom[i];\r
588         if (c >= 'A' && c <= 'Z')\r
589             v = c - 'A';\r
590         else if (c >= 'a' && c <= 'z')\r
591             v = c - 'a' + 26;\r
592         else if (c >= '0' && c <= '9')\r
593             v = c - '0' + 52;\r
594         else if (c == '+')\r
595             v = 62;\r
596         else if (c == '/')\r
597             v = 63;\r
598         else if (c == '=')\r
599             v = -1;\r
600         else\r
601             return 0;                  /* invalid atom */\r
602         vals[i] = v;\r
603     }\r
605     if (vals[0] == -1 || vals[1] == -1)\r
606         return 0;\r
607     if (vals[2] == -1 && vals[3] != -1)\r
608         return 0;\r
610     if (vals[3] != -1)\r
611         len = 3;\r
612     else if (vals[2] != -1)\r
613         len = 2;\r
614     else\r
615         len = 1;\r
617     word = ((vals[0] << 18) |\r
618             (vals[1] << 12) | ((vals[2] & 0x3F) << 6) | (vals[3] & 0x3F));\r
619     out[0] = (word >> 16) & 0xFF;\r
620     if (len > 1)\r
621         out[1] = (word >> 8) & 0xFF;\r
622     if (len > 2)\r
623         out[2] = word & 0xFF;\r
624     return len;\r
627 /* ----------------------------------------------------------------------\r
628  * Generic routines to deal with send buffers: a linked list of\r
629  * smallish blocks, with the operations\r
630  * \r
631  *  - add an arbitrary amount of data to the end of the list\r
632  *  - remove the first N bytes from the list\r
633  *  - return a (pointer,length) pair giving some initial data in\r
634  *    the list, suitable for passing to a send or write system\r
635  *    call\r
636  *  - retrieve a larger amount of initial data from the list\r
637  *  - return the current size of the buffer chain in bytes\r
638  */\r
640 #define BUFFER_MIN_GRANULE  512\r
642 struct bufchain_granule {\r
643     struct bufchain_granule *next;\r
644     char *bufpos, *bufend, *bufmax;\r
645 };\r
647 void bufchain_init(bufchain *ch)\r
649     ch->head = ch->tail = NULL;\r
650     ch->buffersize = 0;\r
653 void bufchain_clear(bufchain *ch)\r
655     struct bufchain_granule *b;\r
656     while (ch->head) {\r
657         b = ch->head;\r
658         ch->head = ch->head->next;\r
659         sfree(b);\r
660     }\r
661     ch->tail = NULL;\r
662     ch->buffersize = 0;\r
665 int bufchain_size(bufchain *ch)\r
667     return ch->buffersize;\r
670 void bufchain_add(bufchain *ch, const void *data, int len)\r
672     const char *buf = (const char *)data;\r
674     if (len == 0) return;\r
676     ch->buffersize += len;\r
678     while (len > 0) {\r
679         if (ch->tail && ch->tail->bufend < ch->tail->bufmax) {\r
680             int copylen = min(len, ch->tail->bufmax - ch->tail->bufend);\r
681             memcpy(ch->tail->bufend, buf, copylen);\r
682             buf += copylen;\r
683             len -= copylen;\r
684             ch->tail->bufend += copylen;\r
685         }\r
686         if (len > 0) {\r
687             int grainlen =\r
688                 max(sizeof(struct bufchain_granule) + len, BUFFER_MIN_GRANULE);\r
689             struct bufchain_granule *newbuf;\r
690             newbuf = smalloc(grainlen);\r
691             newbuf->bufpos = newbuf->bufend =\r
692                 (char *)newbuf + sizeof(struct bufchain_granule);\r
693             newbuf->bufmax = (char *)newbuf + grainlen;\r
694             newbuf->next = NULL;\r
695             if (ch->tail)\r
696                 ch->tail->next = newbuf;\r
697             else\r
698                 ch->head = newbuf;\r
699             ch->tail = newbuf;\r
700         }\r
701     }\r
704 void bufchain_consume(bufchain *ch, int len)\r
706     struct bufchain_granule *tmp;\r
708     assert(ch->buffersize >= len);\r
709     while (len > 0) {\r
710         int remlen = len;\r
711         assert(ch->head != NULL);\r
712         if (remlen >= ch->head->bufend - ch->head->bufpos) {\r
713             remlen = ch->head->bufend - ch->head->bufpos;\r
714             tmp = ch->head;\r
715             ch->head = tmp->next;\r
716             if (!ch->head)\r
717                 ch->tail = NULL;\r
718             sfree(tmp);\r
719         } else\r
720             ch->head->bufpos += remlen;\r
721         ch->buffersize -= remlen;\r
722         len -= remlen;\r
723     }\r
726 void bufchain_prefix(bufchain *ch, void **data, int *len)\r
728     *len = ch->head->bufend - ch->head->bufpos;\r
729     *data = ch->head->bufpos;\r
732 void bufchain_fetch(bufchain *ch, void *data, int len)\r
734     struct bufchain_granule *tmp;\r
735     char *data_c = (char *)data;\r
737     tmp = ch->head;\r
739     assert(ch->buffersize >= len);\r
740     while (len > 0) {\r
741         int remlen = len;\r
743         assert(tmp != NULL);\r
744         if (remlen >= tmp->bufend - tmp->bufpos)\r
745             remlen = tmp->bufend - tmp->bufpos;\r
746         memcpy(data_c, tmp->bufpos, remlen);\r
748         tmp = tmp->next;\r
749         len -= remlen;\r
750         data_c += remlen;\r
751     }\r
754 /* ----------------------------------------------------------------------\r
755  * My own versions of malloc, realloc and free. Because I want\r
756  * malloc and realloc to bomb out and exit the program if they run\r
757  * out of memory, realloc to reliably call malloc if passed a NULL\r
758  * pointer, and free to reliably do nothing if passed a NULL\r
759  * pointer. We can also put trace printouts in, if we need to; and\r
760  * we can also replace the allocator with an ElectricFence-like\r
761  * one.\r
762  */\r
764 #ifdef MINEFIELD\r
765 void *minefield_c_malloc(size_t size);\r
766 void minefield_c_free(void *p);\r
767 void *minefield_c_realloc(void *p, size_t size);\r
768 #endif\r
770 #ifdef MALLOC_LOG\r
771 static FILE *fp = NULL;\r
773 static char *mlog_file = NULL;\r
774 static int mlog_line = 0;\r
776 void mlog(char *file, int line)\r
778     mlog_file = file;\r
779     mlog_line = line;\r
780     if (!fp) {\r
781         fp = fopen("putty_mem.log", "w");\r
782         setvbuf(fp, NULL, _IONBF, BUFSIZ);\r
783     }\r
784     if (fp)\r
785         fprintf(fp, "%s:%d: ", file, line);\r
787 #endif\r
789 void *safemalloc(size_t n, size_t size)\r
791     void *p;\r
793     if (n > INT_MAX / size) {\r
794         p = NULL;\r
795     } else {\r
796         size *= n;\r
797         if (size == 0) size = 1;\r
798 #ifdef MINEFIELD\r
799         p = minefield_c_malloc(size);\r
800 #else\r
801         p = malloc(size);\r
802 #endif\r
803     }\r
805     if (!p) {\r
806         char str[200];\r
807 #ifdef MALLOC_LOG\r
808         sprintf(str, "Out of memory! (%s:%d, size=%d)",\r
809                 mlog_file, mlog_line, size);\r
810         fprintf(fp, "*** %s\n", str);\r
811         fclose(fp);\r
812 #else\r
813         strcpy(str, "Out of memory!");\r
814 #endif\r
815         modalfatalbox("%s", str);\r
816     }\r
817 #ifdef MALLOC_LOG\r
818     if (fp)\r
819         fprintf(fp, "malloc(%d) returns %p\n", size, p);\r
820 #endif\r
821     return p;\r
824 void *saferealloc(void *ptr, size_t n, size_t size)\r
826     void *p;\r
828     if (n > INT_MAX / size) {\r
829         p = NULL;\r
830     } else {\r
831         size *= n;\r
832         if (!ptr) {\r
833 #ifdef MINEFIELD\r
834             p = minefield_c_malloc(size);\r
835 #else\r
836             p = malloc(size);\r
837 #endif\r
838         } else {\r
839 #ifdef MINEFIELD\r
840             p = minefield_c_realloc(ptr, size);\r
841 #else\r
842             p = realloc(ptr, size);\r
843 #endif\r
844         }\r
845     }\r
847     if (!p) {\r
848         char str[200];\r
849 #ifdef MALLOC_LOG\r
850         sprintf(str, "Out of memory! (%s:%d, size=%d)",\r
851                 mlog_file, mlog_line, size);\r
852         fprintf(fp, "*** %s\n", str);\r
853         fclose(fp);\r
854 #else\r
855         strcpy(str, "Out of memory!");\r
856 #endif\r
857         modalfatalbox("%s", str);\r
858     }\r
859 #ifdef MALLOC_LOG\r
860     if (fp)\r
861         fprintf(fp, "realloc(%p,%d) returns %p\n", ptr, size, p);\r
862 #endif\r
863     return p;\r
866 void safefree(void *ptr)\r
868     if (ptr) {\r
869 #ifdef MALLOC_LOG\r
870         if (fp)\r
871             fprintf(fp, "free(%p)\n", ptr);\r
872 #endif\r
873 #ifdef MINEFIELD\r
874         minefield_c_free(ptr);\r
875 #else\r
876         free(ptr);\r
877 #endif\r
878     }\r
879 #ifdef MALLOC_LOG\r
880     else if (fp)\r
881         fprintf(fp, "freeing null pointer - no action taken\n");\r
882 #endif\r
885 /* ----------------------------------------------------------------------\r
886  * Debugging routines.\r
887  */\r
889 #ifdef DEBUG\r
890 extern void dputs(const char *); /* defined in per-platform *misc.c */\r
892 void debug_printf(const char *fmt, ...)\r
894     char *buf;\r
895     va_list ap;\r
897     va_start(ap, fmt);\r
898     buf = dupvprintf(fmt, ap);\r
899     dputs(buf);\r
900     sfree(buf);\r
901     va_end(ap);\r
905 void debug_memdump(const void *buf, int len, int L)\r
907     int i;\r
908     const unsigned char *p = buf;\r
909     char foo[17];\r
910     if (L) {\r
911         int delta;\r
912         debug_printf("\t%d (0x%x) bytes:\n", len, len);\r
913         delta = 15 & (uintptr_t)p;\r
914         p -= delta;\r
915         len += delta;\r
916     }\r
917     for (; 0 < len; p += 16, len -= 16) {\r
918         dputs("  ");\r
919         if (L)\r
920             debug_printf("%p: ", p);\r
921         strcpy(foo, "................");        /* sixteen dots */\r
922         for (i = 0; i < 16 && i < len; ++i) {\r
923             if (&p[i] < (unsigned char *) buf) {\r
924                 dputs("   ");          /* 3 spaces */\r
925                 foo[i] = ' ';\r
926             } else {\r
927                 debug_printf("%c%02.2x",\r
928                         &p[i] != (unsigned char *) buf\r
929                         && i % 4 ? '.' : ' ', p[i]\r
930                     );\r
931                 if (p[i] >= ' ' && p[i] <= '~')\r
932                     foo[i] = (char) p[i];\r
933             }\r
934         }\r
935         foo[i] = '\0';\r
936         debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo);\r
937     }\r
940 #endif                          /* def DEBUG */\r
942 /*\r
943  * Determine whether or not a Conf represents a session which can\r
944  * sensibly be launched right now.\r
945  */\r
946 int conf_launchable(Conf *conf)\r
948     if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)\r
949         return conf_get_str(conf, CONF_serline)[0] != 0;\r
950     else\r
951         return conf_get_str(conf, CONF_host)[0] != 0;\r
954 char const *conf_dest(Conf *conf)\r
956     if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)\r
957         return conf_get_str(conf, CONF_serline);\r
958     else\r
959         return conf_get_str(conf, CONF_host);\r
962 #ifndef PLATFORM_HAS_SMEMCLR\r
963 /*\r
964  * Securely wipe memory.\r
965  *\r
966  * The actual wiping is no different from what memset would do: the\r
967  * point of 'securely' is to try to be sure over-clever compilers\r
968  * won't optimise away memsets on variables that are about to be freed\r
969  * or go out of scope. See\r
970  * https://buildsecurityin.us-cert.gov/bsi-rules/home/g1/771-BSI.html\r
971  *\r
972  * Some platforms (e.g. Windows) may provide their own version of this\r
973  * function.\r
974  */\r
975 void smemclr(void *b, size_t n) {\r
976     volatile char *vp;\r
978     if (b && n > 0) {\r
979         /*\r
980          * Zero out the memory.\r
981          */\r
982         memset(b, 0, n);\r
984         /*\r
985          * Perform a volatile access to the object, forcing the\r
986          * compiler to admit that the previous memset was important.\r
987          *\r
988          * This while loop should in practice run for zero iterations\r
989          * (since we know we just zeroed the object out), but in\r
990          * theory (as far as the compiler knows) it might range over\r
991          * the whole object. (If we had just written, say, '*vp =\r
992          * *vp;', a compiler could in principle have 'helpfully'\r
993          * optimised the memset into only zeroing out the first byte.\r
994          * This should be robust.)\r
995          */\r
996         vp = b;\r
997         while (*vp) vp++;\r
998     }\r
1000 #endif\r
1002 /*\r
1003  * Validate a manual host key specification (either entered in the\r
1004  * GUI, or via -hostkey). If valid, we return TRUE, and update 'key'\r
1005  * to contain a canonicalised version of the key string in 'key'\r
1006  * (which is guaranteed to take up at most as much space as the\r
1007  * original version), suitable for putting into the Conf. If not\r
1008  * valid, we return FALSE.\r
1009  */\r
1010 int validate_manual_hostkey(char *key)\r
1012     char *p, *q, *r, *s;\r
1014     /*\r
1015      * Step through the string word by word, looking for a word that's\r
1016      * in one of the formats we like.\r
1017      */\r
1018     p = key;\r
1019     while ((p += strspn(p, " \t"))[0]) {\r
1020         q = p;\r
1021         p += strcspn(p, " \t");\r
1022         if (*p) *p++ = '\0';\r
1024         /*\r
1025          * Now q is our word.\r
1026          */\r
1028         if (strlen(q) == 16*3 - 1 &&\r
1029             q[strspn(q, "0123456789abcdefABCDEF:")] == 0) {\r
1030             /*\r
1031              * Might be a key fingerprint. Check the colons are in the\r
1032              * right places, and if so, return the same fingerprint\r
1033              * canonicalised into lowercase.\r
1034              */\r
1035             int i;\r
1036             for (i = 0; i < 16; i++)\r
1037                 if (q[3*i] == ':' || q[3*i+1] == ':')\r
1038                     goto not_fingerprint; /* sorry */\r
1039             for (i = 0; i < 15; i++)\r
1040                 if (q[3*i+2] != ':')\r
1041                     goto not_fingerprint; /* sorry */\r
1042             for (i = 0; i < 16*3 - 1; i++)\r
1043                 key[i] = tolower(q[i]);\r
1044             key[16*3 - 1] = '\0';\r
1045             return TRUE;\r
1046         }\r
1047       not_fingerprint:;\r
1049         /*\r
1050          * Before we check for a public-key blob, trim newlines out of\r
1051          * the middle of the word, in case someone's managed to paste\r
1052          * in a public-key blob _with_ them.\r
1053          */\r
1054         for (r = s = q; *r; r++)\r
1055             if (*r != '\n' && *r != '\r')\r
1056                 *s++ = *r;\r
1057         *s = '\0';\r
1059         if (strlen(q) % 4 == 0 && strlen(q) > 2*4 &&\r
1060             q[strspn(q, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"\r
1061                      "abcdefghijklmnopqrstuvwxyz+/=")] == 0) {\r
1062             /*\r
1063              * Might be a base64-encoded SSH-2 public key blob. Check\r
1064              * that it starts with a sensible algorithm string. No\r
1065              * canonicalisation is necessary for this string type.\r
1066              *\r
1067              * The algorithm string must be at most 64 characters long\r
1068              * (RFC 4251 section 6).\r
1069              */\r
1070             unsigned char decoded[6];\r
1071             unsigned alglen;\r
1072             int minlen;\r
1073             int len = 0;\r
1075             len += base64_decode_atom(q, decoded+len);\r
1076             if (len < 3)\r
1077                 goto not_ssh2_blob;    /* sorry */\r
1078             len += base64_decode_atom(q+4, decoded+len);\r
1079             if (len < 4)\r
1080                 goto not_ssh2_blob;    /* sorry */\r
1082             alglen = GET_32BIT_MSB_FIRST(decoded);\r
1083             if (alglen > 64)\r
1084                 goto not_ssh2_blob;    /* sorry */\r
1086             minlen = ((alglen + 4) + 2) / 3;\r
1087             if (strlen(q) < minlen)\r
1088                 goto not_ssh2_blob;    /* sorry */\r
1090             strcpy(key, q);\r
1091             return TRUE;\r
1092         }\r
1093       not_ssh2_blob:;\r
1094     }\r
1096     return FALSE;\r
1099 int smemeq(const void *av, const void *bv, size_t len)\r
1101     const unsigned char *a = (const unsigned char *)av;\r
1102     const unsigned char *b = (const unsigned char *)bv;\r
1103     unsigned val = 0;\r
1105     while (len-- > 0) {\r
1106         val |= *a++ ^ *b++;\r
1107     }\r
1108     /* Now val is 0 iff we want to return 1, and in the range\r
1109      * 0x01..0xFF iff we want to return 0. So subtracting from 0x100\r
1110      * will clear bit 8 iff we want to return 0, and leave it set iff\r
1111      * we want to return 1, so then we can just shift down. */\r
1112     return (0x100 - val) >> 8;\r
1115 int match_ssh_id(int stringlen, const void *string, const char *id)\r
1117     int idlen = strlen(id);\r
1118     return (idlen == stringlen && !memcmp(string, id, idlen));\r
1121 void *get_ssh_string(int *datalen, const void **data, int *stringlen)\r
1123     void *ret;\r
1124     unsigned int len;\r
1126     if (*datalen < 4)\r
1127         return NULL;\r
1128     len = GET_32BIT_MSB_FIRST((const unsigned char *)*data);\r
1129     if (*datalen - 4 < len)\r
1130         return NULL;\r
1131     ret = (void *)((const char *)*data + 4);\r
1132     *datalen -= len + 4;\r
1133     *data = (const char *)*data + len + 4;\r
1134     *stringlen = len;\r
1135     return ret;\r
1138 int get_ssh_uint32(int *datalen, const void **data, unsigned *ret)\r
1140     if (*datalen < 4)\r
1141         return FALSE;\r
1142     *ret = GET_32BIT_MSB_FIRST((const unsigned char *)*data);\r
1143     *datalen -= 4;\r
1144     *data = (const char *)*data + 4;\r
1145     return TRUE;\r
1148 int strstartswith(const char *s, const char *t)\r
1150     return !memcmp(s, t, strlen(t));\r
1153 int strendswith(const char *s, const char *t)\r
1155     size_t slen = strlen(s), tlen = strlen(t);\r
1156     return slen >= tlen && !strcmp(s + (slen - tlen), t);\r
1159 char *buildinfo(const char *newline)\r
1161     strbuf *buf = strbuf_new();\r
1162     extern const char commitid[];      /* in commitid.c */\r
1164     strbuf_catf(buf, "Build platform: %d-bit %s",\r
1165                 (int)(CHAR_BIT * sizeof(void *)),\r
1166                 BUILDINFO_PLATFORM);\r
1168 #ifdef __clang_version__\r
1169 #define FOUND_COMPILER\r
1170     strbuf_catf(buf, "%sCompiler: clang %s", newline, __clang_version__);\r
1171 #elif defined __GNUC__ && defined __VERSION__\r
1172 #define FOUND_COMPILER\r
1173     strbuf_catf(buf, "%sCompiler: gcc %s", newline, __VERSION__);\r
1174 #endif\r
1176 #if defined _MSC_VER\r
1177 #ifndef FOUND_COMPILER\r
1178 #define FOUND_COMPILER\r
1179     strbuf_catf(buf, "%sCompiler: ", newline);\r
1180 #else\r
1181     strbuf_catf(buf, ", emulating ");\r
1182 #endif\r
1183     strbuf_catf(buf, "Visual Studio", newline);\r
1184 #if _MSC_VER == 1900\r
1185     strbuf_catf(buf, " 2015 / MSVC++ 14.0");\r
1186 #elif _MSC_VER == 1800\r
1187     strbuf_catf(buf, " 2013 / MSVC++ 12.0");\r
1188 #elif _MSC_VER == 1700\r
1189     strbuf_catf(buf, " 2012 / MSVC++ 11.0");\r
1190 #elif _MSC_VER == 1600\r
1191     strbuf_catf(buf, " 2010 / MSVC++ 10.0");\r
1192 #elif _MSC_VER == 1500\r
1193     strbuf_catf(buf, " 2008 / MSVC++ 9.0");\r
1194 #elif _MSC_VER == 1400\r
1195     strbuf_catf(buf, " 2005 / MSVC++ 8.0");\r
1196 #elif _MSC_VER == 1310\r
1197     strbuf_catf(buf, " 2003 / MSVC++ 7.1");\r
1198 #elif _MSC_VER == 1300\r
1199     strbuf_catf(buf, " 2003 / MSVC++ 7.0");\r
1200 #else\r
1201     strbuf_catf(buf, ", unrecognised version");\r
1202 #endif\r
1203     strbuf_catf(buf, " (_MSC_VER=%d)", (int)_MSC_VER);\r
1204 #endif\r
1206 #ifdef BUILDINFO_GTK\r
1207     {\r
1208         char *gtk_buildinfo = buildinfo_gtk_version();\r
1209         if (gtk_buildinfo) {\r
1210             strbuf_catf(buf, "%sCompiled against GTK version %s",\r
1211                         newline, gtk_buildinfo);\r
1212             sfree(gtk_buildinfo);\r
1213         }\r
1214     }\r
1215 #endif\r
1217 #if defined _WINDOWS && defined MINEFIELD\r
1218     strbuf_catf(buf, "%sBuild option: MINEFIELD", newline);\r
1219 #endif\r
1220 #ifdef NO_SECURITY\r
1221     strbuf_catf(buf, "%sBuild option: NO_SECURITY", newline);\r
1222 #endif\r
1223 #ifdef NO_SECUREZEROMEMORY\r
1224     strbuf_catf(buf, "%sBuild option: NO_SECUREZEROMEMORY", newline);\r
1225 #endif\r
1226 #ifdef NO_IPV6\r
1227     strbuf_catf(buf, "%sBuild option: NO_IPV6", newline);\r
1228 #endif\r
1229 #ifdef NO_GSSAPI\r
1230     strbuf_catf(buf, "%sBuild option: NO_GSSAPI", newline);\r
1231 #endif\r
1232 #ifdef STATIC_GSSAPI\r
1233     strbuf_catf(buf, "%sBuild option: STATIC_GSSAPI", newline);\r
1234 #endif\r
1235 #ifdef UNPROTECT\r
1236     strbuf_catf(buf, "%sBuild option: UNPROTECT", newline);\r
1237 #endif\r
1238 #ifdef FUZZING\r
1239     strbuf_catf(buf, "%sBuild option: FUZZING", newline);\r
1240 #endif\r
1241 #ifdef DEBUG\r
1242     strbuf_catf(buf, "%sBuild option: DEBUG", newline);\r
1243 #endif\r
1245     strbuf_catf(buf, "%sSource commit: %s", newline, commitid);\r
1247     return strbuf_to_str(buf);\r