PuttyIntf.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  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. // (one of the examples is indirect call from ssh_gssapi_init from HasGSSAPI)
  154. if (frontend != NULL)
  155. {
  156. ((TSecureShell *)frontend)->PuttyLogEvent(string);
  157. }
  158. }
  159. //---------------------------------------------------------------------------
  160. void connection_fatal(void * frontend, char * fmt, ...)
  161. {
  162. va_list Param;
  163. char Buf[200];
  164. va_start(Param, fmt);
  165. vsnprintf(Buf, sizeof(Buf), fmt, Param); \
  166. Buf[sizeof(Buf) - 1] = '\0'; \
  167. va_end(Param);
  168. assert(frontend != NULL);
  169. ((TSecureShell *)frontend)->PuttyFatalError(Buf);
  170. }
  171. //---------------------------------------------------------------------------
  172. int verify_ssh_host_key(void * frontend, char * host, int port, char * keytype,
  173. char * keystr, char * fingerprint, void (*/*callback*/)(void * ctx, int result),
  174. void * /*ctx*/)
  175. {
  176. assert(frontend != NULL);
  177. ((TSecureShell *)frontend)->VerifyHostKey(host, port, keytype, keystr, fingerprint);
  178. // We should return 0 when key was not confirmed, we throw exception instead.
  179. return 1;
  180. }
  181. //---------------------------------------------------------------------------
  182. int askalg(void * frontend, const char * algtype, const char * algname,
  183. void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
  184. {
  185. assert(frontend != NULL);
  186. ((TSecureShell *)frontend)->AskAlg(algtype, algname);
  187. // We should return 0 when alg was not confirmed, we throw exception instead.
  188. return 1;
  189. }
  190. //---------------------------------------------------------------------------
  191. void old_keyfile_warning(void)
  192. {
  193. // no reference to TSecureShell instace available
  194. }
  195. //---------------------------------------------------------------------------
  196. void display_banner(void * frontend, const char * banner, int size)
  197. {
  198. assert(frontend);
  199. AnsiString Banner(banner, size);
  200. ((TSecureShell *)frontend)->DisplayBanner(Banner);
  201. }
  202. //---------------------------------------------------------------------------
  203. static void SSHFatalError(const char * Format, va_list Param)
  204. {
  205. char Buf[200];
  206. vsnprintf(Buf, sizeof(Buf), Format, Param);
  207. Buf[sizeof(Buf) - 1] = '\0';
  208. // Only few calls from putty\winnet.c might be connected with specific
  209. // TSecureShell. Otherwise called only for really fatal errors
  210. // like 'out of memory' from putty\ssh.c.
  211. throw ESshFatal(NULL, Buf);
  212. }
  213. //---------------------------------------------------------------------------
  214. void fatalbox(char * fmt, ...)
  215. {
  216. va_list Param;
  217. va_start(Param, fmt);
  218. SSHFatalError(fmt, Param);
  219. va_end(Param);
  220. }
  221. //---------------------------------------------------------------------------
  222. void modalfatalbox(char * fmt, ...)
  223. {
  224. va_list Param;
  225. va_start(Param, fmt);
  226. SSHFatalError(fmt, Param);
  227. va_end(Param);
  228. }
  229. //---------------------------------------------------------------------------
  230. void cleanup_exit(int /*code*/)
  231. {
  232. throw ESshFatal(NULL, "");
  233. }
  234. //---------------------------------------------------------------------------
  235. int askappend(void * /*frontend*/, Filename /*filename*/,
  236. void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
  237. {
  238. // this is called from logging.c of putty, which is never used with WinSCP
  239. assert(false);
  240. return 0;
  241. }
  242. //---------------------------------------------------------------------------
  243. void ldisc_send(void * /*handle*/, char * /*buf*/, int len, int /*interactive*/)
  244. {
  245. // This is only here because of the calls to ldisc_send(NULL,
  246. // 0) in ssh.c. Nothing in PSCP actually needs to use the ldisc
  247. // as an ldisc. So if we get called with any real data, I want
  248. // to know about it.
  249. assert(len == 0);
  250. USEDPARAM(len);
  251. }
  252. //---------------------------------------------------------------------------
  253. void agent_schedule_callback(void (* /*callback*/)(void *, void *, int),
  254. void * /*callback_ctx*/, void * /*data*/, int /*len*/)
  255. {
  256. assert(false);
  257. }
  258. //---------------------------------------------------------------------------
  259. void notify_remote_exit(void * /*frontend*/)
  260. {
  261. // nothing
  262. }
  263. //---------------------------------------------------------------------------
  264. void update_specials_menu(void * /*frontend*/)
  265. {
  266. // nothing
  267. }
  268. //---------------------------------------------------------------------------
  269. typedef void (*timer_fn_t)(void *ctx, long now);
  270. long schedule_timer(int ticks, timer_fn_t /*fn*/, void * /*ctx*/)
  271. {
  272. return ticks + GetTickCount();
  273. }
  274. //---------------------------------------------------------------------------
  275. void expire_timer_context(void * /*ctx*/)
  276. {
  277. // nothing
  278. }
  279. //---------------------------------------------------------------------------
  280. Pinger pinger_new(Config * /*cfg*/, Backend * /*back*/, void * /*backhandle*/)
  281. {
  282. return NULL;
  283. }
  284. //---------------------------------------------------------------------------
  285. void pinger_reconfig(Pinger /*pinger*/, Config * /*oldcfg*/, Config * /*newcfg*/)
  286. {
  287. // nothing
  288. }
  289. //---------------------------------------------------------------------------
  290. void pinger_free(Pinger /*pinger*/)
  291. {
  292. // nothing
  293. }
  294. //---------------------------------------------------------------------------
  295. void set_busy_status(void * /*frontend*/, int /*status*/)
  296. {
  297. // nothing
  298. }
  299. //---------------------------------------------------------------------------
  300. static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool CanCreate)
  301. {
  302. // This is called once during initialization
  303. // from get_seedpath() (winstore.c).
  304. // In that case we want it to really look into Putty regkey.
  305. long R;
  306. assert(Configuration != NULL);
  307. if (Configuration->Initialized)
  308. {
  309. assert(Key == HKEY_CURRENT_USER);
  310. AnsiString RegKey = SubKey;
  311. int PuttyKeyLen = Configuration->PuttyRegistryStorageKey.Length();
  312. assert(RegKey.SubString(1, PuttyKeyLen) == Configuration->PuttyRegistryStorageKey);
  313. RegKey = RegKey.SubString(PuttyKeyLen + 1, RegKey.Length() - PuttyKeyLen);
  314. if (!RegKey.IsEmpty())
  315. {
  316. assert(RegKey[1] == '\\');
  317. RegKey.Delete(1, 1);
  318. }
  319. // we expect this to be called only from verify_host_key() or store_host_key()
  320. assert(RegKey == "SshHostKeys");
  321. THierarchicalStorage * Storage = Configuration->CreateScpStorage(false);
  322. Storage->AccessMode = (CanCreate ? smReadWrite : smRead);
  323. if (Storage->OpenSubKey(RegKey, CanCreate))
  324. {
  325. *Result = static_cast<HKEY>(Storage);
  326. R = ERROR_SUCCESS;
  327. }
  328. else
  329. {
  330. delete Storage;
  331. R = ERROR_CANTOPEN;
  332. }
  333. }
  334. else
  335. {
  336. assert(Configuration->PuttyRegistryStorageKey == SubKey);
  337. if (CanCreate)
  338. {
  339. R = RegCreateKey(Key, SubKey, Result);
  340. }
  341. else
  342. {
  343. R = RegOpenKey(Key, SubKey, Result);
  344. }
  345. }
  346. return R;
  347. }
  348. //---------------------------------------------------------------------------
  349. long reg_open_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
  350. {
  351. return OpenWinSCPKey(Key, SubKey, Result, false);
  352. }
  353. //---------------------------------------------------------------------------
  354. long reg_create_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
  355. {
  356. return OpenWinSCPKey(Key, SubKey, Result, true);
  357. }
  358. //---------------------------------------------------------------------------
  359. long reg_query_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long * Reserved,
  360. unsigned long * Type, unsigned char * Data, unsigned long * DataSize)
  361. {
  362. long R;
  363. assert(Configuration != NULL);
  364. if (Configuration->Initialized)
  365. {
  366. THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
  367. if (Storage->ValueExists(ValueName))
  368. {
  369. AnsiString Value;
  370. Value = Storage->ReadStringRaw(ValueName, "");
  371. assert(Type != NULL);
  372. *Type = REG_SZ;
  373. char * DataStr = reinterpret_cast<char *>(Data);
  374. strncpy(DataStr, Value.c_str(), *DataSize);
  375. DataStr[*DataSize - 1] = '\0';
  376. *DataSize = strlen(DataStr);
  377. R = ERROR_SUCCESS;
  378. }
  379. else
  380. {
  381. R = ERROR_READ_FAULT;
  382. }
  383. }
  384. else
  385. {
  386. R = RegQueryValueEx(Key, ValueName, Reserved, Type, Data, DataSize);
  387. }
  388. return R;
  389. }
  390. //---------------------------------------------------------------------------
  391. long reg_set_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long Reserved,
  392. unsigned long Type, const unsigned char * Data, unsigned long DataSize)
  393. {
  394. long R;
  395. assert(Configuration != NULL);
  396. if (Configuration->Initialized)
  397. {
  398. assert(Type == REG_SZ);
  399. THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
  400. AnsiString Value(reinterpret_cast<const char*>(Data), DataSize - 1);
  401. Storage->WriteStringRaw(ValueName, Value);
  402. R = ERROR_SUCCESS;
  403. }
  404. else
  405. {
  406. R = RegSetValueEx(Key, ValueName, Reserved, Type, Data, DataSize);
  407. }
  408. return R;
  409. }
  410. //---------------------------------------------------------------------------
  411. long reg_close_winscp_key(HKEY Key)
  412. {
  413. long R;
  414. assert(Configuration != NULL);
  415. if (Configuration->Initialized)
  416. {
  417. THierarchicalStorage * Storage = static_cast<THierarchicalStorage *>(Key);
  418. delete Storage;
  419. R = ERROR_SUCCESS;
  420. }
  421. else
  422. {
  423. R = RegCloseKey(Key);
  424. }
  425. return R;
  426. }
  427. //---------------------------------------------------------------------------
  428. TKeyType KeyType(AnsiString FileName)
  429. {
  430. assert(ktUnopenable == SSH_KEYTYPE_UNOPENABLE);
  431. assert(ktSSHCom == SSH_KEYTYPE_SSHCOM);
  432. Filename KeyFile;
  433. ASCOPY(KeyFile.path, FileName);
  434. return (TKeyType)key_type(&KeyFile);
  435. }
  436. //---------------------------------------------------------------------------
  437. AnsiString KeyTypeName(TKeyType KeyType)
  438. {
  439. return key_type_to_str(KeyType);
  440. }
  441. //---------------------------------------------------------------------------
  442. //---------------------------------------------------------------------------
  443. struct TUnicodeEmitParams
  444. {
  445. WideString Buffer;
  446. int Pos;
  447. int Len;
  448. };
  449. //---------------------------------------------------------------------------
  450. extern "C" void UnicodeEmit(void * AParams, long int Output)
  451. {
  452. if (Output == 0xFFFFL) // see Putty's charset\internal.h
  453. {
  454. throw Exception(LoadStr(DECODE_UTF_ERROR));
  455. }
  456. TUnicodeEmitParams * Params = (TUnicodeEmitParams *)AParams;
  457. if (Params->Pos >= Params->Len)
  458. {
  459. Params->Len += 50;
  460. Params->Buffer.SetLength(Params->Len);
  461. }
  462. Params->Pos++;
  463. Params->Buffer[Params->Pos] = (wchar_t)Output;
  464. }
  465. //---------------------------------------------------------------------------
  466. AnsiString __fastcall DecodeUTF(const AnsiString UTF)
  467. {
  468. charset_state State;
  469. char * Str;
  470. TUnicodeEmitParams Params;
  471. AnsiString Result;
  472. State.s0 = 0;
  473. Str = UTF.c_str();
  474. Params.Pos = 0;
  475. Params.Len = UTF.Length();
  476. Params.Buffer.SetLength(Params.Len);
  477. while (*Str)
  478. {
  479. read_utf8(NULL, (unsigned char)*Str, &State, UnicodeEmit, &Params);
  480. Str++;
  481. }
  482. Params.Buffer.SetLength(Params.Pos);
  483. return Params.Buffer;
  484. }
  485. //---------------------------------------------------------------------------
  486. struct TUnicodeEmitParams2
  487. {
  488. AnsiString Buffer;
  489. int Pos;
  490. int Len;
  491. };
  492. //---------------------------------------------------------------------------
  493. extern "C" void UnicodeEmit2(void * AParams, long int Output)
  494. {
  495. if (Output == 0xFFFFL) // see Putty's charset\internal.h
  496. {
  497. throw Exception(LoadStr(DECODE_UTF_ERROR));
  498. }
  499. TUnicodeEmitParams2 * Params = (TUnicodeEmitParams2 *)AParams;
  500. if (Params->Pos >= Params->Len)
  501. {
  502. Params->Len += 50;
  503. Params->Buffer.SetLength(Params->Len);
  504. }
  505. Params->Pos++;
  506. Params->Buffer[Params->Pos] = (unsigned char)Output;
  507. }
  508. //---------------------------------------------------------------------------
  509. AnsiString __fastcall EncodeUTF(const WideString Source)
  510. {
  511. // WideString::c_bstr() returns NULL for empty strings
  512. // (as opposite to AnsiString::c_str() which returns "")
  513. if (Source.IsEmpty())
  514. {
  515. return "";
  516. }
  517. else
  518. {
  519. charset_state State;
  520. wchar_t * Str;
  521. TUnicodeEmitParams2 Params;
  522. AnsiString Result;
  523. State.s0 = 0;
  524. Str = Source.c_bstr();
  525. Params.Pos = 0;
  526. Params.Len = Source.Length();
  527. Params.Buffer.SetLength(Params.Len);
  528. while (*Str)
  529. {
  530. write_utf8(NULL, (wchar_t)*Str, &State, UnicodeEmit2, &Params);
  531. Str++;
  532. }
  533. Params.Buffer.SetLength(Params.Pos);
  534. return Params.Buffer;
  535. }
  536. }
  537. //---------------------------------------------------------------------------
  538. __int64 __fastcall ParseSize(AnsiString SizeStr)
  539. {
  540. return parse_blocksize(SizeStr.c_str());
  541. }
  542. //---------------------------------------------------------------------------
  543. bool __fastcall HasGSSAPI()
  544. {
  545. static int has = -1;
  546. if (has < 0)
  547. {
  548. has = (has_gssapi_ssh() ? 1 : 0);
  549. }
  550. return (has > 0);
  551. }
  552. //---------------------------------------------------------------------------