PuttyIntf.cpp 18 KB

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