For the inline diff, reverse the diff parts for the right view to get a diff consiste...
[TortoiseGit.git] / src / TortoisePlink / MISC.C
blob26922cc3ab0bd75f960dec700672064447509c6b
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
13 /*\r
14  * Parse a string block size specification. This is approximately a\r
15  * subset of the block size specs supported by GNU fileutils:\r
16  *  "nk" = n kilobytes\r
17  *  "nM" = n megabytes\r
18  *  "nG" = n gigabytes\r
19  * All numbers are decimal, and suffixes refer to powers of two.\r
20  * Case-insensitive.\r
21  */\r
22 unsigned long parse_blocksize(const char *bs)\r
23 {\r
24     char *suf;\r
25     unsigned long r = strtoul(bs, &suf, 10);\r
26     if (*suf != '\0') {\r
27         while (*suf && isspace((unsigned char)*suf)) suf++;\r
28         switch (*suf) {\r
29           case 'k': case 'K':\r
30             r *= 1024ul;\r
31             break;\r
32           case 'm': case 'M':\r
33             r *= 1024ul * 1024ul;\r
34             break;\r
35           case 'g': case 'G':\r
36             r *= 1024ul * 1024ul * 1024ul;\r
37             break;\r
38           case '\0':\r
39           default:\r
40             break;\r
41         }\r
42     }\r
43     return r;\r
44 }\r
46 /*\r
47  * Parse a ^C style character specification.\r
48  * Returns NULL in `next' if we didn't recognise it as a control character,\r
49  * in which case `c' should be ignored.\r
50  * The precise current parsing is an oddity inherited from the terminal\r
51  * answerback-string parsing code. All sequences start with ^; all except\r
52  * ^<123> are two characters. The ones that are worth keeping are probably:\r
53  *   ^?             127\r
54  *   ^@A-Z[\]^_     0-31\r
55  *   a-z            1-26\r
56  *   <num>          specified by number (decimal, 0octal, 0xHEX)\r
57  *   ~              ^ escape\r
58  */\r
59 char ctrlparse(char *s, char **next)\r
60 {\r
61     char c = 0;\r
62     if (*s != '^') {\r
63         *next = NULL;\r
64     } else {\r
65         s++;\r
66         if (*s == '\0') {\r
67             *next = NULL;\r
68         } else if (*s == '<') {\r
69             s++;\r
70             c = (char)strtol(s, next, 0);\r
71             if ((*next == s) || (**next != '>')) {\r
72                 c = 0;\r
73                 *next = NULL;\r
74             } else\r
75                 (*next)++;\r
76         } else if (*s >= 'a' && *s <= 'z') {\r
77             c = (*s - ('a' - 1));\r
78             *next = s+1;\r
79         } else if ((*s >= '@' && *s <= '_') || *s == '?' || (*s & 0x80)) {\r
80             c = ('@' ^ *s);\r
81             *next = s+1;\r
82         } else if (*s == '~') {\r
83             c = '^';\r
84             *next = s+1;\r
85         }\r
86     }\r
87     return c;\r
88 }\r
90 /*\r
91  * Find a character in a string, unless it's a colon contained within\r
92  * square brackets. Used for untangling strings of the form\r
93  * 'host:port', where host can be an IPv6 literal.\r
94  *\r
95  * We provide several variants of this function, with semantics like\r
96  * various standard string.h functions.\r
97  */\r
98 static const char *host_strchr_internal(const char *s, const char *set,\r
99                                         int first)\r
101     int brackets = 0;\r
102     const char *ret = NULL;\r
104     while (1) {\r
105         if (!*s)\r
106             return ret;\r
108         if (*s == '[')\r
109             brackets++;\r
110         else if (*s == ']' && brackets > 0)\r
111             brackets--;\r
112         else if (brackets && *s == ':')\r
113             /* never match */ ;\r
114         else if (strchr(set, *s)) {\r
115             ret = s;\r
116             if (first)\r
117                 return ret;\r
118         }\r
120         s++;\r
121     }\r
123 size_t host_strcspn(const char *s, const char *set)\r
125     const char *answer = host_strchr_internal(s, set, TRUE);\r
126     if (answer)\r
127         return answer - s;\r
128     else\r
129         return strlen(s);\r
131 char *host_strchr(const char *s, int c)\r
133     char set[2];\r
134     set[0] = c;\r
135     set[1] = '\0';\r
136     return (char *) host_strchr_internal(s, set, TRUE);\r
138 char *host_strrchr(const char *s, int c)\r
140     char set[2];\r
141     set[0] = c;\r
142     set[1] = '\0';\r
143     return (char *) host_strchr_internal(s, set, FALSE);\r
146 #ifdef TEST_HOST_STRFOO\r
147 int main(void)\r
149     int passes = 0, fails = 0;\r
151 #define TEST1(func, string, arg2, suffix, result) do                    \\r
152     {                                                                   \\r
153         const char *str = string;                                       \\r
154         unsigned ret = func(string, arg2) suffix;                       \\r
155         if (ret == result) {                                            \\r
156             passes++;                                                   \\r
157         } else {                                                        \\r
158             printf("fail: %s(%s,%s)%s = %u, expected %u\n",             \\r
159                    #func, #string, #arg2, #suffix, ret, result);        \\r
160             fails++;                                                    \\r
161         }                                                               \\r
162 } while (0)\r
164     TEST1(host_strchr, "[1:2:3]:4:5", ':', -str, 7);\r
165     TEST1(host_strrchr, "[1:2:3]:4:5", ':', -str, 9);\r
166     TEST1(host_strcspn, "[1:2:3]:4:5", "/:",, 7);\r
167     TEST1(host_strchr, "[1:2:3]", ':', == NULL, 1);\r
168     TEST1(host_strrchr, "[1:2:3]", ':', == NULL, 1);\r
169     TEST1(host_strcspn, "[1:2:3]", "/:",, 7);\r
170     TEST1(host_strcspn, "[1:2/3]", "/:",, 4);\r
171     TEST1(host_strcspn, "[1:2:3]/", "/:",, 7);\r
173     printf("passed %d failed %d total %d\n", passes, fails, passes+fails);\r
174     return fails != 0 ? 1 : 0;\r
176 /* Stubs to stop the rest of this module causing compile failures. */\r
177 void modalfatalbox(char *fmt, ...) {}\r
178 int conf_get_int(Conf *conf, int primary) { return 0; }\r
179 char *conf_get_str(Conf *conf, int primary) { return NULL; }\r
180 #endif /* TEST_HOST_STRFOO */\r
182 /*\r
183  * Trim square brackets off the outside of an IPv6 address literal.\r
184  * Leave all other strings unchanged. Returns a fresh dynamically\r
185  * allocated string.\r
186  */\r
187 char *host_strduptrim(const char *s)\r
189     if (s[0] == '[') {\r
190         const char *p = s+1;\r
191         int colons = 0;\r
192         while (*p && *p != ']') {\r
193             if (isxdigit((unsigned char)*p))\r
194                 /* OK */;\r
195             else if (*p == ':')\r
196                 colons++;\r
197             else\r
198                 break;\r
199             p++;\r
200         }\r
201         if (*p == ']' && !p[1] && colons > 1) {\r
202             /*\r
203              * This looks like an IPv6 address literal (hex digits and\r
204              * at least two colons, contained in square brackets).\r
205              * Trim off the brackets.\r
206              */\r
207             return dupprintf("%.*s", (int)(p - (s+1)), s+1);\r
208         }\r
209     }\r
211     /*\r
212      * Any other shape of string is simply duplicated.\r
213      */\r
214     return dupstr(s);\r
217 prompts_t *new_prompts(void *frontend)\r
219     prompts_t *p = snew(prompts_t);\r
220     p->prompts = NULL;\r
221     p->n_prompts = 0;\r
222     p->frontend = frontend;\r
223     p->data = NULL;\r
224     p->to_server = TRUE; /* to be on the safe side */\r
225     p->name = p->instruction = NULL;\r
226     p->name_reqd = p->instr_reqd = FALSE;\r
227     return p;\r
229 void add_prompt(prompts_t *p, char *promptstr, int echo)\r
231     prompt_t *pr = snew(prompt_t);\r
232     pr->prompt = promptstr;\r
233     pr->echo = echo;\r
234     pr->result = NULL;\r
235     pr->resultsize = 0;\r
236     p->n_prompts++;\r
237     p->prompts = sresize(p->prompts, p->n_prompts, prompt_t *);\r
238     p->prompts[p->n_prompts-1] = pr;\r
240 void prompt_ensure_result_size(prompt_t *pr, int newlen)\r
242     if ((int)pr->resultsize < newlen) {\r
243         char *newbuf;\r
244         newlen = newlen * 5 / 4 + 512; /* avoid too many small allocs */\r
246         /*\r
247          * We don't use sresize / realloc here, because we will be\r
248          * storing sensitive stuff like passwords in here, and we want\r
249          * to make sure that the data doesn't get copied around in\r
250          * memory without the old copy being destroyed.\r
251          */\r
252         newbuf = snewn(newlen, char);\r
253         memcpy(newbuf, pr->result, pr->resultsize);\r
254         smemclr(pr->result, pr->resultsize);\r
255         sfree(pr->result);\r
256         pr->result = newbuf;\r
257         pr->resultsize = newlen;\r
258     }\r
260 void prompt_set_result(prompt_t *pr, const char *newstr)\r
262     prompt_ensure_result_size(pr, strlen(newstr) + 1);\r
263     strcpy(pr->result, newstr);\r
265 void free_prompts(prompts_t *p)\r
267     size_t i;\r
268     for (i=0; i < p->n_prompts; i++) {\r
269         prompt_t *pr = p->prompts[i];\r
270         smemclr(pr->result, pr->resultsize); /* burn the evidence */\r
271         sfree(pr->result);\r
272         sfree(pr->prompt);\r
273         sfree(pr);\r
274     }\r
275     sfree(p->prompts);\r
276     sfree(p->name);\r
277     sfree(p->instruction);\r
278     sfree(p);\r
281 /* ----------------------------------------------------------------------\r
282  * String handling routines.\r
283  */\r
285 char *dupstr(const char *s)\r
287     char *p = NULL;\r
288     if (s) {\r
289         int len = strlen(s);\r
290         p = snewn(len + 1, char);\r
291         strcpy(p, s);\r
292     }\r
293     return p;\r
296 /* Allocate the concatenation of N strings. Terminate arg list with NULL. */\r
297 char *dupcat(const char *s1, ...)\r
299     int len;\r
300     char *p, *q, *sn;\r
301     va_list ap;\r
303     len = strlen(s1);\r
304     va_start(ap, s1);\r
305     while (1) {\r
306         sn = va_arg(ap, char *);\r
307         if (!sn)\r
308             break;\r
309         len += strlen(sn);\r
310     }\r
311     va_end(ap);\r
313     p = snewn(len + 1, char);\r
314     strcpy(p, s1);\r
315     q = p + strlen(p);\r
317     va_start(ap, s1);\r
318     while (1) {\r
319         sn = va_arg(ap, char *);\r
320         if (!sn)\r
321             break;\r
322         strcpy(q, sn);\r
323         q += strlen(q);\r
324     }\r
325     va_end(ap);\r
327     return p;\r
330 void burnstr(char *string)             /* sfree(str), only clear it first */\r
332     if (string) {\r
333         smemclr(string, strlen(string));\r
334         sfree(string);\r
335     }\r
338 int toint(unsigned u)\r
340     /*\r
341      * Convert an unsigned to an int, without running into the\r
342      * undefined behaviour which happens by the strict C standard if\r
343      * the value overflows. You'd hope that sensible compilers would\r
344      * do the sensible thing in response to a cast, but actually I\r
345      * don't trust modern compilers not to do silly things like\r
346      * assuming that _obviously_ you wouldn't have caused an overflow\r
347      * and so they can elide an 'if (i < 0)' test immediately after\r
348      * the cast.\r
349      *\r
350      * Sensible compilers ought of course to optimise this entire\r
351      * function into 'just return the input value'!\r
352      */\r
353     if (u <= (unsigned)INT_MAX)\r
354         return (int)u;\r
355     else if (u >= (unsigned)INT_MIN)   /* wrap in cast _to_ unsigned is OK */\r
356         return INT_MIN + (int)(u - (unsigned)INT_MIN);\r
357     else\r
358         return INT_MIN; /* fallback; should never occur on binary machines */\r
361 /*\r
362  * Do an sprintf(), but into a custom-allocated buffer.\r
363  * \r
364  * Currently I'm doing this via vsnprintf. This has worked so far,\r
365  * but it's not good, because vsnprintf is not available on all\r
366  * platforms. There's an ifdef to use `_vsnprintf', which seems\r
367  * to be the local name for it on Windows. Other platforms may\r
368  * lack it completely, in which case it'll be time to rewrite\r
369  * this function in a totally different way.\r
370  * \r
371  * The only `properly' portable solution I can think of is to\r
372  * implement my own format string scanner, which figures out an\r
373  * upper bound for the length of each formatting directive,\r
374  * allocates the buffer as it goes along, and calls sprintf() to\r
375  * actually process each directive. If I ever need to actually do\r
376  * this, some caveats:\r
377  * \r
378  *  - It's very hard to find a reliable upper bound for\r
379  *    floating-point values. %f, in particular, when supplied with\r
380  *    a number near to the upper or lower limit of representable\r
381  *    numbers, could easily take several hundred characters. It's\r
382  *    probably feasible to predict this statically using the\r
383  *    constants in <float.h>, or even to predict it dynamically by\r
384  *    looking at the exponent of the specific float provided, but\r
385  *    it won't be fun.\r
386  * \r
387  *  - Don't forget to _check_, after calling sprintf, that it's\r
388  *    used at most the amount of space we had available.\r
389  * \r
390  *  - Fault any formatting directive we don't fully understand. The\r
391  *    aim here is to _guarantee_ that we never overflow the buffer,\r
392  *    because this is a security-critical function. If we see a\r
393  *    directive we don't know about, we should panic and die rather\r
394  *    than run any risk.\r
395  */\r
396 char *dupprintf(const char *fmt, ...)\r
398     char *ret;\r
399     va_list ap;\r
400     va_start(ap, fmt);\r
401     ret = dupvprintf(fmt, ap);\r
402     va_end(ap);\r
403     return ret;\r
405 char *dupvprintf(const char *fmt, va_list ap)\r
407     char *buf;\r
408     int len, size;\r
410     buf = snewn(512, char);\r
411     size = 512;\r
413     while (1) {\r
414 #ifdef _WINDOWS\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, 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, 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             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         buf = sresize(buf, size, char);\r
449     }\r
452 /*\r
453  * Read an entire line of text from a file. Return a buffer\r
454  * malloced to be as big as necessary (caller must free).\r
455  */\r
456 char *fgetline(FILE *fp)\r
458     char *ret = snewn(512, char);\r
459     int size = 512, len = 0;\r
460     while (fgets(ret + len, size - len, fp)) {\r
461         len += strlen(ret + len);\r
462         if (ret[len-1] == '\n')\r
463             break;                     /* got a newline, we're done */\r
464         size = len + 512;\r
465         ret = sresize(ret, size, char);\r
466     }\r
467     if (len == 0) {                    /* first fgets returned NULL */\r
468         sfree(ret);\r
469         return NULL;\r
470     }\r
471     ret[len] = '\0';\r
472     return ret;\r
475 /* ----------------------------------------------------------------------\r
476  * Core base64 encoding and decoding routines.\r
477  */\r
479 void base64_encode_atom(unsigned char *data, int n, char *out)\r
481     static const char base64_chars[] =\r
482         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";\r
484     unsigned word;\r
486     word = data[0] << 16;\r
487     if (n > 1)\r
488         word |= data[1] << 8;\r
489     if (n > 2)\r
490         word |= data[2];\r
491     out[0] = base64_chars[(word >> 18) & 0x3F];\r
492     out[1] = base64_chars[(word >> 12) & 0x3F];\r
493     if (n > 1)\r
494         out[2] = base64_chars[(word >> 6) & 0x3F];\r
495     else\r
496         out[2] = '=';\r
497     if (n > 2)\r
498         out[3] = base64_chars[word & 0x3F];\r
499     else\r
500         out[3] = '=';\r
503 int base64_decode_atom(char *atom, unsigned char *out)\r
505     int vals[4];\r
506     int i, v, len;\r
507     unsigned word;\r
508     char c;\r
510     for (i = 0; i < 4; i++) {\r
511         c = atom[i];\r
512         if (c >= 'A' && c <= 'Z')\r
513             v = c - 'A';\r
514         else if (c >= 'a' && c <= 'z')\r
515             v = c - 'a' + 26;\r
516         else if (c >= '0' && c <= '9')\r
517             v = c - '0' + 52;\r
518         else if (c == '+')\r
519             v = 62;\r
520         else if (c == '/')\r
521             v = 63;\r
522         else if (c == '=')\r
523             v = -1;\r
524         else\r
525             return 0;                  /* invalid atom */\r
526         vals[i] = v;\r
527     }\r
529     if (vals[0] == -1 || vals[1] == -1)\r
530         return 0;\r
531     if (vals[2] == -1 && vals[3] != -1)\r
532         return 0;\r
534     if (vals[3] != -1)\r
535         len = 3;\r
536     else if (vals[2] != -1)\r
537         len = 2;\r
538     else\r
539         len = 1;\r
541     word = ((vals[0] << 18) |\r
542             (vals[1] << 12) | ((vals[2] & 0x3F) << 6) | (vals[3] & 0x3F));\r
543     out[0] = (word >> 16) & 0xFF;\r
544     if (len > 1)\r
545         out[1] = (word >> 8) & 0xFF;\r
546     if (len > 2)\r
547         out[2] = word & 0xFF;\r
548     return len;\r
551 /* ----------------------------------------------------------------------\r
552  * Generic routines to deal with send buffers: a linked list of\r
553  * smallish blocks, with the operations\r
554  * \r
555  *  - add an arbitrary amount of data to the end of the list\r
556  *  - remove the first N bytes from the list\r
557  *  - return a (pointer,length) pair giving some initial data in\r
558  *    the list, suitable for passing to a send or write system\r
559  *    call\r
560  *  - retrieve a larger amount of initial data from the list\r
561  *  - return the current size of the buffer chain in bytes\r
562  */\r
564 #define BUFFER_MIN_GRANULE  512\r
566 struct bufchain_granule {\r
567     struct bufchain_granule *next;\r
568     char *bufpos, *bufend, *bufmax;\r
569 };\r
571 void bufchain_init(bufchain *ch)\r
573     ch->head = ch->tail = NULL;\r
574     ch->buffersize = 0;\r
577 void bufchain_clear(bufchain *ch)\r
579     struct bufchain_granule *b;\r
580     while (ch->head) {\r
581         b = ch->head;\r
582         ch->head = ch->head->next;\r
583         sfree(b);\r
584     }\r
585     ch->tail = NULL;\r
586     ch->buffersize = 0;\r
589 int bufchain_size(bufchain *ch)\r
591     return ch->buffersize;\r
594 void bufchain_add(bufchain *ch, const void *data, int len)\r
596     const char *buf = (const char *)data;\r
598     if (len == 0) return;\r
600     ch->buffersize += len;\r
602     while (len > 0) {\r
603         if (ch->tail && ch->tail->bufend < ch->tail->bufmax) {\r
604             int copylen = min(len, ch->tail->bufmax - ch->tail->bufend);\r
605             memcpy(ch->tail->bufend, buf, copylen);\r
606             buf += copylen;\r
607             len -= copylen;\r
608             ch->tail->bufend += copylen;\r
609         }\r
610         if (len > 0) {\r
611             int grainlen =\r
612                 max(sizeof(struct bufchain_granule) + len, BUFFER_MIN_GRANULE);\r
613             struct bufchain_granule *newbuf;\r
614             newbuf = smalloc(grainlen);\r
615             newbuf->bufpos = newbuf->bufend =\r
616                 (char *)newbuf + sizeof(struct bufchain_granule);\r
617             newbuf->bufmax = (char *)newbuf + grainlen;\r
618             newbuf->next = NULL;\r
619             if (ch->tail)\r
620                 ch->tail->next = newbuf;\r
621             else\r
622                 ch->head = newbuf;\r
623             ch->tail = newbuf;\r
624         }\r
625     }\r
628 void bufchain_consume(bufchain *ch, int len)\r
630     struct bufchain_granule *tmp;\r
632     assert(ch->buffersize >= len);\r
633     while (len > 0) {\r
634         int remlen = len;\r
635         assert(ch->head != NULL);\r
636         if (remlen >= ch->head->bufend - ch->head->bufpos) {\r
637             remlen = ch->head->bufend - ch->head->bufpos;\r
638             tmp = ch->head;\r
639             ch->head = tmp->next;\r
640             if (!ch->head)\r
641                 ch->tail = NULL;\r
642             sfree(tmp);\r
643         } else\r
644             ch->head->bufpos += remlen;\r
645         ch->buffersize -= remlen;\r
646         len -= remlen;\r
647     }\r
650 void bufchain_prefix(bufchain *ch, void **data, int *len)\r
652     *len = ch->head->bufend - ch->head->bufpos;\r
653     *data = ch->head->bufpos;\r
656 void bufchain_fetch(bufchain *ch, void *data, int len)\r
658     struct bufchain_granule *tmp;\r
659     char *data_c = (char *)data;\r
661     tmp = ch->head;\r
663     assert(ch->buffersize >= len);\r
664     while (len > 0) {\r
665         int remlen = len;\r
667         assert(tmp != NULL);\r
668         if (remlen >= tmp->bufend - tmp->bufpos)\r
669             remlen = tmp->bufend - tmp->bufpos;\r
670         memcpy(data_c, tmp->bufpos, remlen);\r
672         tmp = tmp->next;\r
673         len -= remlen;\r
674         data_c += remlen;\r
675     }\r
678 /* ----------------------------------------------------------------------\r
679  * My own versions of malloc, realloc and free. Because I want\r
680  * malloc and realloc to bomb out and exit the program if they run\r
681  * out of memory, realloc to reliably call malloc if passed a NULL\r
682  * pointer, and free to reliably do nothing if passed a NULL\r
683  * pointer. We can also put trace printouts in, if we need to; and\r
684  * we can also replace the allocator with an ElectricFence-like\r
685  * one.\r
686  */\r
688 #ifdef MINEFIELD\r
689 void *minefield_c_malloc(size_t size);\r
690 void minefield_c_free(void *p);\r
691 void *minefield_c_realloc(void *p, size_t size);\r
692 #endif\r
694 #ifdef MALLOC_LOG\r
695 static FILE *fp = NULL;\r
697 static char *mlog_file = NULL;\r
698 static int mlog_line = 0;\r
700 void mlog(char *file, int line)\r
702     mlog_file = file;\r
703     mlog_line = line;\r
704     if (!fp) {\r
705         fp = fopen("putty_mem.log", "w");\r
706         setvbuf(fp, NULL, _IONBF, BUFSIZ);\r
707     }\r
708     if (fp)\r
709         fprintf(fp, "%s:%d: ", file, line);\r
711 #endif\r
713 void *safemalloc(size_t n, size_t size)\r
715     void *p;\r
717     if (n > INT_MAX / size) {\r
718         p = NULL;\r
719     } else {\r
720         size *= n;\r
721         if (size == 0) size = 1;\r
722 #ifdef MINEFIELD\r
723         p = minefield_c_malloc(size);\r
724 #else\r
725         p = malloc(size);\r
726 #endif\r
727     }\r
729     if (!p) {\r
730         char str[200];\r
731 #ifdef MALLOC_LOG\r
732         sprintf(str, "Out of memory! (%s:%d, size=%d)",\r
733                 mlog_file, mlog_line, size);\r
734         fprintf(fp, "*** %s\n", str);\r
735         fclose(fp);\r
736 #else\r
737         strcpy(str, "Out of memory!");\r
738 #endif\r
739         modalfatalbox(str);\r
740     }\r
741 #ifdef MALLOC_LOG\r
742     if (fp)\r
743         fprintf(fp, "malloc(%d) returns %p\n", size, p);\r
744 #endif\r
745     return p;\r
748 void *saferealloc(void *ptr, size_t n, size_t size)\r
750     void *p;\r
752     if (n > INT_MAX / size) {\r
753         p = NULL;\r
754     } else {\r
755         size *= n;\r
756         if (!ptr) {\r
757 #ifdef MINEFIELD\r
758             p = minefield_c_malloc(size);\r
759 #else\r
760             p = malloc(size);\r
761 #endif\r
762         } else {\r
763 #ifdef MINEFIELD\r
764             p = minefield_c_realloc(ptr, size);\r
765 #else\r
766             p = realloc(ptr, size);\r
767 #endif\r
768         }\r
769     }\r
771     if (!p) {\r
772         char str[200];\r
773 #ifdef MALLOC_LOG\r
774         sprintf(str, "Out of memory! (%s:%d, size=%d)",\r
775                 mlog_file, mlog_line, size);\r
776         fprintf(fp, "*** %s\n", str);\r
777         fclose(fp);\r
778 #else\r
779         strcpy(str, "Out of memory!");\r
780 #endif\r
781         modalfatalbox(str);\r
782     }\r
783 #ifdef MALLOC_LOG\r
784     if (fp)\r
785         fprintf(fp, "realloc(%p,%d) returns %p\n", ptr, size, p);\r
786 #endif\r
787     return p;\r
790 void safefree(void *ptr)\r
792     if (ptr) {\r
793 #ifdef MALLOC_LOG\r
794         if (fp)\r
795             fprintf(fp, "free(%p)\n", ptr);\r
796 #endif\r
797 #ifdef MINEFIELD\r
798         minefield_c_free(ptr);\r
799 #else\r
800         free(ptr);\r
801 #endif\r
802     }\r
803 #ifdef MALLOC_LOG\r
804     else if (fp)\r
805         fprintf(fp, "freeing null pointer - no action taken\n");\r
806 #endif\r
809 /* ----------------------------------------------------------------------\r
810  * Debugging routines.\r
811  */\r
813 #ifdef DEBUG\r
814 extern void dputs(char *);             /* defined in per-platform *misc.c */\r
816 void debug_printf(char *fmt, ...)\r
818     char *buf;\r
819     va_list ap;\r
821     va_start(ap, fmt);\r
822     buf = dupvprintf(fmt, ap);\r
823     dputs(buf);\r
824     sfree(buf);\r
825     va_end(ap);\r
829 void debug_memdump(void *buf, int len, int L)\r
831     int i;\r
832     unsigned char *p = buf;\r
833     char foo[17];\r
834     if (L) {\r
835         int delta;\r
836         debug_printf("\t%d (0x%x) bytes:\n", len, len);\r
837         delta = 15 & (unsigned long int) p;\r
838         p -= delta;\r
839         len += delta;\r
840     }\r
841     for (; 0 < len; p += 16, len -= 16) {\r
842         dputs("  ");\r
843         if (L)\r
844             debug_printf("%p: ", p);\r
845         strcpy(foo, "................");        /* sixteen dots */\r
846         for (i = 0; i < 16 && i < len; ++i) {\r
847             if (&p[i] < (unsigned char *) buf) {\r
848                 dputs("   ");          /* 3 spaces */\r
849                 foo[i] = ' ';\r
850             } else {\r
851                 debug_printf("%c%02.2x",\r
852                         &p[i] != (unsigned char *) buf\r
853                         && i % 4 ? '.' : ' ', p[i]\r
854                     );\r
855                 if (p[i] >= ' ' && p[i] <= '~')\r
856                     foo[i] = (char) p[i];\r
857             }\r
858         }\r
859         foo[i] = '\0';\r
860         debug_printf("%*s%s\n", (16 - i) * 3 + 2, "", foo);\r
861     }\r
864 #endif                          /* def DEBUG */\r
866 /*\r
867  * Determine whether or not a Conf represents a session which can\r
868  * sensibly be launched right now.\r
869  */\r
870 int conf_launchable(Conf *conf)\r
872     if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)\r
873         return conf_get_str(conf, CONF_serline)[0] != 0;\r
874     else\r
875         return conf_get_str(conf, CONF_host)[0] != 0;\r
878 char const *conf_dest(Conf *conf)\r
880     if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)\r
881         return conf_get_str(conf, CONF_serline);\r
882     else\r
883         return conf_get_str(conf, CONF_host);\r
886 #ifndef PLATFORM_HAS_SMEMCLR\r
887 /*\r
888  * Securely wipe memory.\r
889  *\r
890  * The actual wiping is no different from what memset would do: the\r
891  * point of 'securely' is to try to be sure over-clever compilers\r
892  * won't optimise away memsets on variables that are about to be freed\r
893  * or go out of scope. See\r
894  * https://buildsecurityin.us-cert.gov/bsi-rules/home/g1/771-BSI.html\r
895  *\r
896  * Some platforms (e.g. Windows) may provide their own version of this\r
897  * function.\r
898  */\r
899 void smemclr(void *b, size_t n) {\r
900     volatile char *vp;\r
902     if (b && n > 0) {\r
903         /*\r
904          * Zero out the memory.\r
905          */\r
906         memset(b, 0, n);\r
908         /*\r
909          * Perform a volatile access to the object, forcing the\r
910          * compiler to admit that the previous memset was important.\r
911          *\r
912          * This while loop should in practice run for zero iterations\r
913          * (since we know we just zeroed the object out), but in\r
914          * theory (as far as the compiler knows) it might range over\r
915          * the whole object. (If we had just written, say, '*vp =\r
916          * *vp;', a compiler could in principle have 'helpfully'\r
917          * optimised the memset into only zeroing out the first byte.\r
918          * This should be robust.)\r
919          */\r
920         vp = b;\r
921         while (*vp) vp++;\r
922     }\r
924 #endif\r
926 /*\r
927  * Validate a manual host key specification (either entered in the\r
928  * GUI, or via -hostkey). If valid, we return TRUE, and update 'key'\r
929  * to contain a canonicalised version of the key string in 'key'\r
930  * (which is guaranteed to take up at most as much space as the\r
931  * original version), suitable for putting into the Conf. If not\r
932  * valid, we return FALSE.\r
933  */\r
934 int validate_manual_hostkey(char *key)\r
936     char *p, *q, *r, *s;\r
938     /*\r
939      * Step through the string word by word, looking for a word that's\r
940      * in one of the formats we like.\r
941      */\r
942     p = key;\r
943     while ((p += strspn(p, " \t"))[0]) {\r
944         q = p;\r
945         p += strcspn(p, " \t");\r
946         if (*p) *p++ = '\0';\r
948         /*\r
949          * Now q is our word.\r
950          */\r
952         if (strlen(q) == 16*3 - 1 &&\r
953             q[strspn(q, "0123456789abcdefABCDEF:")] == 0) {\r
954             /*\r
955              * Might be a key fingerprint. Check the colons are in the\r
956              * right places, and if so, return the same fingerprint\r
957              * canonicalised into lowercase.\r
958              */\r
959             int i;\r
960             for (i = 0; i < 16; i++)\r
961                 if (q[3*i] == ':' || q[3*i+1] == ':')\r
962                     goto not_fingerprint; /* sorry */\r
963             for (i = 0; i < 15; i++)\r
964                 if (q[3*i+2] != ':')\r
965                     goto not_fingerprint; /* sorry */\r
966             for (i = 0; i < 16*3 - 1; i++)\r
967                 key[i] = tolower(q[i]);\r
968             key[16*3 - 1] = '\0';\r
969             return TRUE;\r
970         }\r
971       not_fingerprint:;\r
973         /*\r
974          * Before we check for a public-key blob, trim newlines out of\r
975          * the middle of the word, in case someone's managed to paste\r
976          * in a public-key blob _with_ them.\r
977          */\r
978         for (r = s = q; *r; r++)\r
979             if (*r != '\n' && *r != '\r')\r
980                 *s++ = *r;\r
981         *s = '\0';\r
983         if (strlen(q) % 4 == 0 && strlen(q) > 2*4 &&\r
984             q[strspn(q, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"\r
985                      "abcdefghijklmnopqrstuvwxyz+/=")] == 0) {\r
986             /*\r
987              * Might be a base64-encoded SSH-2 public key blob. Check\r
988              * that it starts with a sensible algorithm string. No\r
989              * canonicalisation is necessary for this string type.\r
990              *\r
991              * The algorithm string must be at most 64 characters long\r
992              * (RFC 4251 section 6).\r
993              */\r
994             unsigned char decoded[6];\r
995             unsigned alglen;\r
996             int minlen;\r
997             int len = 0;\r
999             len += base64_decode_atom(q, decoded+len);\r
1000             if (len < 3)\r
1001                 goto not_ssh2_blob;    /* sorry */\r
1002             len += base64_decode_atom(q+4, decoded+len);\r
1003             if (len < 4)\r
1004                 goto not_ssh2_blob;    /* sorry */\r
1006             alglen = GET_32BIT_MSB_FIRST(decoded);\r
1007             if (alglen > 64)\r
1008                 goto not_ssh2_blob;    /* sorry */\r
1010             minlen = ((alglen + 4) + 2) / 3;\r
1011             if (strlen(q) < minlen)\r
1012                 goto not_ssh2_blob;    /* sorry */\r
1014             strcpy(key, q);\r
1015             return TRUE;\r
1016         }\r
1017       not_ssh2_blob:;\r
1018     }\r
1020     return FALSE;\r