PuttyIntf.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  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. #include <StrUtils.hpp>
  12. //---------------------------------------------------------------------------
  13. char sshver[50];
  14. const int platform_uses_x11_unix_by_default = TRUE;
  15. CRITICAL_SECTION putty_section;
  16. bool SaveRandomSeed;
  17. char appname_[50];
  18. const char *const appname = appname_;
  19. extern const int share_can_be_downstream = FALSE;
  20. extern const int share_can_be_upstream = FALSE;
  21. //---------------------------------------------------------------------------
  22. extern "C"
  23. {
  24. #include <winstuff.h>
  25. }
  26. const UnicodeString OriginalPuttyRegistryStorageKey(_T(PUTTY_REG_POS));
  27. const UnicodeString KittyRegistryStorageKey(L"Software\\9bis.com\\KiTTY");
  28. const UnicodeString OriginalPuttyExecutable("putty.exe");
  29. const UnicodeString KittyExecutable("kitty.exe");
  30. //---------------------------------------------------------------------------
  31. void __fastcall PuttyInitialize()
  32. {
  33. SaveRandomSeed = true;
  34. InitializeCriticalSection(&putty_section);
  35. // make sure random generator is initialised, so random_save_seed()
  36. // in destructor can proceed
  37. random_ref();
  38. flags = FLAG_VERBOSE | FLAG_SYNCAGENT; // verbose log
  39. sk_init();
  40. AnsiString VersionString = AnsiString(SshVersionString());
  41. DebugAssert(!VersionString.IsEmpty() && (static_cast<size_t>(VersionString.Length()) < LENOF(sshver)));
  42. strcpy(sshver, VersionString.c_str());
  43. AnsiString AppName = AnsiString(AppNameString());
  44. DebugAssert(!AppName.IsEmpty() && (static_cast<size_t>(AppName.Length()) < LENOF(appname_)));
  45. strcpy(appname_, AppName.c_str());
  46. }
  47. //---------------------------------------------------------------------------
  48. void __fastcall PuttyFinalize()
  49. {
  50. if (SaveRandomSeed)
  51. {
  52. random_save_seed();
  53. }
  54. random_unref();
  55. sk_cleanup();
  56. win_misc_cleanup();
  57. win_secur_cleanup();
  58. DeleteCriticalSection(&putty_section);
  59. }
  60. //---------------------------------------------------------------------------
  61. void __fastcall DontSaveRandomSeed()
  62. {
  63. SaveRandomSeed = false;
  64. }
  65. //---------------------------------------------------------------------------
  66. extern "C" char * do_select(Plug plug, SOCKET skt, int startup)
  67. {
  68. void * frontend;
  69. if (!is_ssh(plug) && !is_pfwd(plug))
  70. {
  71. // If it is not SSH/PFwd plug, then it must be Proxy plug.
  72. // Get SSH/PFwd plug which it wraps.
  73. Proxy_Socket ProxySocket = ((Proxy_Plug)plug)->proxy_socket;
  74. plug = ProxySocket->plug;
  75. }
  76. bool pfwd = is_pfwd(plug);
  77. if (pfwd)
  78. {
  79. plug = (Plug)get_pfwd_backend(plug);
  80. }
  81. frontend = get_ssh_frontend(plug);
  82. DebugAssert(frontend);
  83. TSecureShell * SecureShell = reinterpret_cast<TSecureShell*>(frontend);
  84. if (!pfwd)
  85. {
  86. SecureShell->UpdateSocket(skt, startup);
  87. }
  88. else
  89. {
  90. SecureShell->UpdatePortFwdSocket(skt, startup);
  91. }
  92. return NULL;
  93. }
  94. //---------------------------------------------------------------------------
  95. int from_backend(void * frontend, int is_stderr, const char * data, int datalen)
  96. {
  97. DebugAssert(frontend);
  98. if (is_stderr >= 0)
  99. {
  100. DebugAssert((is_stderr == 0) || (is_stderr == 1));
  101. ((TSecureShell *)frontend)->FromBackend((is_stderr == 1), reinterpret_cast<const unsigned char *>(data), datalen);
  102. }
  103. else
  104. {
  105. DebugAssert(is_stderr == -1);
  106. ((TSecureShell *)frontend)->CWrite(data, datalen);
  107. }
  108. return 0;
  109. }
  110. //---------------------------------------------------------------------------
  111. int from_backend_untrusted(void * /*frontend*/, const char * /*data*/, int /*len*/)
  112. {
  113. // currently used with authentication banner only,
  114. // for which we have own interface display_banner
  115. return 0;
  116. }
  117. //---------------------------------------------------------------------------
  118. int from_backend_eof(void * /*frontend*/)
  119. {
  120. return FALSE;
  121. }
  122. //---------------------------------------------------------------------------
  123. int get_userpass_input(prompts_t * p, const unsigned char * /*in*/, int /*inlen*/)
  124. {
  125. DebugAssert(p != NULL);
  126. TSecureShell * SecureShell = reinterpret_cast<TSecureShell *>(p->frontend);
  127. DebugAssert(SecureShell != NULL);
  128. int Result;
  129. TStrings * Prompts = new TStringList();
  130. TStrings * Results = new TStringList();
  131. try
  132. {
  133. UnicodeString Name = UTF8ToString(p->name);
  134. UnicodeString AName = Name;
  135. TPromptKind PromptKind = SecureShell->IdentifyPromptKind(AName);
  136. bool UTF8Prompt = (PromptKind != pkPassphrase);
  137. for (int Index = 0; Index < int(p->n_prompts); Index++)
  138. {
  139. prompt_t * Prompt = p->prompts[Index];
  140. UnicodeString S;
  141. if (UTF8Prompt)
  142. {
  143. S = UTF8ToString(Prompt->prompt);
  144. }
  145. else
  146. {
  147. S = UnicodeString(AnsiString(Prompt->prompt));
  148. }
  149. Prompts->AddObject(S, (TObject *)(FLAGMASK(Prompt->echo, pupEcho)));
  150. // this fails, when new passwords do not match on change password prompt,
  151. // and putty retries the prompt
  152. DebugAssert(Prompt->resultsize == 0);
  153. Results->Add(L"");
  154. }
  155. UnicodeString Instructions = UTF8ToString(p->instruction);
  156. if (SecureShell->PromptUser(p->to_server, Name, p->name_reqd,
  157. Instructions, p->instr_reqd, Prompts, Results))
  158. {
  159. for (int Index = 0; Index < int(p->n_prompts); Index++)
  160. {
  161. prompt_t * Prompt = p->prompts[Index];
  162. RawByteString S;
  163. if (UTF8Prompt)
  164. {
  165. S = RawByteString(UTF8String(Results->Strings[Index]));
  166. }
  167. else
  168. {
  169. S = RawByteString(AnsiString(Results->Strings[Index]));
  170. }
  171. prompt_set_result(Prompt, S.c_str());
  172. }
  173. Result = 1;
  174. }
  175. else
  176. {
  177. Result = 0;
  178. }
  179. }
  180. __finally
  181. {
  182. delete Prompts;
  183. delete Results;
  184. }
  185. return Result;
  186. }
  187. //---------------------------------------------------------------------------
  188. char * get_ttymode(void * /*frontend*/, const char * /*mode*/)
  189. {
  190. // should never happen when Config.nopty == TRUE
  191. DebugFail();
  192. return NULL;
  193. }
  194. //---------------------------------------------------------------------------
  195. void logevent(void * frontend, const char * string)
  196. {
  197. // Frontend maybe NULL here
  198. if (frontend != NULL)
  199. {
  200. ((TSecureShell *)frontend)->PuttyLogEvent(string);
  201. }
  202. }
  203. //---------------------------------------------------------------------------
  204. void connection_fatal(void * frontend, const char * fmt, ...)
  205. {
  206. va_list Param;
  207. char Buf[200];
  208. va_start(Param, fmt);
  209. vsnprintf(Buf, LENOF(Buf), fmt, Param); \
  210. Buf[LENOF(Buf) - 1] = '\0'; \
  211. va_end(Param);
  212. DebugAssert(frontend != NULL);
  213. ((TSecureShell *)frontend)->PuttyFatalError(Buf);
  214. }
  215. //---------------------------------------------------------------------------
  216. int verify_ssh_host_key(void * frontend, char * host, int port, const char * keytype,
  217. char * keystr, char * fingerprint, void (*/*callback*/)(void * ctx, int result),
  218. void * /*ctx*/)
  219. {
  220. DebugAssert(frontend != NULL);
  221. static_cast<TSecureShell *>(frontend)->VerifyHostKey(host, port, keytype, keystr, fingerprint);
  222. // We should return 0 when key was not confirmed, we throw exception instead.
  223. return 1;
  224. }
  225. //---------------------------------------------------------------------------
  226. int have_ssh_host_key(void * frontend, const char * hostname, int port,
  227. const char * keytype)
  228. {
  229. DebugAssert(frontend != NULL);
  230. return static_cast<TSecureShell *>(frontend)->HaveHostKey(hostname, port, keytype) ? 1 : 0;
  231. }
  232. //---------------------------------------------------------------------------
  233. int askalg(void * frontend, const char * algtype, const char * algname,
  234. void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
  235. {
  236. DebugAssert(frontend != NULL);
  237. ((TSecureShell *)frontend)->AskAlg(algtype, algname);
  238. // We should return 0 when alg was not confirmed, we throw exception instead.
  239. return 1;
  240. }
  241. //---------------------------------------------------------------------------
  242. void old_keyfile_warning(void)
  243. {
  244. // no reference to TSecureShell instace available
  245. }
  246. //---------------------------------------------------------------------------
  247. void display_banner(void * frontend, const char * banner, int size)
  248. {
  249. DebugAssert(frontend);
  250. UnicodeString Banner(UTF8String(banner, size));
  251. ((TSecureShell *)frontend)->DisplayBanner(Banner);
  252. }
  253. //---------------------------------------------------------------------------
  254. static void SSHFatalError(const char * Format, va_list Param)
  255. {
  256. char Buf[200];
  257. vsnprintf(Buf, LENOF(Buf), Format, Param);
  258. Buf[LENOF(Buf) - 1] = '\0';
  259. // Only few calls from putty\winnet.c might be connected with specific
  260. // TSecureShell. Otherwise called only for really fatal errors
  261. // like 'out of memory' from putty\ssh.c.
  262. throw ESshFatal(NULL, Buf);
  263. }
  264. //---------------------------------------------------------------------------
  265. void fatalbox(const char * fmt, ...)
  266. {
  267. va_list Param;
  268. va_start(Param, fmt);
  269. SSHFatalError(fmt, Param);
  270. va_end(Param);
  271. }
  272. //---------------------------------------------------------------------------
  273. void modalfatalbox(const char * fmt, ...)
  274. {
  275. va_list Param;
  276. va_start(Param, fmt);
  277. SSHFatalError(fmt, Param);
  278. va_end(Param);
  279. }
  280. //---------------------------------------------------------------------------
  281. void nonfatal(const char * fmt, ...)
  282. {
  283. va_list Param;
  284. va_start(Param, fmt);
  285. SSHFatalError(fmt, Param);
  286. va_end(Param);
  287. }
  288. //---------------------------------------------------------------------------
  289. void cleanup_exit(int /*code*/)
  290. {
  291. throw ESshFatal(NULL, "");
  292. }
  293. //---------------------------------------------------------------------------
  294. int askappend(void * /*frontend*/, Filename * /*filename*/,
  295. void (*/*callback*/)(void * ctx, int result), void * /*ctx*/)
  296. {
  297. // this is called from logging.c of putty, which is never used with WinSCP
  298. DebugFail();
  299. return 0;
  300. }
  301. //---------------------------------------------------------------------------
  302. void ldisc_echoedit_update(void * /*handle*/)
  303. {
  304. DebugFail();
  305. }
  306. //---------------------------------------------------------------------------
  307. void agent_schedule_callback(void (* /*callback*/)(void *, void *, int),
  308. void * /*callback_ctx*/, void * /*data*/, int /*len*/)
  309. {
  310. DebugFail();
  311. }
  312. //---------------------------------------------------------------------------
  313. void notify_remote_exit(void * /*frontend*/)
  314. {
  315. // nothing
  316. }
  317. //---------------------------------------------------------------------------
  318. void update_specials_menu(void * /*frontend*/)
  319. {
  320. // nothing
  321. }
  322. //---------------------------------------------------------------------------
  323. unsigned long schedule_timer(int ticks, timer_fn_t /*fn*/, void * /*ctx*/)
  324. {
  325. return ticks + GetTickCount();
  326. }
  327. //---------------------------------------------------------------------------
  328. void expire_timer_context(void * /*ctx*/)
  329. {
  330. // nothing
  331. }
  332. //---------------------------------------------------------------------------
  333. Pinger pinger_new(Conf * /*conf*/, Backend * /*back*/, void * /*backhandle*/)
  334. {
  335. return NULL;
  336. }
  337. //---------------------------------------------------------------------------
  338. void pinger_reconfig(Pinger /*pinger*/, Conf * /*oldconf*/, Conf * /*newconf*/)
  339. {
  340. // nothing
  341. }
  342. //---------------------------------------------------------------------------
  343. void pinger_free(Pinger /*pinger*/)
  344. {
  345. // nothing
  346. }
  347. //---------------------------------------------------------------------------
  348. void set_busy_status(void * /*frontend*/, int /*status*/)
  349. {
  350. // nothing
  351. }
  352. //---------------------------------------------------------------------------
  353. void platform_get_x11_auth(struct X11Display * /*display*/, Conf * /*conf*/)
  354. {
  355. // nothing, therefore no auth.
  356. }
  357. //---------------------------------------------------------------------------
  358. // Based on PuTTY's settings.c
  359. char * get_remote_username(Conf * conf)
  360. {
  361. char * username = conf_get_str(conf, CONF_username);
  362. char * result;
  363. if (*username)
  364. {
  365. result = dupstr(username);
  366. }
  367. else
  368. {
  369. result = NULL;
  370. }
  371. return result;
  372. }
  373. //---------------------------------------------------------------------------
  374. static long OpenWinSCPKey(HKEY Key, const char * SubKey, HKEY * Result, bool CanCreate)
  375. {
  376. long R;
  377. DebugAssert(Configuration != NULL);
  378. DebugAssert(Key == HKEY_CURRENT_USER);
  379. DebugUsedParam(Key);
  380. UnicodeString RegKey = SubKey;
  381. int PuttyKeyLen = OriginalPuttyRegistryStorageKey.Length();
  382. DebugAssert(RegKey.SubString(1, PuttyKeyLen) == OriginalPuttyRegistryStorageKey);
  383. RegKey = RegKey.SubString(PuttyKeyLen + 1, RegKey.Length() - PuttyKeyLen);
  384. if (!RegKey.IsEmpty())
  385. {
  386. DebugAssert(RegKey[1] == L'\\');
  387. RegKey.Delete(1, 1);
  388. }
  389. if (RegKey.IsEmpty())
  390. {
  391. *Result = static_cast<HKEY>(NULL);
  392. R = ERROR_SUCCESS;
  393. }
  394. else
  395. {
  396. // we expect this to be called only from verify_host_key() or store_host_key()
  397. DebugAssert(RegKey == L"SshHostKeys");
  398. THierarchicalStorage * Storage = Configuration->CreateConfigStorage();
  399. Storage->AccessMode = (CanCreate ? smReadWrite : smRead);
  400. if (Storage->OpenSubKey(RegKey, CanCreate))
  401. {
  402. *Result = reinterpret_cast<HKEY>(Storage);
  403. R = ERROR_SUCCESS;
  404. }
  405. else
  406. {
  407. delete Storage;
  408. R = ERROR_CANTOPEN;
  409. }
  410. }
  411. return R;
  412. }
  413. //---------------------------------------------------------------------------
  414. long reg_open_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
  415. {
  416. return OpenWinSCPKey(Key, SubKey, Result, false);
  417. }
  418. //---------------------------------------------------------------------------
  419. long reg_create_winscp_key(HKEY Key, const char * SubKey, HKEY * Result)
  420. {
  421. return OpenWinSCPKey(Key, SubKey, Result, true);
  422. }
  423. //---------------------------------------------------------------------------
  424. long reg_query_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long * /*Reserved*/,
  425. unsigned long * Type, unsigned char * Data, unsigned long * DataSize)
  426. {
  427. long R;
  428. DebugAssert(Configuration != NULL);
  429. THierarchicalStorage * Storage = reinterpret_cast<THierarchicalStorage *>(Key);
  430. AnsiString Value;
  431. if (Storage == NULL)
  432. {
  433. if (UnicodeString(ValueName) == L"RandSeedFile")
  434. {
  435. Value = AnsiString(Configuration->RandomSeedFileName);
  436. R = ERROR_SUCCESS;
  437. }
  438. else
  439. {
  440. DebugFail();
  441. R = ERROR_READ_FAULT;
  442. }
  443. }
  444. else
  445. {
  446. if (Storage->ValueExists(ValueName))
  447. {
  448. Value = AnsiString(Storage->ReadStringRaw(ValueName, L""));
  449. R = ERROR_SUCCESS;
  450. }
  451. else
  452. {
  453. R = ERROR_READ_FAULT;
  454. }
  455. }
  456. if (R == ERROR_SUCCESS)
  457. {
  458. DebugAssert(Type != NULL);
  459. *Type = REG_SZ;
  460. char * DataStr = reinterpret_cast<char *>(Data);
  461. strncpy(DataStr, Value.c_str(), *DataSize);
  462. DataStr[*DataSize - 1] = '\0';
  463. *DataSize = strlen(DataStr);
  464. }
  465. return R;
  466. }
  467. //---------------------------------------------------------------------------
  468. long reg_set_winscp_value_ex(HKEY Key, const char * ValueName, unsigned long /*Reserved*/,
  469. unsigned long Type, const unsigned char * Data, unsigned long DataSize)
  470. {
  471. DebugAssert(Configuration != NULL);
  472. DebugAssert(Type == REG_SZ);
  473. DebugUsedParam(Type);
  474. THierarchicalStorage * Storage = reinterpret_cast<THierarchicalStorage *>(Key);
  475. DebugAssert(Storage != NULL);
  476. if (Storage != NULL)
  477. {
  478. UnicodeString Value(reinterpret_cast<const char*>(Data), DataSize - 1);
  479. Storage->WriteStringRaw(ValueName, Value);
  480. }
  481. return ERROR_SUCCESS;
  482. }
  483. //---------------------------------------------------------------------------
  484. long reg_close_winscp_key(HKEY Key)
  485. {
  486. DebugAssert(Configuration != NULL);
  487. THierarchicalStorage * Storage = reinterpret_cast<THierarchicalStorage *>(Key);
  488. if (Storage != NULL)
  489. {
  490. delete Storage;
  491. }
  492. return ERROR_SUCCESS;
  493. }
  494. //---------------------------------------------------------------------------
  495. TKeyType KeyType(UnicodeString FileName)
  496. {
  497. DebugAssert(ktUnopenable == SSH_KEYTYPE_UNOPENABLE);
  498. DebugAssert(ktSSHCom == SSH_KEYTYPE_SSHCOM);
  499. DebugAssert(ktSSH2PublicOpenSSH == SSH_KEYTYPE_SSH2_PUBLIC_OPENSSH);
  500. UTF8String UtfFileName = UTF8String(FileName);
  501. Filename * KeyFile = filename_from_str(UtfFileName.c_str());
  502. TKeyType Result = (TKeyType)key_type(KeyFile);
  503. filename_free(KeyFile);
  504. return Result;
  505. }
  506. //---------------------------------------------------------------------------
  507. bool IsKeyEncrypted(TKeyType KeyType, const UnicodeString & FileName, UnicodeString & Comment)
  508. {
  509. UTF8String UtfFileName = UTF8String(FileName);
  510. Filename * KeyFile = filename_from_str(UtfFileName.c_str());
  511. bool Result;
  512. char * CommentStr = NULL;
  513. switch (KeyType)
  514. {
  515. case ktSSH2:
  516. Result = (ssh2_userkey_encrypted(KeyFile, &CommentStr) != 0);
  517. break;
  518. case ktOpenSSHPEM:
  519. case ktOpenSSHNew:
  520. case ktSSHCom:
  521. Result = (import_encrypted(KeyFile, KeyType, &CommentStr) != NULL);
  522. break;
  523. default:
  524. DebugFail();
  525. Result = false;
  526. break;
  527. }
  528. if (CommentStr != NULL)
  529. {
  530. Comment = UnicodeString(AnsiString(CommentStr));
  531. // ktOpenSSH has no comment, PuTTY defaults to file path
  532. if (Comment == FileName)
  533. {
  534. Comment = ExtractFileName(FileName);
  535. }
  536. sfree(CommentStr);
  537. }
  538. return Result;
  539. }
  540. //---------------------------------------------------------------------------
  541. TPrivateKey * LoadKey(TKeyType KeyType, const UnicodeString & FileName, const UnicodeString & Passphrase)
  542. {
  543. UTF8String UtfFileName = UTF8String(FileName);
  544. Filename * KeyFile = filename_from_str(UtfFileName.c_str());
  545. AnsiString AnsiPassphrase = Passphrase;
  546. struct ssh2_userkey * Ssh2Key = NULL;
  547. const char * ErrorStr = NULL;
  548. switch (KeyType)
  549. {
  550. case ktSSH2:
  551. Ssh2Key = ssh2_load_userkey(KeyFile, AnsiPassphrase.c_str(), &ErrorStr);
  552. break;
  553. case ktOpenSSHPEM:
  554. case ktOpenSSHNew:
  555. case ktSSHCom:
  556. Ssh2Key = import_ssh2(KeyFile, KeyType, AnsiPassphrase.c_str(), &ErrorStr);
  557. break;
  558. default:
  559. DebugFail();
  560. break;
  561. }
  562. Shred(AnsiPassphrase);
  563. if (Ssh2Key == NULL)
  564. {
  565. UnicodeString Error = AnsiString(ErrorStr);
  566. // While theoretically we may get "unable to open key file" and
  567. // so we should check system error code,
  568. // we actully never get here unless we call KeyType previously
  569. // and handle ktUnopenable accordingly.
  570. throw Exception(Error);
  571. }
  572. else if (Ssh2Key == SSH2_WRONG_PASSPHRASE)
  573. {
  574. throw Exception(LoadStr(AUTH_TRANSL_WRONG_PASSPHRASE));
  575. }
  576. return reinterpret_cast<TPrivateKey *>(Ssh2Key);
  577. }
  578. //---------------------------------------------------------------------------
  579. void ChangeKeyComment(TPrivateKey * PrivateKey, const UnicodeString & Comment)
  580. {
  581. AnsiString AnsiComment(Comment);
  582. struct ssh2_userkey * Ssh2Key = reinterpret_cast<struct ssh2_userkey *>(PrivateKey);
  583. sfree(Ssh2Key->comment);
  584. Ssh2Key->comment = dupstr(AnsiComment.c_str());
  585. }
  586. //---------------------------------------------------------------------------
  587. void SaveKey(TKeyType KeyType, const UnicodeString & FileName,
  588. const UnicodeString & Passphrase, TPrivateKey * PrivateKey)
  589. {
  590. UTF8String UtfFileName = UTF8String(FileName);
  591. Filename * KeyFile = filename_from_str(UtfFileName.c_str());
  592. struct ssh2_userkey * Ssh2Key = reinterpret_cast<struct ssh2_userkey *>(PrivateKey);
  593. AnsiString AnsiPassphrase = Passphrase;
  594. char * PassphrasePtr = (AnsiPassphrase.IsEmpty() ? NULL : AnsiPassphrase.c_str());
  595. switch (KeyType)
  596. {
  597. case ktSSH2:
  598. if (!ssh2_save_userkey(KeyFile, Ssh2Key, PassphrasePtr))
  599. {
  600. int Error = errno;
  601. throw EOSExtException(FMTLOAD(KEY_SAVE_ERROR, (FileName)), Error);
  602. }
  603. break;
  604. default:
  605. DebugFail();
  606. break;
  607. }
  608. }
  609. //---------------------------------------------------------------------------
  610. void FreeKey(TPrivateKey * PrivateKey)
  611. {
  612. struct ssh2_userkey * Ssh2Key = reinterpret_cast<struct ssh2_userkey *>(PrivateKey);
  613. Ssh2Key->alg->freekey(Ssh2Key->data);
  614. sfree(Ssh2Key);
  615. }
  616. //---------------------------------------------------------------------------
  617. __int64 __fastcall ParseSize(UnicodeString SizeStr)
  618. {
  619. AnsiString AnsiSizeStr = AnsiString(SizeStr);
  620. return parse_blocksize64(AnsiSizeStr.c_str());
  621. }
  622. //---------------------------------------------------------------------------
  623. bool __fastcall HasGSSAPI(UnicodeString CustomPath)
  624. {
  625. static int has = -1;
  626. if (has < 0)
  627. {
  628. Conf * conf = conf_new();
  629. ssh_gss_liblist * List = NULL;
  630. try
  631. {
  632. Filename * filename = filename_from_str(UTF8String(CustomPath).c_str());
  633. conf_set_filename(conf, CONF_ssh_gss_custom, filename);
  634. filename_free(filename);
  635. List = ssh_gss_setup(conf);
  636. for (int Index = 0; (has <= 0) && (Index < List->nlibraries); Index++)
  637. {
  638. ssh_gss_library * library = &List->libraries[Index];
  639. Ssh_gss_ctx ctx;
  640. memset(&ctx, 0, sizeof(ctx));
  641. has =
  642. ((library->acquire_cred(library, &ctx) == SSH_GSS_OK) &&
  643. (library->release_cred(library, &ctx) == SSH_GSS_OK)) ? 1 : 0;
  644. }
  645. }
  646. __finally
  647. {
  648. ssh_gss_cleanup(List);
  649. conf_free(conf);
  650. }
  651. if (has < 0)
  652. {
  653. has = 0;
  654. }
  655. }
  656. return (has > 0);
  657. }
  658. //---------------------------------------------------------------------------
  659. static void __fastcall DoNormalizeFingerprint(UnicodeString & Fingerprint, UnicodeString & KeyType)
  660. {
  661. int Count = 0;
  662. const wchar_t NormalizedSeparator = L'-';
  663. // We may use find_pubkey_alg, but it gets complicated with normalized fingerprint
  664. // as the names have different number of dashes
  665. const ssh_signkey ** SignKeys = get_hostkey_algs(&Count);
  666. for (int Index = 0; Index < Count; Index++)
  667. {
  668. const ssh_signkey * SignKey = SignKeys[Index];
  669. UnicodeString Name = UnicodeString(SignKey->name);
  670. if (StartsStr(Name + L" ", Fingerprint))
  671. {
  672. int LenStart = Name.Length() + 1;
  673. Fingerprint[LenStart] = NormalizedSeparator;
  674. int Space = Fingerprint.Pos(L" ");
  675. DebugAssert(IsNumber(Fingerprint.SubString(LenStart + 1, Space - LenStart - 1)));
  676. Fingerprint.Delete(LenStart + 1, Space - LenStart);
  677. Fingerprint = ReplaceChar(Fingerprint, L':', NormalizedSeparator);
  678. KeyType = UnicodeString(SignKey->keytype);
  679. return;
  680. }
  681. else if (StartsStr(Name + NormalizedSeparator, Fingerprint))
  682. {
  683. KeyType = UnicodeString(SignKey->keytype);
  684. return;
  685. }
  686. }
  687. }
  688. //---------------------------------------------------------------------------
  689. UnicodeString __fastcall NormalizeFingerprint(UnicodeString Fingerprint)
  690. {
  691. UnicodeString KeyType; // unused
  692. DoNormalizeFingerprint(Fingerprint, KeyType);
  693. return Fingerprint;
  694. }
  695. //---------------------------------------------------------------------------
  696. UnicodeString __fastcall KeyTypeFromFingerprint(UnicodeString Fingerprint)
  697. {
  698. UnicodeString KeyType;
  699. DoNormalizeFingerprint(Fingerprint, KeyType);
  700. return KeyType;
  701. }
  702. //---------------------------------------------------------------------------
  703. UnicodeString __fastcall GetPuTTYVersion()
  704. {
  705. // "Release 0.64"
  706. // "Pre-release 0.65:2015-07-20.95501a1"
  707. // "Development snapshot 2015-12-22.51465fa"
  708. UnicodeString Result = get_putty_version();
  709. // Skip "Release", "Pre-release", "Development snapshot"
  710. int P = Result.LastDelimiter(L" ");
  711. Result.Delete(1, P);
  712. return Result;
  713. }
  714. //---------------------------------------------------------------------------
  715. UnicodeString __fastcall Sha256(const char * Data, size_t Size)
  716. {
  717. unsigned char Digest[32];
  718. SHA256_Simple(Data, Size, Digest);
  719. UnicodeString Result(BytesToHex(Digest, LENOF(Digest)));
  720. return Result;
  721. }
  722. //---------------------------------------------------------------------------
  723. //---------------------------------------------------------------------------