Doc: Fix broken link
[TortoiseGit.git] / src / TortoisePlink / MISC.C
blobf1073b5d6c6d1bb47900c1203b8a9a17ec8f4541
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, result);        \\r
161             fails++;                                                    \\r
162         }                                                               \\r
163 } while (0)\r
165     TEST1(host_strchr, "[1:2:3]:4:5", ':', -str, 7);\r
166     TEST1(host_strrchr, "[1:2:3]:4:5", ':', -str, 9);\r
167     TEST1(host_strcspn, "[1:2:3]:4:5", "/:",, 7);\r
168     TEST1(host_strchr, "[1:2:3]", ':', == NULL, 1);\r
169     TEST1(host_strrchr, "[1:2:3]", ':', == NULL, 1);\r
170     TEST1(host_strcspn, "[1:2:3]", "/:",, 7);\r
171     TEST1(host_strcspn, "[1:2/3]", "/:",, 4);\r
172     TEST1(host_strcspn, "[1:2:3]/", "/:",, 7);\r
174     printf("passed %d failed %d total %d\n", passes, fails, passes+fails);\r
175     return fails != 0 ? 1 : 0;\r
177 /* Stubs to stop the rest of this module causing compile failures. */\r
178 void modalfatalbox(const char *fmt, ...) {}\r
179 int conf_get_int(Conf *conf, int primary) { return 0; }\r
180 char *conf_get_str(Conf *conf, int primary) { return NULL; }\r
181 #endif /* TEST_HOST_STRFOO */\r
183 /*\r
184  * Trim square brackets off the outside of an IPv6 address literal.\r
185  * Leave all other strings unchanged. Returns a fresh dynamically\r
186  * allocated string.\r
187  */\r
188 char *host_strduptrim(const char *s)\r
190     if (s[0] == '[') {\r
191         const char *p = s+1;\r
192         int colons = 0;\r
193         while (*p && *p != ']') {\r
194             if (isxdigit((unsigned char)*p))\r
195                 /* OK */;\r
196             else if (*p == ':')\r
197                 colons++;\r
198             else\r
199                 break;\r
200             p++;\r
201         }\r
202         if (*p == ']' && !p[1] && colons > 1) {\r
203             /*\r
204              * This looks like an IPv6 address literal (hex digits and\r
205              * at least two colons, contained in square brackets).\r
206              * Trim off the brackets.\r
207              */\r
208             return dupprintf("%.*s", (int)(p - (s+1)), s+1);\r
209         }\r
210     }\r
212     /*\r
213      * Any other shape of string is simply duplicated.\r
214      */\r
215     return dupstr(s);\r
218 prompts_t *new_prompts(void *frontend)\r
220     prompts_t *p = snew(prompts_t);\r
221     p->prompts = NULL;\r
222     p->n_prompts = 0;\r
223     p->frontend = frontend;\r
224     p->data = NULL;\r
225     p->to_server = TRUE; /* to be on the safe side */\r
226     p->name = p->instruction = NULL;\r
227     p->name_reqd = p->instr_reqd = FALSE;\r
228     return p;\r
230 void add_prompt(prompts_t *p, char *promptstr, int echo)\r
232     prompt_t *pr = snew(prompt_t);\r
233     pr->prompt = promptstr;\r
234     pr->echo = echo;\r
235     pr->result = NULL;\r
236     pr->resultsize = 0;\r
237     p->n_prompts++;\r
238     p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *);\r
239     p->prompts[p->n_prompts-1] = pr;\r
241 void prompt_ensure_result_size(prompt_t *pr, int newlen)\r
243     if ((int)pr->resultsize < newlen) {\r
244         char *newbuf;\r
245         newlen = newlen * 5 / 4 + 512; /* avoid too many small allocs */\r
247         /*\r
248          * We don't use sresize / realloc here, because we will be\r
249          * storing sensitive stuff like passwords in here, and we want\r
250          * to make sure that the data doesn't get copied around in\r
251          * memory without the old copy being destroyed.\r
252          */\r
253         newbuf = snewn(newlen, char);\r
254         memcpy(newbuf, pr->result, pr->resultsize);\r
255         smemclr(pr->result, pr->resultsize);\r
256         sfree(pr->result);\r
257         pr->result = newbuf;\r
258         pr->resultsize = newlen;\r
259     }\r
261 void prompt_set_result(prompt_t *pr, const char *newstr)\r
263     prompt_ensure_result_size(pr, strlen(newstr) + 1);\r
264     strcpy(pr->result, newstr);\r
266 void free_prompts(prompts_t *p)\r
268     size_t i;\r
269     for (i=0; i < p->n_prompts; i++) {\r
270         prompt_t *pr = p->prompts[i];\r
271         smemclr(pr->result, pr->resultsize); /* burn the evidence */\r
272         sfree(pr->result);\r
273         sfree(pr->prompt);\r
274         sfree(pr);\r
275     }\r
276     sfree(p->prompts);\r
277     sfree(p->name);\r
278     sfree(p->instruction);\r
279     sfree(p);\r
282 /* ----------------------------------------------------------------------\r
283  * String handling routines.\r
284  */\r
286 char *dupstr(const char *s)\r
288     char *p = NULL;\r
289     if (s) {\r
290         int len = strlen(s);\r
291         p = snewn(len + 1, char);\r
292         strcpy(p, s);\r
293     }\r
294     return p;\r
297 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */\r
298 char *dupcat(const char *s1, ...)\r
300     int len;\r
301     char *p, *q, *sn;\r
302     va_list ap;\r
304     len = strlen(s1);\r
305     va_start(ap, s1);\r
306     while (1) {\r
307         sn = va_arg(ap, char *);\r
308         if (!sn)\r
309             break;\r
310         len += strlen(sn);\r
311     }\r
312     va_end(ap);\r
314     p = snewn(len + 1, char);\r
315     strcpy(p, s1);\r
316     q = p + strlen(p);\r
318     va_start(ap, s1);\r
319     while (1) {\r
320         sn = va_arg(ap, char *);\r
321         if (!sn)\r
322             break;\r
323         strcpy(q, sn);\r
324         q += strlen(q);\r
325     }\r
326     va_end(ap);\r
328     return p;\r
331 void burnstr(char *string)             /* sfree(str), only clear it first */\r
333     if (string) {\r
334         smemclr(string, strlen(string));\r
335         sfree(string);\r
336     }\r
339 int toint(unsigned u)\r
341     /*\r
342      * Convert an unsigned to an int, without running into the\r
343      * undefined behaviour which happens by the strict C standard if\r
344      * the value overflows. You'd hope that sensible compilers would\r
345      * do the sensible thing in response to a cast, but actually I\r
346      * don't trust modern compilers not to do silly things like\r
347      * assuming that _obviously_ you wouldn't have caused an overflow\r
348      * and so they can elide an 'if (i < 0)' test immediately after\r
349      * the cast.\r
350      *\r
351      * Sensible compilers ought of course to optimise this entire\r
352      * function into 'just return the input value'!\r
353      */\r
354     if (u <= (unsigned)INT_MAX)\r
355         return (int)u;\r
356     else if (u >= (unsigned)INT_MIN)   /* wrap in cast _to_ unsigned is OK */\r
357         return INT_MIN + (int)(u - (unsigned)INT_MIN);\r
358     else\r
359         return INT_MIN; /* fallback; should never occur on binary machines */\r
362 /*\r
363  * Do an sprintf(), but into a custom-allocated buffer.\r
364  * \r
365  * Currently I'm doing this via vsnprintf. This has worked so far,\r
366  * but it's not good, because vsnprintf is not available on all\r
367  * platforms. There's an ifdef to use `_vsnprintf', which seems\r
368  * to be the local name for it on Windows. Other platforms may\r
369  * lack it completely, in which case it'll be time to rewrite\r
370  * this function in a totally different way.\r
371  * \r
372  * The only `properly' portable solution I can think of is to\r
373  * implement my own format string scanner, which figures out an\r
374  * upper bound for the length of each formatting directive,\r
375  * allocates the buffer as it goes along, and calls sprintf() to\r
376  * actually process each directive. If I ever need to actually do\r
377  * this, some caveats:\r
378  * \r
379  *  - It's very hard to find a reliable upper bound for\r
380  *    floating-point values. %f, in particular, when supplied with\r
381  *    a number near to the upper or lower limit of representable\r
382  *    numbers, could easily take several hundred characters. It's\r
383  *    probably feasible to predict this statically using the\r
384  *    constants in <float.h>, or even to predict it dynamically by\r
385  *    looking at the exponent of the specific float provided, but\r
386  *    it won't be fun.\r
387  * \r
388  *  - Don't forget to _check_, after calling sprintf, that it's\r
389  *    used at most the amount of space we had available.\r
390  * \r
391  *  - Fault any formatting directive we don't fully understand. The\r
392  *    aim here is to _guarantee_ that we never overflow the buffer,\r
393  *    because this is a security-critical function. If we see a\r
394  *    directive we don't know about, we should panic and die rather\r
395  *    than run any risk.\r
396  */\r
397 static char *dupvprintf_inner(char *buf, int oldlen, int *oldsize,\r
398                               const char *fmt, va_list ap)\r
400     int len, size, newsize;\r
402     assert(*oldsize >= oldlen);\r
403     size = *oldsize - oldlen;\r
404     if (size == 0) {\r
405         size = 512;\r
406         newsize = oldlen + size;\r
407         buf = sresize(buf, newsize, char);\r
408     } else {\r
409         newsize = *oldsize;\r
410     }\r
412     while (1) {\r
413 #if defined _WINDOWS && !defined __WINE__ && _MSC_VER < 1900 /* 1900 == VS2015 has real snprintf */\r
414 #define vsnprintf _vsnprintf\r
415 #endif\r
416 #ifdef va_copy\r
417         /* Use the `va_copy' macro mandated by C99, if present.\r
418          * XXX some environments may have this as __va_copy() */\r
419         va_list aq;\r
420         va_copy(aq, ap);\r
421         len = vsnprintf(buf + oldlen, size, fmt, aq);\r
422         va_end(aq);\r
423 #else\r
424         /* Ugh. No va_copy macro, so do something nasty.\r
425          * Technically, you can't reuse a va_list like this: it is left\r
426          * unspecified whether advancing a va_list pointer modifies its\r
427          * value or something it points to, so on some platforms calling\r
428          * vsnprintf twice on the same va_list might fail hideously\r
429          * (indeed, it has been observed to).\r
430          * XXX the autoconf manual suggests that using memcpy() will give\r
431          *     "maximum portability". */\r
432         len = vsnprintf(buf + oldlen, size, fmt, ap);\r
433 #endif\r
434         if (len >= 0 && len < size) {\r
435             /* This is the C99-specified criterion for snprintf to have\r
436              * been completely successful. */\r
437             *oldsize = newsize;\r
438             return buf;\r
439         } else if (len > 0) {\r
440             /* This is the C99 error condition: the returned length is\r
441              * the required buffer size not counting the NUL. */\r
442             size = len + 1;\r
443         } else {\r
444             /* This is the pre-C99 glibc error condition: <0 means the\r
445              * buffer wasn't big enough, so we enlarge it a bit and hope. */\r
446             size += 512;\r
447         }\r
448         newsize = oldlen + size;\r
449         buf = sresize(buf, newsize, char);\r
450     }\r
453 char *dupvprintf(const char *fmt, va_list ap)\r
455     int size = 0;\r
456     return dupvprintf_inner(NULL, 0, &size, fmt, ap);\r
458 char *dupprintf(const char *fmt, ...)\r
460     char *ret;\r
461     va_list ap;\r
462     va_start(ap, fmt);\r
463     ret = dupvprintf(fmt, ap);\r
464     va_end(ap);\r
465     return ret;\r
468 struct strbuf {\r
469     char *s;\r
470     int len, size;\r
471 };\r
472 strbuf *strbuf_new(void)\r
474     strbuf *buf = snew(strbuf);\r
475     buf->len = 0;\r
476     buf->size = 512;\r
477     buf->s = snewn(buf->size, char);\r
478     *buf->s = '\0';\r
479     return buf;\r
481 void strbuf_free(strbuf *buf)\r
483     sfree(buf->s);\r
484     sfree(buf);\r
486 char *strbuf_str(strbuf *buf)\r
488     return buf->s;\r
490 char *strbuf_to_str(strbuf *buf)\r
492     char *ret = buf->s;\r
493     sfree(buf);\r
494     return ret;\r
496 void strbuf_catfv(strbuf *buf, const char *fmt, va_list ap)\r
498     buf->s = dupvprintf_inner(buf->s, buf->len, &buf->size, fmt, ap);\r
499     buf->len += strlen(buf->s + buf->len);\r
501 void strbuf_catf(strbuf *buf, const char *fmt, ...)\r
503     va_list ap;\r
504     va_start(ap, fmt);\r
505     strbuf_catfv(buf, fmt, ap);\r
506     va_end(ap);\r
509 /*\r
510  * Read an entire line of text from a file. Return a buffer\r
511  * malloced to be as big as necessary (caller must free).\r
512  */\r
513 char *fgetline(FILE *fp)\r
515     char *ret = snewn(512, char);\r
516     int size = 512, len = 0;\r
517     while (fgets(ret + len, size - len, fp)) {\r
518         len += strlen(ret + len);\r
519         if (len > 0 && ret[len-1] == '\n')\r
520             break;                     /* got a newline, we're done */\r
521         size = len + 512;\r
522         ret = sresize(ret, size, char);\r
523     }\r
524     if (len == 0) {                    /* first fgets returned NULL */\r
525         sfree(ret);\r
526         return NULL;\r
527     }\r
528     ret[len] = '\0';\r
529     return ret;\r
532 /*\r
533  * Perl-style 'chomp', for a line we just read with fgetline. Unlike\r
534  * Perl chomp, however, we're deliberately forgiving of strange\r
535  * line-ending conventions. Also we forgive NULL on input, so you can\r
536  * just write 'line = chomp(fgetline(fp));' and not bother checking\r
537  * for NULL until afterwards.\r
538  */\r
539 char *chomp(char *str)\r
541     if (str) {\r
542         int len = strlen(str);\r
543         while (len > 0 && (str[len-1] == '\r' || str[len-1] == '\n'))\r
544             len--;\r
545         str[len] = '\0';\r
546     }\r
547     return str;\r
550 /* ----------------------------------------------------------------------\r
551  * Core base64 encoding and decoding routines.\r
552  */\r
554 void base64_encode_atom(const unsigned char *data, int n, char *out)\r
556     static const char base64_chars[] =\r
557         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\r
559     unsigned word;\r
561     word = data[0] << 16;\r
562     if (n > 1)\r
563         word |= data[1] << 8;\r
564     if (n > 2)\r
565         word |= data[2];\r
566     out[0] = base64_chars[(word >> 18) & 0x3F];\r
567     out[1] = base64_chars[(word >> 12) & 0x3F];\r
568     if (n > 1)\r
569         out[2] = base64_chars[(word >> 6) & 0x3F];\r
570     else\r
571         out[2] = '=';\r
572     if (n > 2)\r
573         out[3] = base64_chars[word & 0x3F];\r
574     else\r
575         out[3] = '=';\r
578 int base64_decode_atom(const char *atom, unsigned char *out)\r
580     int vals[4];\r
581     int i, v, len;\r
582     unsigned word;\r
583     char c;\r
585     for (i = 0; i < 4; i++) {\r
586         c = atom[i];\r
587         if (c >= 'A' && c <= 'Z')\r
588             v = c - 'A';\r
589         else if (c >= 'a' && c <= 'z')\r
590             v = c - 'a' + 26;\r
591         else if (c >= '0' && c <= '9')\r
592             v = c - '0' + 52;\r
593         else if (c == '+')\r
594             v = 62;\r
595         else if (c == '/')\r
596             v = 63;\r
597         else if (c == '=')\r
598             v = -1;\r
599         else\r
600             return 0;                  /* invalid atom */\r
601         vals[i] = v;\r
602     }\r
604     if (vals[0] == -1 || vals[1] == -1)\r
605         return 0;\r
606     if (vals[2] == -1 && vals[3] != -1)\r
607         return 0;\r
609     if (vals[3] != -1)\r
610         len = 3;\r
611     else if (vals[2] != -1)\r
612         len = 2;\r
613     else\r
614         len = 1;\r
616     word = ((vals[0] << 18) |\r
617             (vals[1] << 12) | ((vals[2] & 0x3F) << 6) | (vals[3] & 0x3F));\r
618     out[0] = (word >> 16) & 0xFF;\r
619     if (len > 1)\r
620         out[1] = (word >> 8) & 0xFF;\r
621     if (len > 2)\r
622         out[2] = word & 0xFF;\r
623     return len;\r
626 /* ----------------------------------------------------------------------\r
627  * Generic routines to deal with send buffers: a linked list of\r
628  * smallish blocks, with the operations\r
629  * \r
630  *  - add an arbitrary amount of data to the end of the list\r
631  *  - remove the first N bytes from the list\r
632  *  - return a (pointer,length) pair giving some initial data in\r
633  *    the list, suitable for passing to a send or write system\r
634  *    call\r
635  *  - retrieve a larger amount of initial data from the list\r
636  *  - return the current size of the buffer chain in bytes\r
637  */\r
639 #define BUFFER_MIN_GRANULE  512\r
641 struct bufchain_granule {\r
642     struct bufchain_granule *next;\r
643     char *bufpos, *bufend, *bufmax;\r
644 };\r
646 void bufchain_init(bufchain *ch)\r
648     ch->head = ch->tail = NULL;\r
649     ch->buffersize = 0;\r
652 void bufchain_clear(bufchain *ch)\r
654     struct bufchain_granule *b;\r
655     while (ch->head) {\r
656         b = ch->head;\r
657         ch->head = ch->head->next;\r
658         sfree(b);\r
659     }\r
660     ch->tail = NULL;\r
661     ch->buffersize = 0;\r
664 int bufchain_size(bufchain *ch)\r
666     return ch->buffersize;\r
669 void bufchain_add(bufchain *ch, const void *data, int len)\r
671     const char *buf = (const char *)data;\r
673     if (len == 0) return;\r
675     ch->buffersize += len;\r
677     while (len > 0) {\r
678         if (ch->tail && ch->tail->bufend < ch->tail->bufmax) {\r
679             int copylen = min(len, ch->tail->bufmax - ch->tail->bufend);\r
680             memcpy(ch->tail->bufend, buf, copylen);\r
681             buf += copylen;\r
682             len -= copylen;\r
683             ch->tail->bufend += copylen;\r
684         }\r
685         if (len > 0) {\r
686             int grainlen =\r
687                 max(sizeof(struct bufchain_granule) + len, BUFFER_MIN_GRANULE);\r
688             struct bufchain_granule *newbuf;\r
689             newbuf = smalloc(grainlen);\r
690             newbuf->bufpos = newbuf->bufend =\r
691                 (char *)newbuf + sizeof(struct bufchain_granule);\r
692             newbuf->bufmax = (char *)newbuf + grainlen;\r
693             newbuf->next = NULL;\r
694             if (ch->tail)\r
695                 ch->tail->next = newbuf;\r
696             else\r
697                 ch->head = newbuf;\r
698             ch->tail = newbuf;\r
699         }\r
700     }\r
703 void bufchain_consume(bufchain *ch, int len)\r
705     struct bufchain_granule *tmp;\r
707     assert(ch->buffersize >= len);\r
708     while (len > 0) {\r
709         int remlen = len;\r
710         assert(ch->head != NULL);\r
711         if (remlen >= ch->head->bufend - ch->head->bufpos) {\r
712             remlen = ch->head->bufend - ch->head->bufpos;\r
713             tmp = ch->head;\r
714             ch->head = tmp->next;\r
715             if (!ch->head)\r
716                 ch->tail = NULL;\r
717             sfree(tmp);\r
718         } else\r
719             ch->head->bufpos += remlen;\r
720         ch->buffersize -= remlen;\r
721         len -= remlen;\r
722     }\r
725 void bufchain_prefix(bufchain *ch, void **data, int *len)\r
727     *len = ch->head->bufend - ch->head->bufpos;\r
728     *data = ch->head->bufpos;\r
731 void bufchain_fetch(bufchain *ch, void *data, int len)\r
733     struct bufchain_granule *tmp;\r
734     char *data_c = (char *)data;\r
736     tmp = ch->head;\r
738     assert(ch->buffersize >= len);\r
739     while (len > 0) {\r
740         int remlen = len;\r
742         assert(tmp != NULL);\r
743         if (remlen >= tmp->bufend - tmp->bufpos)\r
744             remlen = tmp->bufend - tmp->bufpos;\r
745         memcpy(data_c, tmp->bufpos, remlen);\r
747         tmp = tmp->next;\r
748         len -= remlen;\r
749         data_c += remlen;\r
750     }\r
753 /* ----------------------------------------------------------------------\r
754  * My own versions of malloc, realloc and free. Because I want\r
755  * malloc and realloc to bomb out and exit the program if they run\r
756  * out of memory, realloc to reliably call malloc if passed a NULL\r
757  * pointer, and free to reliably do nothing if passed a NULL\r
758  * pointer. We can also put trace printouts in, if we need to; and\r
759  * we can also replace the allocator with an ElectricFence-like\r
760  * one.\r
761  */\r
763 #ifdef MINEFIELD\r
764 void *minefield_c_malloc(size_t size);\r
765 void minefield_c_free(void *p);\r
766 void *minefield_c_realloc(void *p, size_t size);\r
767 #endif\r
769 #ifdef MALLOC_LOG\r
770 static FILE *fp = NULL;\r
772 static char *mlog_file = NULL;\r
773 static int mlog_line = 0;\r
775 void mlog(char *file, int line)\r
777     mlog_file = file;\r
778     mlog_line = line;\r
779     if (!fp) {\r
780         fp = fopen("putty_mem.log", "w");\r
781         setvbuf(fp, NULL, _IONBF, BUFSIZ);\r
782     }\r
783     if (fp)\r
784         fprintf(fp, "%s:%d: ", file, line);\r
786 #endif\r
788 void *safemalloc(size_t n, size_t size)\r
790     void *p;\r
792     if (n > INT_MAX / size) {\r
793         p = NULL;\r
794     } else {\r
795         size *= n;\r
796         if (size == 0) size = 1;\r
797 #ifdef MINEFIELD\r
798         p = minefield_c_malloc(size);\r
799 #else\r
800         p = malloc(size);\r
801 #endif\r
802     }\r
804     if (!p) {\r
805         char str[200];\r
806 #ifdef MALLOC_LOG\r
807         sprintf(str, "Out of memory! (%s:%d, size=%d)",\r
808                 mlog_file, mlog_line, size);\r
809         fprintf(fp, "*** %s\n", str);\r
810         fclose(fp);\r
811 #else\r
812         strcpy(str, "Out of memory!");\r
813 #endif\r
814         modalfatalbox("%s", str);\r
815     }\r
816 #ifdef MALLOC_LOG\r
817     if (fp)\r
818         fprintf(fp, "malloc(%d) returns %p\n", size, p);\r
819 #endif\r
820     return p;\r
823 void *saferealloc(void *ptr, size_t n, size_t size)\r
825     void *p;\r
827     if (n > INT_MAX / size) {\r
828         p = NULL;\r
829     } else {\r
830         size *= n;\r
831         if (!ptr) {\r
832 #ifdef MINEFIELD\r
833             p = minefield_c_malloc(size);\r
834 #else\r
835             p = malloc(size);\r
836 #endif\r
837         } else {\r
838 #ifdef MINEFIELD\r
839             p = minefield_c_realloc(ptr, size);\r
840 #else\r
841             p = realloc(ptr, size);\r
842 #endif\r
843         }\r
844     }\r
846     if (!p) {\r
847         char str[200];\r
848 #ifdef MALLOC_LOG\r
849         sprintf(str, "Out of memory! (%s:%d, size=%d)",\r
850                 mlog_file, mlog_line, size);\r
851         fprintf(fp, "*** %s\n", str);\r
852         fclose(fp);\r
853 #else\r
854         strcpy(str, "Out of memory!");\r
855 #endif\r
856         modalfatalbox("%s", str);\r
857     }\r
858 #ifdef MALLOC_LOG\r
859     if (fp)\r
860         fprintf(fp, "realloc(%p,%d) returns %p\n", ptr, size, p);\r
861 #endif\r
862     return p;\r
865 void safefree(void *ptr)\r
867     if (ptr) {\r
868 #ifdef MALLOC_LOG\r
869         if (fp)\r
870             fprintf(fp, "free(%p)\n", ptr);\r
871 #endif\r
872 #ifdef MINEFIELD\r
873         minefield_c_free(ptr);\r
874 #else\r
875         free(ptr);\r
876 #endif\r
877     }\r
878 #ifdef MALLOC_LOG\r
879     else if (fp)\r
880         fprintf(fp, "freeing null pointer - no action taken\n");\r
881 #endif\r
884 /* ----------------------------------------------------------------------\r
885  * Debugging routines.\r
886  */\r
888 #ifdef DEBUG\r
889 extern void dputs(const char *); /* defined in per-platform *misc.c */\r
891 void debug_printf(const char *fmt, ...)\r
893     char *buf;\r
894     va_list ap;\r
896     va_start(ap, fmt);\r
897     buf = dupvprintf(fmt, ap);\r
898     dputs(buf);\r
899     sfree(buf);\r
900     va_end(ap);\r
904 void debug_memdump(const void *buf, int len, int L)\r
906     int i;\r
907     const unsigned char *p = buf;\r
908     char foo[17];\r
909     if (L) {\r
910         int delta;\r
911         debug_printf("\t%d (0x%x) bytes:\n", len, len);\r
912         delta = 15 & (uintptr_t)p;\r
913         p -= delta;\r
914         len += delta;\r
915     }\r
916     for (; 0 < len; p += 16, len -= 16) {\r
917         dputs("  ");\r
918         if (L)\r
919             debug_printf("%p: ", p);\r
920         strcpy(foo, "................");        /* sixteen dots */\r
921         for (i = 0; i < 16 && i < len; ++i) {\r
922             if (&p[i] < (unsigned char *) buf) {\r
923                 dputs("   ");          /* 3 spaces */\r
924                 foo[i] = ' ';\r
925             } else {\r
926                 debug_printf("%c%02.2x",\r
927                         &p[i] != (unsigned char *) buf\r
928                         && i % 4 ? '.' : ' ', p[i]\r
929                     );\r
930                 if (p[i] >= ' ' && p[i] <= '~')\r
931                     foo[i] = (char) p[i];\r
932             }\r
933         }\r
934         foo[i] = '\0';\r
935         debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo);\r
936     }\r
939 #endif                          /* def DEBUG */\r
941 /*\r
942  * Determine whether or not a Conf represents a session which can\r
943  * sensibly be launched right now.\r
944  */\r
945 int conf_launchable(Conf *conf)\r
947     if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)\r
948         return conf_get_str(conf, CONF_serline)[0] != 0;\r
949     else\r
950         return conf_get_str(conf, CONF_host)[0] != 0;\r
953 char const *conf_dest(Conf *conf)\r
955     if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)\r
956         return conf_get_str(conf, CONF_serline);\r
957     else\r
958         return conf_get_str(conf, CONF_host);\r
961 #ifndef PLATFORM_HAS_SMEMCLR\r
962 /*\r
963  * Securely wipe memory.\r
964  *\r
965  * The actual wiping is no different from what memset would do: the\r
966  * point of 'securely' is to try to be sure over-clever compilers\r
967  * won't optimise away memsets on variables that are about to be freed\r
968  * or go out of scope. See\r
969  * https://buildsecurityin.us-cert.gov/bsi-rules/home/g1/771-BSI.html\r
970  *\r
971  * Some platforms (e.g. Windows) may provide their own version of this\r
972  * function.\r
973  */\r
974 void smemclr(void *b, size_t n) {\r
975     volatile char *vp;\r
977     if (b && n > 0) {\r
978         /*\r
979          * Zero out the memory.\r
980          */\r
981         memset(b, 0, n);\r
983         /*\r
984          * Perform a volatile access to the object, forcing the\r
985          * compiler to admit that the previous memset was important.\r
986          *\r
987          * This while loop should in practice run for zero iterations\r
988          * (since we know we just zeroed the object out), but in\r
989          * theory (as far as the compiler knows) it might range over\r
990          * the whole object. (If we had just written, say, '*vp =\r
991          * *vp;', a compiler could in principle have 'helpfully'\r
992          * optimised the memset into only zeroing out the first byte.\r
993          * This should be robust.)\r
994          */\r
995         vp = b;\r
996         while (*vp) vp++;\r
997     }\r
999 #endif\r
1001 /*\r
1002  * Validate a manual host key specification (either entered in the\r
1003  * GUI, or via -hostkey). If valid, we return TRUE, and update 'key'\r
1004  * to contain a canonicalised version of the key string in 'key'\r
1005  * (which is guaranteed to take up at most as much space as the\r
1006  * original version), suitable for putting into the Conf. If not\r
1007  * valid, we return FALSE.\r
1008  */\r
1009 int validate_manual_hostkey(char *key)\r
1011     char *p, *q, *r, *s;\r
1013     /*\r
1014      * Step through the string word by word, looking for a word that's\r
1015      * in one of the formats we like.\r
1016      */\r
1017     p = key;\r
1018     while ((p += strspn(p, " \t"))[0]) {\r
1019         q = p;\r
1020         p += strcspn(p, " \t");\r
1021         if (*p) *p++ = '\0';\r
1023         /*\r
1024          * Now q is our word.\r
1025          */\r
1027         if (strlen(q) == 16*3 - 1 &&\r
1028             q[strspn(q, "0123456789abcdefABCDEF:")] == 0) {\r
1029             /*\r
1030              * Might be a key fingerprint. Check the colons are in the\r
1031              * right places, and if so, return the same fingerprint\r
1032              * canonicalised into lowercase.\r
1033              */\r
1034             int i;\r
1035             for (i = 0; i < 16; i++)\r
1036                 if (q[3*i] == ':' || q[3*i+1] == ':')\r
1037                     goto not_fingerprint; /* sorry */\r
1038             for (i = 0; i < 15; i++)\r
1039                 if (q[3*i+2] != ':')\r
1040                     goto not_fingerprint; /* sorry */\r
1041             for (i = 0; i < 16*3 - 1; i++)\r
1042                 key[i] = tolower(q[i]);\r
1043             key[16*3 - 1] = '\0';\r
1044             return TRUE;\r
1045         }\r
1046       not_fingerprint:;\r
1048         /*\r
1049          * Before we check for a public-key blob, trim newlines out of\r
1050          * the middle of the word, in case someone's managed to paste\r
1051          * in a public-key blob _with_ them.\r
1052          */\r
1053         for (r = s = q; *r; r++)\r
1054             if (*r != '\n' && *r != '\r')\r
1055                 *s++ = *r;\r
1056         *s = '\0';\r
1058         if (strlen(q) % 4 == 0 && strlen(q) > 2*4 &&\r
1059             q[strspn(q, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"\r
1060                      "abcdefghijklmnopqrstuvwxyz+/=")] == 0) {\r
1061             /*\r
1062              * Might be a base64-encoded SSH-2 public key blob. Check\r
1063              * that it starts with a sensible algorithm string. No\r
1064              * canonicalisation is necessary for this string type.\r
1065              *\r
1066              * The algorithm string must be at most 64 characters long\r
1067              * (RFC 4251 section 6).\r
1068              */\r
1069             unsigned char decoded[6];\r
1070             unsigned alglen;\r
1071             int minlen;\r
1072             int len = 0;\r
1074             len += base64_decode_atom(q, decoded+len);\r
1075             if (len < 3)\r
1076                 goto not_ssh2_blob;    /* sorry */\r
1077             len += base64_decode_atom(q+4, decoded+len);\r
1078             if (len < 4)\r
1079                 goto not_ssh2_blob;    /* sorry */\r
1081             alglen = GET_32BIT_MSB_FIRST(decoded);\r
1082             if (alglen > 64)\r
1083                 goto not_ssh2_blob;    /* sorry */\r
1085             minlen = ((alglen + 4) + 2) / 3;\r
1086             if (strlen(q) < minlen)\r
1087                 goto not_ssh2_blob;    /* sorry */\r
1089             strcpy(key, q);\r
1090             return TRUE;\r
1091         }\r
1092       not_ssh2_blob:;\r
1093     }\r
1095     return FALSE;\r
1098 int smemeq(const void *av, const void *bv, size_t len)\r
1100     const unsigned char *a = (const unsigned char *)av;\r
1101     const unsigned char *b = (const unsigned char *)bv;\r
1102     unsigned val = 0;\r
1104     while (len-- > 0) {\r
1105         val |= *a++ ^ *b++;\r
1106     }\r
1107     /* Now val is 0 iff we want to return 1, and in the range\r
1108      * 0x01..0xFF iff we want to return 0. So subtracting from 0x100\r
1109      * will clear bit 8 iff we want to return 0, and leave it set iff\r
1110      * we want to return 1, so then we can just shift down. */\r
1111     return (0x100 - val) >> 8;\r
1114 int match_ssh_id(int stringlen, const void *string, const char *id)\r
1116     int idlen = strlen(id);\r
1117     return (idlen == stringlen && !memcmp(string, id, idlen));\r
1120 void *get_ssh_string(int *datalen, const void **data, int *stringlen)\r
1122     void *ret;\r
1123     unsigned int len;\r
1125     if (*datalen < 4)\r
1126         return NULL;\r
1127     len = GET_32BIT_MSB_FIRST((const unsigned char *)*data);\r
1128     if (*datalen - 4 < len)\r
1129         return NULL;\r
1130     ret = (void *)((const char *)*data + 4);\r
1131     *datalen -= len + 4;\r
1132     *data = (const char *)*data + len + 4;\r
1133     *stringlen = len;\r
1134     return ret;\r
1137 int get_ssh_uint32(int *datalen, const void **data, unsigned *ret)\r
1139     if (*datalen < 4)\r
1140         return FALSE;\r
1141     *ret = GET_32BIT_MSB_FIRST((const unsigned char *)*data);\r
1142     *datalen -= 4;\r
1143     *data = (const char *)*data + 4;\r
1144     return TRUE;\r
1147 int strstartswith(const char *s, const char *t)\r
1149     return !memcmp(s, t, strlen(t));\r
1152 int strendswith(const char *s, const char *t)\r
1154     size_t slen = strlen(s), tlen = strlen(t);\r
1155     return slen >= tlen && !strcmp(s + (slen - tlen), t);\r
1158 char *buildinfo(const char *newline)\r
1160     strbuf *buf = strbuf_new();\r
1161     extern const char commitid[];      /* in commitid.c */\r
1163     strbuf_catf(buf, "Build platform: %d-bit %s",\r
1164                 (int)(CHAR_BIT * sizeof(void *)),\r
1165                 BUILDINFO_PLATFORM);\r
1167 #ifdef __clang_version__\r
1168     strbuf_catf(buf, "%sCompiler: clang %s", newline, __clang_version__);\r
1169 #elif defined __GNUC__ && defined __VERSION__\r
1170     strbuf_catf(buf, "%sCompiler: gcc %s", newline, __VERSION__);\r
1171 #elif defined _MSC_VER\r
1172     strbuf_catf(buf, "%sCompiler: Visual Studio", newline);\r
1173 #if _MSC_VER == 1900\r
1174     strbuf_catf(buf, " 2015 / MSVC++ 14.0");\r
1175 #elif _MSC_VER == 1800\r
1176     strbuf_catf(buf, " 2013 / MSVC++ 12.0");\r
1177 #elif _MSC_VER == 1700\r
1178     strbuf_catf(buf, " 2012 / MSVC++ 11.0");\r
1179 #elif _MSC_VER == 1600\r
1180     strbuf_catf(buf, " 2010 / MSVC++ 10.0");\r
1181 #elif  _MSC_VER == 1500\r
1182     strbuf_catf(buf, " 2008 / MSVC++ 9.0");\r
1183 #elif  _MSC_VER == 1400\r
1184     strbuf_catf(buf, " 2005 / MSVC++ 8.0");\r
1185 #elif  _MSC_VER == 1310\r
1186     strbuf_catf(buf, " 2003 / MSVC++ 7.1");\r
1187 #else\r
1188     strbuf_catf(buf, ", unrecognised version");\r
1189 #endif\r
1190     strbuf_catf(buf, " (_MSC_VER=%d)", (int)_MSC_VER);\r
1191 #endif\r
1193 #ifdef BUILDINFO_GTK\r
1194     {\r
1195         char *gtk_buildinfo = buildinfo_gtk_version();\r
1196         if (gtk_buildinfo) {\r
1197             strbuf_catf(buf, "%sCompiled against GTK version %s",\r
1198                         newline, gtk_buildinfo);\r
1199             sfree(gtk_buildinfo);\r
1200         }\r
1201     }\r
1202 #endif\r
1204 #ifdef NO_SECURITY\r
1205     strbuf_catf(buf, "%sBuild option: NO_SECURITY", newline);\r
1206 #endif\r
1207 #ifdef NO_SECUREZEROMEMORY\r
1208     strbuf_catf(buf, "%sBuild option: NO_SECUREZEROMEMORY", newline);\r
1209 #endif\r
1210 #ifdef NO_IPV6\r
1211     strbuf_catf(buf, "%sBuild option: NO_IPV6", newline);\r
1212 #endif\r
1213 #ifdef NO_GSSAPI\r
1214     strbuf_catf(buf, "%sBuild option: NO_GSSAPI", newline);\r
1215 #endif\r
1216 #ifdef STATIC_GSSAPI\r
1217     strbuf_catf(buf, "%sBuild option: STATIC_GSSAPI", newline);\r
1218 #endif\r
1219 #ifdef UNPROTECT\r
1220     strbuf_catf(buf, "%sBuild option: UNPROTECT", newline);\r
1221 #endif\r
1222 #ifdef FUZZING\r
1223     strbuf_catf(buf, "%sBuild option: FUZZING", newline);\r
1224 #endif\r
1225 #ifdef DEBUG\r
1226     strbuf_catf(buf, "%sBuild option: DEBUG", newline);\r
1227 #endif\r
1229     strbuf_catf(buf, "%sSource commit: %s", newline, commitid);\r
1231     return strbuf_to_str(buf);\r