PuttyIntf.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. //---------------------------------------------------------------------------
  2. #include <vcl.h>
  3. #pragma hdrstop
  4. #define PUTTY_DO_GLOBALS
  5. #include "PuttyIntf.h"
  6. #include "Interface.h"
  7. #include "SecureShell.h"
  8. #include "Exceptions.h"
  9. #include "CoreMain.h"
  10. #include "TextsCore.h"
  11. //---------------------------------------------------------------------------
  12. char sshver[50];
  13. CRITICAL_SECTION noise_section;
  14. bool SaveRandomSeed;
  15. //---------------------------------------------------------------------------
  16. int get_line(void * frontend, const char * prompt, char * str, int maxlen, int is_pw);
  17. //---------------------------------------------------------------------------
  18. void __fastcall PuttyInitialize()
  19. {
  20. SaveRandomSeed = true;
  21. InitializeCriticalSection(&noise_section);
  22. // make sure random generator is initialised, so random_save_seed()
  23. // in destructor can proceed
  24. random_ref();
  25. // initialize default seed path value same way as putty does (only change filename)
  26. putty_get_seedpath();
  27. flags = FLAG_VERBOSE | FLAG_SYNCAGENT; // verbose log
  28. ssh_get_line = get_line;
  29. ssh_getline_pw_only = FALSE;
  30. sk_init();
  31. AnsiString VersionString = SshVersionString();
  32. assert(!VersionString.IsEmpty() && (VersionString.Length() < sizeof(sshver)));
  33. strcpy(sshver, VersionString.c_str());
  34. }
  35. //---------------------------------------------------------------------------
  36. void __fastcall PuttyFinalize()
  37. {
  38. if (SaveRandomSeed)
  39. {
  40. random_save_seed();
  41. }
  42. random_unref();
  43. sk_cleanup();
  44. DeleteCriticalSection(&noise_section);
  45. }
  46. //---------------------------------------------------------------------------
  47. void __fastcall DontSaveRandomSeed()
  48. {
  49. SaveRandomSeed = false;
  50. }
  51. //---------------------------------------------------------------------------
  52. bool __fastcall IsListenerFree(unsigned int PortNumber)
  53. {
  54. Socket socket =
  55. sk_newlistener(NULL, PortNumber, NULL, true, ADDRTYPE_IPV4);
  56. bool Result = (sk_socket_error(socket) == NULL);
  57. sk_close(socket);
  58. return Result;
  59. }
  60. //---------------------------------------------------------------------------
  61. int __fastcall ProtocolByName(const AnsiString & Name)
  62. {
  63. int Protocol = 0; // raw
  64. for (int Index = 0; backends[Index].name != NULL; Index++)
  65. {
  66. if (!Name.AnsiCompareIC(backends[Index].name))
  67. {
  68. Protocol = (TProtocol)backends[Index].protocol;
  69. break;
  70. }
  71. }
  72. return Protocol;
  73. }
  74. //---------------------------------------------------------------------------
  75. AnsiString __fastcall ProtocolName(int Protocol)
  76. {
  77. for (int Index = 0; backends[Index].name != NULL; Index++)
  78. {
  79. if ((TProtocol)backends[Index].protocol == Protocol)
  80. {
  81. return backends[Index].name;
  82. }
  83. }
  84. return "raw";
  85. }
  86. //---------------------------------------------------------------------------
  87. extern "C" char * do_select(Plug plug, SOCKET skt, int startup)
  88. {
  89. // is NULL, when sk_newlistener is used to check for free port from
  90. // TTerminal::OpenTunnel()
  91. if (plug != NULL)
  92. {
  93. void * frontend;
  94. if (!is_ssh(plug) && !is_pfwd(plug))
  95. {
  96. // If it is not SSH/PFwd plug, them it must be Proxy plug.
  97. // Get SSH/PFwd plug which it wraps.
  98. Proxy_Socket ProxySocket = ((Proxy_Plug)plug)->proxy_socket;
  99. plug = ProxySocket->plug;
  100. }
  101. bool pfwd = is_pfwd(plug);
  102. if (pfwd)
  103. {
  104. plug = (Plug)get_pfwd_backend(plug);
  105. }
  106. frontend = get_ssh_frontend(plug);
  107. assert(frontend);
  108. TSecureShell * SecureShell = reinterpret_cast<TSecureShell*>(frontend);
  109. if (!pfwd)
  110. {
  111. SecureShell->UpdateSocket(skt, startup);
  112. }
  113. else
  114. {
  115. SecureShell->UpdatePortFwdSocket(skt, startup);
  116. }
  117. }
  118. return NULL;
  119. }
  120. //---------------------------------------------------------------------------
  121. int from_backend(void * frontend, int is_stderr, const char * data, int datalen, int type)
  122. {
  123. assert(frontend);
  124. if (type > 0)
  125. {
  126. ((TSecureShell *)frontend)->FromBackend((is_stderr == 1), data, datalen);
  127. }
  128. else
  129. {
  130. assert(is_stderr == 1);
  131. ((TSecureShell *)frontend)->CWrite(data, datalen, type < 0);
  132. }
  133. return 0;
  134. }
  135. //---------------------------------------------------------------------------
  136. static int get_line(void * frontend, const char * prompt, char * str,
  137. int maxlen, int is_pw)
  138. {
  139. assert(frontend != NULL);
  140. TSecureShell * SecureShell = reinterpret_cast<TSecureShell*>(frontend);
  141. AnsiString Response;
  142. bool Result = SecureShell->PromptUser(prompt, Response, is_pw);
  143. if (Result)
  144. {
  145. strcpy(str, Response.SubString(1, maxlen - 1).c_str());
  146. }
  147. return Result ? 1 : 0;
  148. }
  149. //---------------------------------------------------------------------------
  150. void logevent(void * frontend, const char * string)
  151. {
  152. // Frontend maybe NULL here
  153. if (frontend != NULL)
  154. {
  155. ((TSecureShell *)frontend)->PuttyLogEvent(string);
  156. }
  157. }
  158. //---------------------------------------------------------------------------
  159. void connection_fatal(void * frontend, char * fmt, ...)
  160. {
  161. va_list Param;
  162. char Buf[200];
  163. va_start(Param, fmt);
  164. vsnprintf(Buf, sizeof(Buf), fmt, Param); \
  165. Buf[sizeof(Buf) - 1] = '\0'; \
  166. va_end(Param);
  167. assert(frontend != NULL);
  168. ((TSecureShell *)frontend)->PuttyFatalError(Buf);
  169. }
  170. //---------------------------------------------------------------------------
  171. int verify_ssh_host_key(void * frontend, char * host, int port, char * keytype,
  172. char * keystr, char * fingerprint, void (*/*callback*/)(void * ctx, int result),
  173. void * /*ctx*/)
  174. {
  175. assert(frontend != NULL);
  176. ((TSecureShell *)frontend)->VerifyHostKey(host, port, keytype, keystr, fingerprint);
  177. // We should return 0 when key was not confirmed, we throw exception instead.
  178. return 1;
  179. }
  180. //---------------------------------------------------------------------------
  181. int askalg(void * frontend, const char * algtype, const char * algname,
  182. void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
  183. {
  184. assert(frontend != NULL);
  185. ((TSecureShell *)frontend)->AskAlg(algtype, algname);
  186. // We should return 0 when alg was not confirmed, we throw exception instead.
  187. return 1;
  188. }
  189. //---------------------------------------------------------------------------
  190. void old_keyfile_warning(void)
  191. {
  192. // no reference to TSecureShell instace available
  193. }
  194. //---------------------------------------------------------------------------
  195. void display_banner(void * frontend, const char * banner, int size)
  196. {
  197. assert(frontend);
  198. AnsiString Banner(banner, size);
  199. ((TSecureShell *)frontend)->DisplayBanner(Banner);
  200. }
  201. //---------------------------------------------------------------------------
  202. static void SSHFatalError(const char * Format, va_list Param)
  203. {
  204. char Buf[200];
  205. vsnprintf(Buf, sizeof(Buf), Format, Param);
  206. Buf[sizeof(Buf) - 1] = '\0';
  207. // Only few calls from putty\winnet.c might be connected with specific
  208. // TSecureShell. Otherwise called only for really fatal errors
  209. // like 'out of memory' from putty\ssh.c.
  210. throw ESshFatal(NULL, Buf);
  211. }
  212. //---------------------------------------------------------------------------
  213. void fatalbox(char * fmt, ...)
  214. {
  215. va_list Param;
  216. va_start(Param, fmt);
  217. SSHFatalError(fmt, Param);
  218. va_end(Param);
  219. }
  220. //---------------------------------------------------------------------------
  221. void modalfatalbox(char * fmt, ...)
  222. {
  223. va_list Param;
  224. va_start(Param, fmt);
  225. SSHFatalError(fmt, Param);
  226. va_end(Param);
  227. }
  228. //---------------------------------------------------------------------------
  229. void cleanup_exit(int /*code*/)
  230. {
  231. throw ESshFatal(NULL, "");
  232. }
  233. //---------------------------------------------------------------------------
  234. int askappend(void * /*frontend*/, Filename /*filename*/,
  235. void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
  236. {
  237. // this is called from logging.c of putty, which is never used with WinSCP
  238. assert(false);
  239. return 0;
  240. }
  241. //---------------------------------------------------------------------------
  242. void ldisc_send(void * /*handle*/, char * /*buf*/, int len, int /*interactive*/)
  243. {
  244. // This is only here because of the calls to ldisc_send(NULL,
  245. // 0) in ssh.c. Nothing in PSCP actually needs to use the ldisc
  246. // as an ldisc. So if we get called with any real data, I want
  247. // to know about it.
  248. assert(len == 0);
  249. USEDPARAM(len);
  250. }
  251. //---------------------------------------------------------------------------
  252. void agent_schedule_callback(void (* /*callback*/)(void *, void *, int),
  253. void * /*callback_ctx*/, void * /*data*/, int /*len*/)
  254. {
  255. assert(false);
  256. }
  257. //---------------------------------------------------------------------------
  258. void notify_remote_exit(void * /*frontend*/)
  259. {
  260. // nothing
  261. }
  262. //---------------------------------------------------------------------------
  263. void update_specials_menu(void * /*frontend*/)
  264. {
  265. // nothing
  266. }
  267. //---------------------------------------------------------------------------
  268. typedef void (*timer_fn_t)(void *ctx, long now);
  269. long schedule_timer(int ticks, timer_fn_t /*fn*/, void * /*ctx*/)
  270. {
  271. return ticks + GetTickCount();
  272. }
  273. //---------------------------------------------------------------------------
  274. void expire_timer_context(void * /*ctx*/)
  275. {
  276. // nothing
  277. }
  278. //---------------------------------------------------------------------------
  279. Pinger pinger_new(Config * /*cfg*/, Backend * /*back*/, void * /*backhandle*/)
  280. {
  281. return NULL;
  282. }
  283. //---------------------------------------------------------------------------
  284. void pinger_reconfig(Pinger /*pinger*/, Config * /*oldcfg*/, Config * /*newcfg*/)
  285. {
  286. // nothing
  287. }
  288. //---------------------------------------------------------------------------
  289. void pinger_free(Pinger /*pinger*/)
  290. {
  291. // nothing
  292. }
  293. //---------------------------------------------------------------------------
  294. void set_busy_status(void * /*frontend*/, int /*status*/)
  295. {
  296. // nothing
  297. }
  298. //---------------------------------------------------------------------------
  299. static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool CanCreate)
  300. {
  301. // This is called once during initialization
  302. // from get_seedpath() (winstore.c).
  303. // In that case we want it to really look into Putty regkey.
  304. long R;
  305. assert(Configuration != NULL);
  306. if (Configuration->Initialized)
  307. {
  308. assert(Key == HKEY_CURRENT_USER);
  309. AnsiString RegKey = SubKey;
  310. int PuttyKeyLen = Configuration->PuttyRegistryStorageKey.Length();
  311. assert(RegKey.SubString(1, PuttyKeyLen) == Configuration->PuttyRegistryStorageKey);
  312. RegKey = RegKey.SubString(PuttyKeyLen + 1, RegKey.Length() - PuttyKeyLen);
  313. if (!RegKey.IsEmpty())
  314. {
  315. assert(RegKey[1] == '\\');
  316. RegKey.Delete(1, 1);
  317. }
  318. // we expect this to be called only from verify_host_key() or store_host_key()
  319. assert(RegKey == "SshHostKeys");
  320. THierarchicalStorage * Storage = Configuration->CreateScpStorage(false);
  321. Storage->AccessMode = (CanCreate ? smReadWrite : smRead);
  322. if (Storage->OpenSubKey(RegKey, CanCreate))
  323. {
  324. *Result = static_cast<HKEY>(Storage);
  325. R = ERROR_SUCCESS;
  326. }
  327. else
  328. {
  329. delete Storage;
  330. R = ERROR_CANTOPEN;
  331. }
  332. }
  333. else
  334. {
  335. assert(Configuration->PuttyRegistryStorageKey == SubKey);
  336. if (CanCreate)
  337. {
  338. R = RegCreateKey(Key, SubKey, Result);
  339. }
  340. else
  341. {
  342. R = RegOpenKey(Key, SubKey, Result);
  343. }
  344. }
  345. return R;
  346. }
  347. //---------------------------------------------------------------------------
  348. long reg_open_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
  349. {
  350. return OpenWinSCPKey(Key, SubKey, Result, false);
  351. }
  352. //---------------------------------------------------------------------------
  353. long reg_create_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
  354. {
  355. return OpenWinSCPKey(Key, SubKey, Result, true);
  356. }
  357. //---------------------------------------------------------------------------
  358. long reg_query_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long * Reserved,
  359. unsigned long * Type, unsigned char * Data, unsigned long * DataSize)
  360. {
  361. long R;
  362. assert(Configuration != NULL);
  363. if (Configuration->Initialized)
  364. {
  365. THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
  366. if (Storage->ValueExists(ValueName))
  367. {
  368. AnsiString Value;
  369. Value = Storage->ReadStringRaw(ValueName, "");
  370. assert(Type != NULL);
  371. *Type = REG_SZ;
  372. char * DataStr = reinterpret_cast<char *>(Data);
  373. strncpy(DataStr, Value.c_str(), *DataSize);
  374. DataStr[*DataSize - 1] = '\0';
  375. *DataSize = strlen(DataStr);
  376. R = ERROR_SUCCESS;
  377. }
  378. else
  379. {
  380. R = ERROR_READ_FAULT;
  381. }
  382. }
  383. else
  384. {
  385. R = RegQueryValueEx(Key, ValueName, Reserved, Type, Data, DataSize);
  386. }
  387. return R;
  388. }
  389. //---------------------------------------------------------------------------
  390. long reg_set_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long Reserved,
  391. unsigned long Type, const unsigned char * Data, unsigned long DataSize)
  392. {
  393. long R;
  394. assert(Configuration != NULL);
  395. if (Configuration->Initialized)
  396. {
  397. assert(Type == REG_SZ);
  398. THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
  399. AnsiString Value(reinterpret_cast<const char*>(Data), DataSize - 1);
  400. Storage->WriteStringRaw(ValueName, Value);
  401. R = ERROR_SUCCESS;
  402. }
  403. else
  404. {
  405. R = RegSetValueEx(Key, ValueName, Reserved, Type, Data, DataSize);
  406. }
  407. return R;
  408. }
  409. //---------------------------------------------------------------------------
  410. long reg_close_winscp_key(HKEY Key)
  411. {
  412. long R;
  413. assert(Configuration != NULL);
  414. if (Configuration->Initialized)
  415. {
  416. THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
  417. delete Storage;
  418. R = ERROR_SUCCESS;
  419. }
  420. else
  421. {
  422. R = RegCloseKey(Key);
  423. }
  424. return R;
  425. }
  426. //---------------------------------------------------------------------------
  427. TKeyType KeyType(AnsiString FileName)
  428. {
  429. assert(ktUnopenable == SSH_KEYTYPE_UNOPENABLE);
  430. assert(ktSSHCom == SSH_KEYTYPE_SSHCOM);
  431. Filename KeyFile;
  432. ASCOPY(KeyFile.path, FileName);
  433. return (TKeyType)key_type(&KeyFile);
  434. }
  435. //---------------------------------------------------------------------------
  436. AnsiString KeyTypeName(TKeyType KeyType)
  437. {
  438. return key_type_to_str(KeyType);
  439. }
  440. //---------------------------------------------------------------------------
  441. //---------------------------------------------------------------------------
  442. struct TUnicodeEmitParams
  443. {
  444. WideString Buffer;
  445. int Pos;
  446. int Len;
  447. };
  448. //---------------------------------------------------------------------------
  449. extern "C" void UnicodeEmit(void * AParams, long int Output)
  450. {
  451. if (Output == 0xFFFFL) // see Putty's charset\internal.h
  452. {
  453. throw Exception(LoadStr(DECODE_UTF_ERROR));
  454. }
  455. TUnicodeEmitParams * Params = (TUnicodeEmitParams *)AParams;
  456. if (Params->Pos >= Params->Len)
  457. {
  458. Params->Len += 50;
  459. Params->Buffer.SetLength(Params->Len);
  460. }
  461. Params->Pos++;
  462. Params->Buffer[Params->Pos] = (wchar_t)Output;
  463. }
  464. //---------------------------------------------------------------------------
  465. AnsiString __fastcall DecodeUTF(const AnsiString UTF)
  466. {
  467. charset_state State;
  468. char * Str;
  469. TUnicodeEmitParams Params;
  470. AnsiString Result;
  471. State.s0 = 0;
  472. Str = UTF.c_str();
  473. Params.Pos = 0;
  474. Params.Len = UTF.Length();
  475. Params.Buffer.SetLength(Params.Len);
  476. while (*Str)
  477. {
  478. read_utf8(NULL, (unsigned char)*Str, &State, UnicodeEmit, &Params);
  479. Str++;
  480. }
  481. Params.Buffer.SetLength(Params.Pos);
  482. return Params.Buffer;
  483. }
  484. //---------------------------------------------------------------------------
  485. struct TUnicodeEmitParams2
  486. {
  487. AnsiString Buffer;
  488. int Pos;
  489. int Len;
  490. };
  491. //---------------------------------------------------------------------------
  492. extern "C" void UnicodeEmit2(void * AParams, long int Output)
  493. {
  494. if (Output == 0xFFFFL) // see Putty's charset\internal.h
  495. {
  496. throw Exception(LoadStr(DECODE_UTF_ERROR));
  497. }
  498. TUnicodeEmitParams2 * Params = (TUnicodeEmitParams2 *)AParams;
  499. if (Params->Pos >= Params->Len)
  500. {
  501. Params->Len += 50;
  502. Params->Buffer.SetLength(Params->Len);
  503. }
  504. Params->Pos++;
  505. Params->Buffer[Params->Pos] = (unsigned char)Output;
  506. }
  507. //---------------------------------------------------------------------------
  508. AnsiString __fastcall EncodeUTF(const WideString Source)
  509. {
  510. // WideString::c_bstr() returns NULL for empty strings
  511. // (as opposite to AnsiString::c_str() which returns "")
  512. if (Source.IsEmpty())
  513. {
  514. return "";
  515. }
  516. else
  517. {
  518. charset_state State;
  519. wchar_t * Str;
  520. TUnicodeEmitParams2 Params;
  521. AnsiString Result;
  522. State.s0 = 0;
  523. Str = Source.c_bstr();
  524. Params.Pos = 0;
  525. Params.Len = Source.Length();
  526. Params.Buffer.SetLength(Params.Len);
  527. while (*Str)
  528. {
  529. write_utf8(NULL, (wchar_t)*Str, &State, UnicodeEmit2, &Params);
  530. Str++;
  531. }
  532. Params.Buffer.SetLength(Params.Pos);
  533. return Params.Buffer;
  534. }
  535. }
  536. //---------------------------------------------------------------------------
  537. __int64 __fastcall ParseSize(AnsiString SizeStr)
  538. {
  539. return parse_blocksize(SizeStr.c_str());
  540. }
  541. //---------------------------------------------------------------------------