misc.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. /*
  2. * Platform-independent routines shared between all PuTTY programs.
  3. *
  4. * This file contains functions that use the kind of infrastructure
  5. * like conf.c that tends to only live in the main applications, or
  6. * that do things that only something like a main PuTTY application
  7. * would need. So standalone test programs should generally be able to
  8. * avoid linking against it.
  9. *
  10. * More standalone functions that depend on nothing but the C library
  11. * live in utils.c.
  12. */
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <stdarg.h>
  16. #include <limits.h>
  17. #include <ctype.h>
  18. #include <assert.h>
  19. #include "defs.h"
  20. #include "putty.h"
  21. #include "misc.h"
  22. #define BASE64_CHARS_NOEQ \
  23. "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"
  24. #define BASE64_CHARS_ALL BASE64_CHARS_NOEQ "="
  25. void seat_connection_fatal(Seat *seat, const char *fmt, ...)
  26. {
  27. va_list ap;
  28. char *msg;
  29. va_start(ap, fmt);
  30. msg = dupvprintf(fmt, ap);
  31. va_end(ap);
  32. seat->vt->connection_fatal(seat, msg);
  33. sfree(msg); /* if we return */
  34. }
  35. prompts_t *new_prompts(void)
  36. {
  37. prompts_t *p = snew(prompts_t);
  38. p->prompts = NULL;
  39. p->n_prompts = p->prompts_size = 0;
  40. p->data = NULL;
  41. p->to_server = true; /* to be on the safe side */
  42. p->name = p->instruction = NULL;
  43. p->name_reqd = p->instr_reqd = false;
  44. return p;
  45. }
  46. void add_prompt(prompts_t *p, char *promptstr, bool echo)
  47. {
  48. prompt_t *pr = snew(prompt_t);
  49. pr->prompt = promptstr;
  50. pr->echo = echo;
  51. pr->result = strbuf_new_nm();
  52. sgrowarray(p->prompts, p->prompts_size, p->n_prompts);
  53. p->prompts[p->n_prompts++] = pr;
  54. }
  55. void prompt_set_result(prompt_t *pr, const char *newstr)
  56. {
  57. strbuf_clear(pr->result);
  58. put_datapl(pr->result, ptrlen_from_asciz(newstr));
  59. }
  60. const char *prompt_get_result_ref(prompt_t *pr)
  61. {
  62. return pr->result->s;
  63. }
  64. char *prompt_get_result(prompt_t *pr)
  65. {
  66. return dupstr(pr->result->s);
  67. }
  68. void free_prompts(prompts_t *p)
  69. {
  70. size_t i;
  71. for (i=0; i < p->n_prompts; i++) {
  72. prompt_t *pr = p->prompts[i];
  73. strbuf_free(pr->result);
  74. sfree(pr->prompt);
  75. sfree(pr);
  76. }
  77. sfree(p->prompts);
  78. sfree(p->name);
  79. sfree(p->instruction);
  80. sfree(p);
  81. }
  82. /*
  83. * Determine whether or not a Conf represents a session which can
  84. * sensibly be launched right now.
  85. */
  86. bool conf_launchable(Conf *conf)
  87. {
  88. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
  89. return conf_get_str(conf, CONF_serline)[0] != 0;
  90. else
  91. return conf_get_str(conf, CONF_host)[0] != 0;
  92. }
  93. char const *conf_dest(Conf *conf)
  94. {
  95. if (conf_get_int(conf, CONF_protocol) == PROT_SERIAL)
  96. return conf_get_str(conf, CONF_serline);
  97. else
  98. return conf_get_str(conf, CONF_host);
  99. }
  100. /*
  101. * Validate a manual host key specification (either entered in the
  102. * GUI, or via -hostkey). If valid, we return true, and update 'key'
  103. * to contain a canonicalised version of the key string in 'key'
  104. * (which is guaranteed to take up at most as much space as the
  105. * original version), suitable for putting into the Conf. If not
  106. * valid, we return false.
  107. */
  108. bool validate_manual_hostkey(char *key)
  109. {
  110. char *p, *q, *r, *s;
  111. /*
  112. * Step through the string word by word, looking for a word that's
  113. * in one of the formats we like.
  114. */
  115. p = key;
  116. while ((p += strspn(p, " \t"))[0]) {
  117. q = p;
  118. p += strcspn(p, " \t");
  119. if (*p) *p++ = '\0';
  120. /*
  121. * Now q is our word.
  122. */
  123. if (strstartswith(q, "SHA256:")) {
  124. /* Test for a valid SHA256 key fingerprint. */
  125. r = q + 7;
  126. if (strlen(r) == 43 && r[strspn(r, BASE64_CHARS_NOEQ)] == 0)
  127. return true;
  128. }
  129. r = q;
  130. if (strstartswith(r, "MD5:"))
  131. r += 4;
  132. if (strlen(r) == 16*3 - 1 &&
  133. r[strspn(r, "0123456789abcdefABCDEF:")] == 0) {
  134. /*
  135. * Test for a valid MD5 key fingerprint. Check the colons
  136. * are in the right places, and if so, return the same
  137. * fingerprint canonicalised into lowercase.
  138. */
  139. int i;
  140. for (i = 0; i < 16; i++)
  141. if (r[3*i] == ':' || r[3*i+1] == ':')
  142. goto not_fingerprint; /* sorry */
  143. for (i = 0; i < 15; i++)
  144. if (r[3*i+2] != ':')
  145. goto not_fingerprint; /* sorry */
  146. for (i = 0; i < 16*3 - 1; i++)
  147. key[i] = tolower(r[i]);
  148. key[16*3 - 1] = '\0';
  149. return true;
  150. }
  151. not_fingerprint:;
  152. /*
  153. * Before we check for a public-key blob, trim newlines out of
  154. * the middle of the word, in case someone's managed to paste
  155. * in a public-key blob _with_ them.
  156. */
  157. for (r = s = q; *r; r++)
  158. if (*r != '\n' && *r != '\r')
  159. *s++ = *r;
  160. *s = '\0';
  161. if (strlen(q) % 4 == 0 && strlen(q) > 2*4 &&
  162. q[strspn(q, BASE64_CHARS_ALL)] == 0) {
  163. /*
  164. * Might be a base64-encoded SSH-2 public key blob. Check
  165. * that it starts with a sensible algorithm string. No
  166. * canonicalisation is necessary for this string type.
  167. *
  168. * The algorithm string must be at most 64 characters long
  169. * (RFC 4251 section 6).
  170. */
  171. unsigned char decoded[6];
  172. unsigned alglen;
  173. int minlen;
  174. int len = 0;
  175. len += base64_decode_atom(q, decoded+len);
  176. if (len < 3)
  177. goto not_ssh2_blob; /* sorry */
  178. len += base64_decode_atom(q+4, decoded+len);
  179. if (len < 4)
  180. goto not_ssh2_blob; /* sorry */
  181. alglen = GET_32BIT_MSB_FIRST(decoded);
  182. if (alglen > 64)
  183. goto not_ssh2_blob; /* sorry */
  184. minlen = ((alglen + 4) + 2) / 3;
  185. if (strlen(q) < minlen)
  186. goto not_ssh2_blob; /* sorry */
  187. strcpy(key, q);
  188. return true;
  189. }
  190. not_ssh2_blob:;
  191. }
  192. return false;
  193. }
  194. char *buildinfo(const char *newline)
  195. {
  196. strbuf *buf = strbuf_new();
  197. strbuf_catf(buf, "Build platform: %d-bit %s",
  198. (int)(CHAR_BIT * sizeof(void *)),
  199. BUILDINFO_PLATFORM);
  200. #ifdef __clang_version__
  201. #define FOUND_COMPILER
  202. strbuf_catf(buf, "%sCompiler: clang %s", newline, __clang_version__);
  203. #elif defined __GNUC__ && defined __VERSION__
  204. #define FOUND_COMPILER
  205. strbuf_catf(buf, "%sCompiler: gcc %s", newline, __VERSION__);
  206. #endif
  207. #if defined _MSC_VER
  208. #ifndef FOUND_COMPILER
  209. #define FOUND_COMPILER
  210. strbuf_catf(buf, "%sCompiler: ", newline);
  211. #else
  212. strbuf_catf(buf, ", emulating ");
  213. #endif
  214. strbuf_catf(buf, "Visual Studio");
  215. #if 0
  216. /*
  217. * List of _MSC_VER values and their translations taken from
  218. * https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros
  219. *
  220. * The pointless #if 0 branch containing this comment is there so
  221. * that every real clause can start with #elif and there's no
  222. * anomalous first clause. That way the patch looks nicer when you
  223. * add extra ones.
  224. */
  225. #elif _MSC_VER == 1928 && _MSC_FULL_VER >= 192829500
  226. /*
  227. * 16.9 and 16.8 have the same _MSC_VER value, and have to be
  228. * distinguished by _MSC_FULL_VER. As of 2021-03-04 that is not
  229. * mentioned on the above page, but see e.g.
  230. * https://developercommunity.visualstudio.com/t/the-169-cc-compiler-still-uses-the-same-version-nu/1335194#T-N1337120
  231. * which says that 16.9 builds will have versions starting at
  232. * 19.28.29500.* and going up. Hence, 19 28 29500 is what we
  233. * compare _MSC_FULL_VER against above.
  234. */
  235. strbuf_catf(buf, " 2019 (16.9)");
  236. #elif _MSC_VER == 1928
  237. strbuf_catf(buf, " 2019 (16.8)");
  238. #elif _MSC_VER == 1927
  239. strbuf_catf(buf, " 2019 (16.7)");
  240. #elif _MSC_VER == 1926
  241. strbuf_catf(buf, " 2019 (16.6)");
  242. #elif _MSC_VER == 1925
  243. strbuf_catf(buf, " 2019 (16.5)");
  244. #elif _MSC_VER == 1924
  245. strbuf_catf(buf, " 2019 (16.4)");
  246. #elif _MSC_VER == 1923
  247. strbuf_catf(buf, " 2019 (16.3)");
  248. #elif _MSC_VER == 1922
  249. strbuf_catf(buf, " 2019 (16.2)");
  250. #elif _MSC_VER == 1921
  251. strbuf_catf(buf, " 2019 (16.1)");
  252. #elif _MSC_VER == 1920
  253. strbuf_catf(buf, " 2019 (16.0)");
  254. #elif _MSC_VER == 1916
  255. strbuf_catf(buf, " 2017 version 15.9");
  256. #elif _MSC_VER == 1915
  257. strbuf_catf(buf, " 2017 version 15.8");
  258. #elif _MSC_VER == 1914
  259. strbuf_catf(buf, " 2017 version 15.7");
  260. #elif _MSC_VER == 1913
  261. strbuf_catf(buf, " 2017 version 15.6");
  262. #elif _MSC_VER == 1912
  263. strbuf_catf(buf, " 2017 version 15.5");
  264. #elif _MSC_VER == 1911
  265. strbuf_catf(buf, " 2017 version 15.3");
  266. #elif _MSC_VER == 1910
  267. strbuf_catf(buf, " 2017 RTW (15.0)");
  268. #elif _MSC_VER == 1900
  269. strbuf_catf(buf, " 2015 (14.0)");
  270. #elif _MSC_VER == 1800
  271. strbuf_catf(buf, " 2013 (12.0)");
  272. #elif _MSC_VER == 1700
  273. strbuf_catf(buf, " 2012 (11.0)");
  274. #elif _MSC_VER == 1600
  275. strbuf_catf(buf, " 2010 (10.0)");
  276. #elif _MSC_VER == 1500
  277. strbuf_catf(buf, " 2008 (9.0)");
  278. #elif _MSC_VER == 1400
  279. strbuf_catf(buf, " 2005 (8.0)");
  280. #elif _MSC_VER == 1310
  281. strbuf_catf(buf, " .NET 2003 (7.1)");
  282. #elif _MSC_VER == 1300
  283. strbuf_catf(buf, " .NET 2002 (7.0)");
  284. #elif _MSC_VER == 1200
  285. strbuf_catf(buf, " 6.0");
  286. #else
  287. strbuf_catf(buf, ", unrecognised version");
  288. #endif
  289. strbuf_catf(buf, ", _MSC_VER=%d", (int)_MSC_VER);
  290. #endif
  291. #ifdef BUILDINFO_GTK
  292. {
  293. char *gtk_buildinfo = buildinfo_gtk_version();
  294. if (gtk_buildinfo) {
  295. strbuf_catf(buf, "%sCompiled against GTK version %s",
  296. newline, gtk_buildinfo);
  297. sfree(gtk_buildinfo);
  298. }
  299. }
  300. #endif
  301. #if defined _WINDOWS
  302. {
  303. int echm = has_embedded_chm();
  304. if (echm >= 0)
  305. strbuf_catf(buf, "%sEmbedded HTML Help file: %s", newline,
  306. echm ? "yes" : "no");
  307. }
  308. #endif
  309. #if defined _WINDOWS && defined MINEFIELD
  310. strbuf_catf(buf, "%sBuild option: MINEFIELD", newline);
  311. #endif
  312. #ifdef NO_SECURITY
  313. strbuf_catf(buf, "%sBuild option: NO_SECURITY", newline);
  314. #endif
  315. #ifdef NO_SECUREZEROMEMORY
  316. strbuf_catf(buf, "%sBuild option: NO_SECUREZEROMEMORY", newline);
  317. #endif
  318. #ifdef NO_IPV6
  319. strbuf_catf(buf, "%sBuild option: NO_IPV6", newline);
  320. #endif
  321. #ifdef NO_GSSAPI
  322. strbuf_catf(buf, "%sBuild option: NO_GSSAPI", newline);
  323. #endif
  324. #ifdef STATIC_GSSAPI
  325. strbuf_catf(buf, "%sBuild option: STATIC_GSSAPI", newline);
  326. #endif
  327. #ifdef UNPROTECT
  328. strbuf_catf(buf, "%sBuild option: UNPROTECT", newline);
  329. #endif
  330. #ifdef FUZZING
  331. strbuf_catf(buf, "%sBuild option: FUZZING", newline);
  332. #endif
  333. #ifdef DEBUG
  334. strbuf_catf(buf, "%sBuild option: DEBUG", newline);
  335. #endif
  336. strbuf_catf(buf, "%sSource commit: %s", newline, commitid);
  337. return strbuf_to_str(buf);
  338. }
  339. size_t nullseat_output(
  340. Seat *seat, bool is_stderr, const void *data, size_t len) { return 0; }
  341. bool nullseat_eof(Seat *seat) { return true; }
  342. int nullseat_get_userpass_input(
  343. Seat *seat, prompts_t *p, bufchain *input) { return 0; }
  344. void nullseat_notify_remote_exit(Seat *seat) {}
  345. void nullseat_connection_fatal(Seat *seat, const char *message) {}
  346. void nullseat_update_specials_menu(Seat *seat) {}
  347. char *nullseat_get_ttymode(Seat *seat, const char *mode) { return NULL; }
  348. void nullseat_set_busy_status(Seat *seat, BusyStatus status) {}
  349. int nullseat_verify_ssh_host_key(
  350. Seat *seat, const char *host, int port, const char *keytype,
  351. char *keystr, const char *keydisp, char **key_fingerprints,
  352. void (*callback)(void *ctx, int result), void *ctx) { return 0; }
  353. int nullseat_confirm_weak_crypto_primitive(
  354. Seat *seat, const char *algtype, const char *algname,
  355. void (*callback)(void *ctx, int result), void *ctx) { return 0; }
  356. int nullseat_confirm_weak_cached_hostkey(
  357. Seat *seat, const char *algname, const char *betteralgs,
  358. void (*callback)(void *ctx, int result), void *ctx) { return 0; }
  359. bool nullseat_is_never_utf8(Seat *seat) { return false; }
  360. bool nullseat_is_always_utf8(Seat *seat) { return true; }
  361. void nullseat_echoedit_update(Seat *seat, bool echoing, bool editing) {}
  362. const char *nullseat_get_x_display(Seat *seat) { return NULL; }
  363. bool nullseat_get_windowid(Seat *seat, long *id_out) { return false; }
  364. bool nullseat_get_window_pixel_size(
  365. Seat *seat, int *width, int *height) { return false; }
  366. StripCtrlChars *nullseat_stripctrl_new(
  367. Seat *seat, BinarySink *bs_out, SeatInteractionContext sic) {return NULL;}
  368. bool nullseat_set_trust_status(Seat *seat, bool tr) { return false; }
  369. bool nullseat_set_trust_status_vacuously(Seat *seat, bool tr) { return true; }
  370. bool nullseat_verbose_no(Seat *seat) { return false; }
  371. bool nullseat_verbose_yes(Seat *seat) { return true; }
  372. bool nullseat_interactive_no(Seat *seat) { return false; }
  373. bool nullseat_interactive_yes(Seat *seat) { return true; }
  374. bool nullseat_get_cursor_position(Seat *seat, int *x, int *y) { return false; }
  375. bool null_lp_verbose_no(LogPolicy *lp) { return false; }
  376. bool null_lp_verbose_yes(LogPolicy *lp) { return true; }
  377. void sk_free_peer_info(SocketPeerInfo *pi)
  378. {
  379. if (pi) {
  380. sfree((char *)pi->addr_text);
  381. sfree((char *)pi->log_text);
  382. sfree(pi);
  383. }
  384. }
  385. void out_of_memory(void)
  386. {
  387. modalfatalbox("Out of memory");
  388. }