Develop and Download Open Source Software

Browse Subversion Repository

Contents of /branches/ssh_chacha20poly1305/ttssh2/ttxssh/ttxssh.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2909 - (show annotations) (download) (as text)
Mon Sep 18 06:14:48 2006 UTC (17 years, 6 months ago) by maya
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 90139 byte(s)
ポートフォワードしているウインドウから新規接続するとエラーが出る問題を修正した。

1 /*
2 Copyright (c) 1998-2001, Robert O'Callahan
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 Redistributions of source code must retain the above copyright notice, this list of
9 conditions and the following disclaimer.
10
11 Redistributions in binary form must reproduce the above copyright notice, this list
12 of conditions and the following disclaimer in the documentation and/or other materials
13 provided with the distribution.
14
15 The name of Robert O'Callahan may not be used to endorse or promote products derived from
16 this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* Teraterm extension mechanism
30 Robert O'Callahan (roc+tt@cs.cmu.edu)
31
32 Teraterm by Takashi Teranishi (teranishi@rikaxp.riken.go.jp)
33 */
34
35 #include "ttxssh.h"
36 #include "fwdui.h"
37 #include "util.h"
38 #include "ssh.h"
39
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <io.h>
44 #include <fcntl.h>
45 #include <sys/stat.h>
46 #include <time.h>
47
48 #include "resource.h"
49 #include <commctrl.h>
50 #include <commdlg.h>
51 #ifdef INET6
52 #include <winsock2.h>
53 static char FAR *ProtocolFamilyList[] = { "UNSPEC", "IPv6", "IPv4", NULL };
54 #else
55 #include <winsock.h>
56 #endif /* INET6 */
57
58 #include <Lmcons.h>
59
60 // include OpenSSL header file
61 #include <openssl/opensslv.h>
62 #include <openssl/evp.h>
63 #include <openssl/rsa.h>
64 #include <openssl/dsa.h>
65 #include <openssl/bn.h>
66 #include <openssl/pem.h>
67 #include <openssl/rand.h>
68 #include <openssl/rc4.h>
69 #include <openssl/md5.h>
70
71 // include ZLib header file
72 #include <zlib.h>
73
74 #include "buffer.h"
75 #include "cipher.h"
76
77 #define MATCH_STR(s, o) _strnicmp((s), (o), NUM_ELEM(o) - 1)
78
79 /* This extension implements SSH, so we choose a load order in the
80 "protocols" range. */
81 #define ORDER 2500
82
83 #ifdef TERATERM32
84 static HICON SecureLargeIcon = NULL;
85 static HICON SecureSmallIcon = NULL;
86 #endif
87
88 static TInstVar FAR *pvar;
89
90 #ifdef TERATERM32
91 /* WIN32 allows multiple instances of a DLL */
92 static TInstVar InstVar;
93 #define GET_VAR()
94 #else
95 /* WIN16 does not allow multiple instances of a DLL */
96
97 /* maximum number of Tera Term instances */
98 #define MAXNUMINST 32
99 /* list of task handles for Tera Term instances */
100 static HANDLE FAR TaskList[MAXNUMINST];
101 /* variable sets for instances */
102 static TInstVar FAR *FAR InstVar[MAXNUMINST];
103
104 /* Here's how the TS settings work.
105 Whenever the TS settings are read or written to the INI file, then
106 the shared memory containing those settings is updated.
107 When Teraterm starts, the shared memory is read to initialize the TS
108 settings. */
109
110 /* TS settings shared across instances */
111 static TS_SSH ts_SSH_settings;
112
113
114 extern void SSH2_update_cipher_myproposal(PTInstVar pvar);
115
116
117 static BOOL NewVar()
118 {
119 int i = 0;
120 HANDLE Task = GetCurrentTask();
121
122 if (TaskList[0] == NULL)
123
124 if (Task == NULL)
125 return FALSE;
126 while ((i < MAXNUMINST) && (TaskList[i] != NULL))
127 i++;
128 if (i >= MAXNUMINST)
129 return FALSE;
130 pvar = (TInstVar FAR *) malloc(sizeof(TInstVar));
131 InstVar[i] = pvar;
132 TaskList[i] = Task;
133 return TRUE;
134 }
135
136 void DelVar()
137 {
138 int i = 0;
139 HANDLE Task = GetCurrentTask();
140
141 if (Task == NULL)
142 return;
143 while ((i < MAXNUMINST) && (TaskList[i] != Task))
144 i++;
145 if (i >= MAXNUMINST)
146 return;
147 free(TaskList[i]);
148 TaskList[i] = NULL;
149 }
150
151 BOOL GetVar()
152 {
153 int i = 0;
154 HANDLE Task = GetCurrentTask();
155
156 if (Task == NULL)
157 return FALSE;
158 while ((i < MAXNUMINST) && (TaskList[i] != Task))
159 i++;
160 if (i >= MAXNUMINST)
161 return FALSE;
162 pvar = InstVar[i];
163 return TRUE;
164 }
165
166 #define GET_VAR() if (!GetVar()) return
167 #endif
168
169 /*
170 This code makes lots of assumptions about the order in which Teraterm
171 does things, and how. A key assumption is that the Notification window
172 passed into WSAAsyncSelect is the main terminal window. We also assume
173 that the socket used in the first WSAconnect is the main session socket.
174 */
175
176 static void init_TTSSH(PTInstVar pvar)
177 {
178 pvar->socket = INVALID_SOCKET;
179 pvar->OldLargeIcon = NULL;
180 pvar->OldSmallIcon = NULL;
181 pvar->NotificationWindow = NULL;
182 pvar->hostdlg_activated = FALSE;
183 pvar->socket = INVALID_SOCKET;
184 pvar->NotificationWindow = NULL;
185 pvar->protocol_major = 0;
186 pvar->protocol_minor = 0;
187
188 PKT_init(pvar);
189 SSH_init(pvar);
190 CRYPT_init(pvar);
191 AUTH_init(pvar);
192 HOSTS_init(pvar);
193 FWD_init(pvar);
194 FWDUI_init(pvar);
195
196 ssh_heartbeat_lock_initialize();
197 }
198
199 static void uninit_TTSSH(PTInstVar pvar)
200 {
201 halt_ssh_heartbeat_thread(pvar);
202
203 ssh2_channel_free();
204
205 SSH_end(pvar);
206 PKT_end(pvar);
207 AUTH_end(pvar);
208 CRYPT_end(pvar);
209 HOSTS_end(pvar);
210 FWD_end(pvar);
211 FWDUI_end(pvar);
212
213 if (pvar->OldLargeIcon != NULL) {
214 PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_BIG,
215 (LPARAM) pvar->OldLargeIcon);
216 pvar->OldLargeIcon = NULL;
217 }
218 if (pvar->OldSmallIcon != NULL) {
219 PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_SMALL,
220 (LPARAM) pvar->OldSmallIcon);
221 pvar->OldSmallIcon = NULL;
222 }
223
224 ssh_heartbeat_lock_finalize();
225 }
226
227 static void PASCAL FAR TTXInit(PTTSet ts, PComVar cv)
228 {
229 #ifndef TERATERM32
230 if (!NewVar())
231 return; /* should be called first */
232 pvar->ts_SSH = &ts_SSH_settings;
233 #endif
234 pvar->settings = *pvar->ts_SSH;
235 pvar->ts = ts;
236 pvar->cv = cv;
237 pvar->fatal_error = FALSE;
238 pvar->showing_err = FALSE;
239 pvar->err_msg = NULL;
240
241 init_TTSSH(pvar);
242 }
243
244 static void normalize_cipher_order(char FAR * buf)
245 {
246 char ciphers_listed[SSH_CIPHER_MAX + 1];
247 char ciphers_allowed[SSH_CIPHER_MAX + 1];
248 int i, j;
249
250 /* SSH_CIPHER_NONE means that all ciphers below that one are disabled.
251 We *never* allow no encryption. */
252 #if 0
253 static char default_ciphers[] = {
254 SSH_CIPHER_3DES,
255 SSH_CIPHER_NONE,
256 SSH_CIPHER_DES, SSH_CIPHER_BLOWFISH
257 };
258 #else
259 // for SSH2(yutaka)
260 static char default_ciphers[] = {
261 SSH_CIPHER_AES128,
262 SSH_CIPHER_3DES_CBC,
263 SSH_CIPHER_3DES,
264 SSH_CIPHER_NONE,
265 SSH_CIPHER_DES, SSH_CIPHER_BLOWFISH
266 };
267 #endif
268
269 memset(ciphers_listed, 0, sizeof(ciphers_listed));
270
271 memset(ciphers_allowed, 0, sizeof(ciphers_allowed));
272 for (i = 0; i < NUM_ELEM(default_ciphers); i++) {
273 ciphers_allowed[default_ciphers[i]] = 1;
274 }
275
276 for (i = 0; buf[i] != 0; i++) {
277 int cipher_num = buf[i] - '0';
278
279 if (cipher_num < 0 || cipher_num > SSH_CIPHER_MAX
280 || !ciphers_allowed[cipher_num]
281 || ciphers_listed[cipher_num]) {
282 memmove(buf + i, buf + i + 1, strlen(buf + i + 1) + 1);
283 i--;
284 } else {
285 ciphers_listed[cipher_num] = 1;
286 }
287 }
288
289 for (j = 0; j < NUM_ELEM(default_ciphers); j++) {
290 int cipher_num = default_ciphers[j];
291
292 if (!ciphers_listed[cipher_num]) {
293 buf[i] = cipher_num + '0';
294 i++;
295 }
296 }
297
298 buf[i] = 0;
299 }
300
301 /* Remove local settings from the shared memory block. */
302 static void clear_local_settings(PTInstVar pvar)
303 {
304 pvar->ts_SSH->TryDefaultAuth = FALSE;
305 }
306
307 static BOOL read_BOOL_option(PCHAR fileName, char FAR * keyName, BOOL def)
308 {
309 char buf[1024];
310
311 buf[0] = 0;
312 GetPrivateProfileString("TTSSH", keyName, "", buf, sizeof(buf),
313 fileName);
314 if (buf[0] == 0) {
315 return def;
316 } else {
317 return atoi(buf) != 0 ||
318 _stricmp(buf, "yes") == 0 || _stricmp(buf, "y") == 0;
319 }
320 }
321
322 static void read_string_option(PCHAR fileName, char FAR * keyName,
323 char FAR * def, char FAR * buf, int bufSize)
324 {
325
326 buf[0] = 0;
327 GetPrivateProfileString("TTSSH", keyName, def, buf, bufSize, fileName);
328 }
329
330 static void read_ssh_options(PTInstVar pvar, PCHAR fileName)
331 {
332 char buf[1024];
333 TS_SSH FAR *settings = pvar->ts_SSH;
334
335 #define READ_STD_STRING_OPTION(name) \
336 read_string_option(fileName, #name, "", settings->name, sizeof(settings->name))
337
338 settings->Enabled = read_BOOL_option(fileName, "Enabled", FALSE);
339
340 buf[0] = 0;
341 GetPrivateProfileString("TTSSH", "Compression", "", buf, sizeof(buf),
342 fileName);
343 settings->CompressionLevel = atoi(buf);
344 if (settings->CompressionLevel < 0 || settings->CompressionLevel > 9) {
345 settings->CompressionLevel = 0;
346 }
347
348 READ_STD_STRING_OPTION(DefaultUserName);
349 READ_STD_STRING_OPTION(DefaultForwarding);
350 READ_STD_STRING_OPTION(DefaultRhostsLocalUserName);
351 READ_STD_STRING_OPTION(DefaultRhostsHostPrivateKeyFile);
352 READ_STD_STRING_OPTION(DefaultRSAPrivateKeyFile);
353
354 READ_STD_STRING_OPTION(CipherOrder);
355 normalize_cipher_order(settings->CipherOrder);
356
357 read_string_option(fileName, "KnownHostsFiles", "ssh_known_hosts",
358 settings->KnownHostsFiles,
359 sizeof(settings->KnownHostsFiles));
360
361 buf[0] = 0;
362 GetPrivateProfileString("TTSSH", "DefaultAuthMethod", "", buf,
363 sizeof(buf), fileName);
364 settings->DefaultAuthMethod = atoi(buf);
365 if (settings->DefaultAuthMethod != SSH_AUTH_PASSWORD
366 && settings->DefaultAuthMethod != SSH_AUTH_RSA
367 && settings->DefaultAuthMethod != SSH_AUTH_TIS // add (2005.3.12 yutaka)
368 && settings->DefaultAuthMethod != SSH_AUTH_RHOSTS) {
369 /* this default can never be SSH_AUTH_RHOSTS_RSA because that is not a
370 selection in the dialog box; SSH_AUTH_RHOSTS_RSA is automatically chosen
371 when the dialog box has rhosts selected and an host private key file
372 is supplied. */
373 settings->DefaultAuthMethod = SSH_AUTH_PASSWORD;
374 }
375
376 buf[0] = 0;
377 GetPrivateProfileString("TTSSH", "LogLevel", "", buf, sizeof(buf),
378 fileName);
379 settings->LogLevel = atoi(buf);
380
381 buf[0] = 0;
382 GetPrivateProfileString("TTSSH", "WriteBufferSize", "", buf,
383 sizeof(buf), fileName);
384 settings->WriteBufferSize = atoi(buf);
385 if (settings->WriteBufferSize <= 0) {
386 settings->WriteBufferSize = 2 * 1024 * 1024;
387 }
388
389 settings->LocalForwardingIdentityCheck =
390 read_BOOL_option(fileName, "LocalForwardingIdentityCheck", TRUE);
391
392 // SSH protocol version (2004.10.11 yutaka)
393 // default is SSH2 (2004.11.30 yutaka)
394 settings->ssh_protocol_version = GetPrivateProfileInt("TTSSH", "ProtocolVersion", 2, fileName);
395
396 // SSH heartbeat time(second) (2004.12.11 yutaka)
397 settings->ssh_heartbeat_overtime = GetPrivateProfileInt("TTSSH", "HeartBeat", 60, fileName);
398
399 // SSH2 keyboard-interactive (2005.1.23 yutaka)
400 // �f�t�H���g���������������BOpenSSH 4.0����keyboard-interactive���\�b�h�����`�������������������A
401 // ���Y���\�b�h���g�����R�l�N�V���������������������B(2005.3.12 yutaka)
402 settings->ssh2_keyboard_interactive = GetPrivateProfileInt("TTSSH", "KeyboardInteractive", 0, fileName);
403
404 // �p�X���[�h�F�����������J���F�����g���p�X���[�h����������������������������������
405 // �\���B(2006.8.5 yutaka)
406 settings->remember_password = GetPrivateProfileInt("TTSSH", "RememberPassword", 1, fileName);
407
408 clear_local_settings(pvar);
409 }
410
411 static void write_ssh_options(PTInstVar pvar, PCHAR fileName,
412 TS_SSH FAR * settings, BOOL copy_forward)
413 {
414 char buf[1024];
415
416 WritePrivateProfileString("TTSSH", "Enabled",
417 settings->Enabled ? "1" : "0", fileName);
418
419 _itoa(settings->CompressionLevel, buf, 10);
420 WritePrivateProfileString("TTSSH", "Compression", buf, fileName);
421
422 WritePrivateProfileString("TTSSH", "DefaultUserName",
423 settings->DefaultUserName, fileName);
424
425 if (copy_forward) {
426 WritePrivateProfileString("TTSSH", "DefaultForwarding",
427 settings->DefaultForwarding, fileName);
428 }
429
430 WritePrivateProfileString("TTSSH", "CipherOrder",
431 settings->CipherOrder, fileName);
432
433 WritePrivateProfileString("TTSSH", "KnownHostsFiles",
434 settings->KnownHostsFiles, fileName);
435
436 WritePrivateProfileString("TTSSH", "DefaultRhostsLocalUserName",
437 settings->DefaultRhostsLocalUserName,
438 fileName);
439
440 WritePrivateProfileString("TTSSH", "DefaultRhostsHostPrivateKeyFile",
441 settings->DefaultRhostsHostPrivateKeyFile,
442 fileName);
443
444 WritePrivateProfileString("TTSSH", "DefaultRSAPrivateKeyFile",
445 settings->DefaultRSAPrivateKeyFile,
446 fileName);
447
448 _itoa(settings->DefaultAuthMethod, buf, 10);
449 WritePrivateProfileString("TTSSH", "DefaultAuthMethod", buf, fileName);
450
451 _itoa(settings->LogLevel, buf, 10);
452 WritePrivateProfileString("TTSSH", "LogLevel", buf, fileName);
453
454 _itoa(settings->WriteBufferSize, buf, 10);
455 WritePrivateProfileString("TTSSH", "WriteBufferSize", buf, fileName);
456
457 WritePrivateProfileString("TTSSH", "LocalForwardingIdentityCheck",
458 settings->
459 LocalForwardingIdentityCheck ? "1" : "0",
460 fileName);
461
462 // SSH protocol version (2004.10.11 yutaka)
463 WritePrivateProfileString("TTSSH", "ProtocolVersion",
464 settings->ssh_protocol_version==2 ? "2" : "1",
465 fileName);
466
467 // SSH heartbeat time(second) (2004.12.11 yutaka)
468 _snprintf(buf, sizeof(buf), "%d", settings->ssh_heartbeat_overtime);
469 WritePrivateProfileString("TTSSH", "HeartBeat", buf, fileName);
470
471 // SSH2 keyboard-interactive (2005.1.23 yutaka)
472 WritePrivateProfileString("TTSSH", "KeyboardInteractive",
473 settings->ssh2_keyboard_interactive ? "1" : "0",
474 fileName);
475
476 // Remember password (2006.8.5 yutaka)
477 WritePrivateProfileString("TTSSH", "RememberPassword",
478 settings->remember_password ? "1" : "0",
479 fileName);
480 }
481
482
483 /* find free port in all protocol family */
484 static unsigned short find_local_port(PTInstVar pvar)
485 {
486 int tries;
487 #ifdef INET6
488 SOCKET connecter;
489 struct addrinfo hints;
490 struct addrinfo FAR *res;
491 struct addrinfo FAR *res0;
492 unsigned short port;
493 char pname[NI_MAXHOST];
494 #endif /* INET6 */
495
496 if (pvar->session_settings.DefaultAuthMethod != SSH_AUTH_RHOSTS) {
497 return 0;
498 }
499
500 /* The random numbers here are only used to try to get fresh
501 ports across runs (dangling ports can cause bind errors
502 if we're unlucky). They do not need to be (and are not)
503 cryptographically strong.
504 */
505 srand((unsigned) GetTickCount());
506
507 #ifdef INET6
508 for (tries = 20; tries > 0; tries--) {
509 memset(&hints, 0, sizeof(hints));
510 hints.ai_family = pvar->ts->ProtocolFamily;
511 hints.ai_flags = AI_PASSIVE;
512 hints.ai_socktype = SOCK_STREAM;
513 port = (unsigned) rand() % 512 + 512;
514 _snprintf(pname, sizeof(pname), "%d", (int) port);
515 if (getaddrinfo(NULL, pname, &hints, &res0)) {
516 return 0;
517 /* NOT REACHED */
518 }
519
520 for (res = res0; res; res = res->ai_next) {
521 if (res->ai_family == AF_INET || res->ai_family == AF_INET6)
522 continue;
523
524 connecter =
525 socket(res->ai_family, res->ai_socktype, res->ai_protocol);
526 if (connecter == INVALID_SOCKET) {
527 freeaddrinfo(res0);
528 return 0;
529 }
530
531 if (bind(connecter, res->ai_addr, res->ai_addrlen) !=
532 SOCKET_ERROR) {
533 return port;
534 freeaddrinfo(res0);
535 closesocket(connecter);
536 } else if (WSAGetLastError() != WSAEADDRINUSE) {
537 closesocket(connecter);
538 freeaddrinfo(res0);
539 return 0;
540 }
541
542 closesocket(connecter);
543 }
544 freeaddrinfo(res0);
545 }
546
547 return 0;
548 #else
549 for (tries = 20; tries > 0; tries--) {
550 SOCKET connecter = socket(AF_INET, SOCK_STREAM, 0);
551 struct sockaddr_in connecter_addr;
552
553 connecter_addr.sin_family = AF_INET;
554 connecter_addr.sin_port = (unsigned) rand() % 512 + 512;
555 connecter_addr.sin_addr.s_addr = htonl(INADDR_ANY);
556
557 if (connecter == INVALID_SOCKET) {
558 return 0;
559 }
560
561 if (bind
562 (connecter, (struct sockaddr FAR *) &connecter_addr,
563 sizeof(connecter_addr)) != SOCKET_ERROR) {
564 closesocket(connecter);
565 return connecter_addr.sin_port;
566 } else if (WSAGetLastError() != WSAEADDRINUSE) {
567 closesocket(connecter);
568 return 0;
569 }
570
571 closesocket(connecter);
572 }
573
574 return 0;
575 #endif /* INET6 */
576 }
577
578 static int PASCAL FAR TTXconnect(SOCKET s,
579 const struct sockaddr FAR * name,
580 int namelen)
581 {
582 GET_VAR();
583
584 #ifdef INET6
585 if (pvar->socket == INVALID_SOCKET) {
586 struct sockaddr_storage ss;
587 int len;
588
589 pvar->socket = s;
590
591 memset(&ss, 0, sizeof(ss));
592 switch (pvar->ts->ProtocolFamily) {
593 case AF_INET:
594 len = sizeof(struct sockaddr_in);
595 ((struct sockaddr_in FAR *) &ss)->sin_family = AF_INET;
596 ((struct sockaddr_in FAR *) &ss)->sin_addr.s_addr = INADDR_ANY;
597 ((struct sockaddr_in FAR *) &ss)->sin_port =
598 htons(find_local_port(pvar));
599 break;
600 case AF_INET6:
601 len = sizeof(struct sockaddr_in6);
602 ((struct sockaddr_in6 FAR *) &ss)->sin6_family = AF_INET6;
603 #if 0 /* symbol "in6addr_any" is not included in wsock32.lib */
604 /* if wsock32.lib will be linked, we can't refer "in6addr_any" */
605 ((struct sockaddr_in6 FAR *) &ss)->sin6_addr = in6addr_any;
606 #eles
607 memset(&((struct sockaddr_in6 FAR *) &ss)->sin6_addr, 0,
608 sizeof(struct in_addr6));
609 #endif /* 0 */
610 ((struct sockaddr_in6 FAR *) &ss)->sin6_port =
611 htons(find_local_port(pvar));
612 break;
613 default:
614 /* NOT REACHED */
615 break;
616 }
617
618 bind(s, (struct sockaddr FAR *) &ss, len);
619 }
620 #else
621 if (pvar->socket == INVALID_SOCKET) {
622 struct sockaddr_in addr;
623
624 pvar->socket = s;
625
626 addr.sin_family = AF_INET;
627 addr.sin_port = htons(find_local_port(pvar));
628 addr.sin_addr.s_addr = INADDR_ANY;
629 memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
630
631 bind(s, (struct sockaddr FAR *) &addr, sizeof(addr));
632 }
633 #endif /* INET6 */
634
635 return (pvar->Pconnect) (s, name, namelen);
636 }
637
638 static int PASCAL FAR TTXWSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
639 long lEvent)
640 {
641 GET_VAR();
642
643 if (s == pvar->socket) {
644 pvar->notification_events = lEvent;
645 pvar->notification_msg = wMsg;
646
647 if (pvar->NotificationWindow == NULL) {
648 pvar->NotificationWindow = hWnd;
649 AUTH_advance_to_next_cred(pvar);
650 }
651 }
652
653 return (pvar->PWSAAsyncSelect) (s, hWnd, wMsg, lEvent);
654 }
655
656 static int PASCAL FAR TTXrecv(SOCKET s, char FAR * buf, int len, int flags)
657 {
658 GET_VAR();
659
660 if (s == pvar->socket) {
661 int ret;
662
663 ssh_heartbeat_lock();
664 ret = PKT_recv(pvar, buf, len);
665 ssh_heartbeat_unlock();
666 return (ret);
667
668 } else {
669 return (pvar->Precv) (s, buf, len, flags);
670 }
671 }
672
673 static int PASCAL FAR TTXsend(SOCKET s, char const FAR * buf, int len,
674 int flags)
675 {
676 GET_VAR();
677
678 if (s == pvar->socket) {
679 ssh_heartbeat_lock();
680 SSH_send(pvar, buf, len);
681 ssh_heartbeat_unlock();
682 return len;
683 } else {
684 return (pvar->Psend) (s, buf, len, flags);
685 }
686 }
687
688 void notify_established_secure_connection(PTInstVar pvar)
689 {
690 #ifdef TERATERM32
691 // LoadIcon �������� LoadImage ���g�����������A
692 // 16x16 ���A�C�R���������I�������������������� (2006.8.9 maya)
693 if (SecureLargeIcon == NULL) {
694 SecureLargeIcon = LoadImage(hInst, MAKEINTRESOURCE(IDI_SECURETT),
695 IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
696 }
697 if (SecureSmallIcon == NULL) {
698 SecureSmallIcon = LoadImage(hInst, MAKEINTRESOURCE(IDI_SECURETT),
699 IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
700 }
701
702 if (SecureLargeIcon != NULL && SecureSmallIcon != NULL) {
703 // �������A�C�R���� WNDCLASS ���Z�b�g�����������������o���������� (2006.8.10 maya)
704 pvar->OldLargeIcon =
705 (HICON) GetClassLong(pvar->NotificationWindow, GCL_HICON);
706 pvar->OldSmallIcon =
707 (HICON) SendMessage(pvar->NotificationWindow, WM_GETICON,
708 ICON_SMALL, 0);
709
710 PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_BIG,
711 (LPARAM) SecureLargeIcon);
712 PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_SMALL,
713 (LPARAM) SecureSmallIcon);
714 }
715 #endif
716
717 notify_verbose_message(pvar, "Entering secure mode",
718 LOG_LEVEL_VERBOSE);
719 }
720
721 void notify_closed_connection(PTInstVar pvar)
722 {
723 SSH_notify_disconnecting(pvar, NULL);
724 AUTH_notify_disconnecting(pvar);
725 HOSTS_notify_disconnecting(pvar);
726
727 PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
728 pvar->socket, MAKELPARAM(FD_CLOSE, 0));
729
730 }
731
732 static void add_err_msg(PTInstVar pvar, char FAR * msg)
733 {
734 if (pvar->err_msg != NULL) {
735 char FAR *buf =
736 (char FAR *) malloc(strlen(pvar->err_msg) + 3 + strlen(msg));
737
738 strcpy(buf, pvar->err_msg);
739 strcat(buf, "\n\n");
740 strcat(buf, msg);
741 free(pvar->err_msg);
742 pvar->err_msg = buf;
743 } else {
744 pvar->err_msg = _strdup(msg);
745 }
746 }
747
748 void notify_nonfatal_error(PTInstVar pvar, char FAR * msg)
749 {
750 if (!pvar->showing_err) {
751 // �������������������m���E�B���h�E�����������A�f�X�N�g�b�v���I�[�i�[������
752 // ���b�Z�[�W�{�b�N�X���o���������B(2006.6.11 yutaka)
753 if (pvar->NotificationWindow == NULL) {
754 MessageBox(NULL, msg, "Tera Term: not fatal error", MB_OK|MB_ICONINFORMATION);
755 msg[0] = '\0';
756
757 } else {
758 PostMessage(pvar->NotificationWindow, WM_COMMAND,
759 ID_SSHASYNCMESSAGEBOX, 0);
760 }
761 }
762 if (msg[0] != 0) {
763 notify_verbose_message(pvar, msg, LOG_LEVEL_ERROR);
764 add_err_msg(pvar, msg);
765 }
766 }
767
768 void notify_fatal_error(PTInstVar pvar, char FAR * msg)
769 {
770 if (msg[0] != 0) {
771 notify_verbose_message(pvar, msg, LOG_LEVEL_FATAL);
772 add_err_msg(pvar, msg);
773 }
774
775 if (!pvar->fatal_error) {
776 pvar->fatal_error = TRUE;
777
778 SSH_notify_disconnecting(pvar, msg);
779 AUTH_notify_disconnecting(pvar);
780 HOSTS_notify_disconnecting(pvar);
781
782 PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
783 pvar->socket, MAKELPARAM(FD_CLOSE,
784 (pvar->PWSAGetLastError) ()));
785 }
786 }
787
788 void notify_verbose_message(PTInstVar pvar, char FAR * msg, int level)
789 {
790 if (level <= pvar->session_settings.LogLevel) {
791 char buf[1024];
792 int file;
793
794 get_teraterm_dir_relative_name(buf, NUM_ELEM(buf), "TTSSH.LOG");
795 file = _open(buf, _O_RDWR | _O_APPEND | _O_CREAT | _O_TEXT,
796 _S_IREAD | _S_IWRITE);
797
798 if (file >= 0) {
799 _write(file, msg, strlen(msg));
800 _write(file, "\n", 1);
801 _close(file);
802 }
803 }
804 }
805
806 static void PASCAL FAR TTXOpenTCP(TTXSockHooks FAR * hooks)
807 {
808 GET_VAR();
809
810 if (pvar->settings.Enabled) {
811 char buf[1024] = "\n---------------------------------------------------------------------\nInitiating SSH session at ";
812 struct tm FAR *newtime;
813 time_t long_time;
814
815 pvar->session_settings = pvar->settings;
816
817 time(&long_time);
818 newtime = localtime(&long_time);
819 strcat(buf, asctime(newtime));
820 buf[strlen(buf) - 1] = 0;
821 notify_verbose_message(pvar, buf, LOG_LEVEL_VERBOSE);
822
823 FWDUI_load_settings(pvar);
824
825 pvar->cv->TelAutoDetect = FALSE;
826 /* This next line should not be needed because Teraterm's
827 CommLib should find ts->Telnet == 0 ... but we'll do this
828 just to be on the safe side. */
829 pvar->cv->TelFlag = FALSE;
830
831 pvar->Precv = *hooks->Precv;
832 pvar->Psend = *hooks->Psend;
833 pvar->PWSAAsyncSelect = *hooks->PWSAAsyncSelect;
834 pvar->Pconnect = *hooks->Pconnect;
835 pvar->PWSAGetLastError = *hooks->PWSAGetLastError;
836
837 *hooks->Precv = TTXrecv;
838 *hooks->Psend = TTXsend;
839 *hooks->PWSAAsyncSelect = TTXWSAAsyncSelect;
840 *hooks->Pconnect = TTXconnect;
841
842 SSH_open(pvar);
843 HOSTS_open(pvar);
844 FWDUI_open(pvar);
845
846 // ������ myproposal �����f���������A�������O�����������B (2006.6.26 maya)
847 SSH2_update_cipher_myproposal(pvar);
848 SSH2_update_compression_myproposal(pvar);
849 }
850 }
851
852 static void PASCAL FAR TTXCloseTCP(TTXSockHooks FAR * hooks)
853 {
854 GET_VAR();
855
856 if (pvar->session_settings.Enabled) {
857 pvar->socket = INVALID_SOCKET;
858
859 notify_verbose_message(pvar, "Terminating SSH session...",
860 LOG_LEVEL_VERBOSE);
861
862 *hooks->Precv = pvar->Precv;
863 *hooks->Psend = pvar->Psend;
864 *hooks->PWSAAsyncSelect = pvar->PWSAAsyncSelect;
865 *hooks->Pconnect = pvar->Pconnect;
866 }
867
868 uninit_TTSSH(pvar);
869 init_TTSSH(pvar);
870 }
871
872 static void enable_dlg_items(HWND dlg, int from, int to, BOOL enabled)
873 {
874 for (; from <= to; from++) {
875 EnableWindow(GetDlgItem(dlg, from), enabled);
876 }
877 }
878
879 static BOOL CALLBACK TTXHostDlg(HWND dlg, UINT msg, WPARAM wParam,
880 LPARAM lParam)
881 {
882 static char *ssh_version[] = {"SSH1", "SSH2", NULL};
883 PGetHNRec GetHNRec;
884 char EntName[7];
885 char TempHost[HostNameMaxLength + 1];
886 WORD i, j, w;
887 BOOL Ok;
888
889 GET_VAR();
890
891 switch (msg) {
892 case WM_INITDIALOG:
893 GetHNRec = (PGetHNRec) lParam;
894 SetWindowLong(dlg, DWL_USER, lParam);
895
896 // �z�X�g�q�X�g�����`�F�b�N�{�b�N�X������ (2005.10.21 yutaka)
897 if (pvar->ts->HistoryList > 0) {
898 SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_SETCHECK, BST_CHECKED, 0);
899 } else {
900 SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_SETCHECK, BST_UNCHECKED, 0);
901 }
902
903 if (GetHNRec->PortType == IdFile)
904 GetHNRec->PortType = IdTCPIP;
905 CheckRadioButton(dlg, IDC_HOSTTCPIP, IDC_HOSTSERIAL,
906 IDC_HOSTTCPIP + GetHNRec->PortType - 1);
907
908 strcpy(EntName, "Host");
909
910 i = 1;
911 do {
912 sprintf(&EntName[4], "%d", i);
913 GetPrivateProfileString("Hosts", EntName, "",
914 TempHost, sizeof(TempHost),
915 GetHNRec->SetupFN);
916 if (strlen(TempHost) > 0)
917 SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_ADDSTRING,
918 0, (LPARAM) TempHost);
919 i++;
920 } while ((i <= 99) && (strlen(TempHost) > 0));
921
922 SendDlgItemMessage(dlg, IDC_HOSTNAME, EM_LIMITTEXT,
923 HostNameMaxLength - 1, 0);
924
925 SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_SETCURSEL, 0, 0);
926
927 CheckRadioButton(dlg, IDC_HOSTTELNET, IDC_HOSTOTHER,
928 pvar->settings.Enabled ? IDC_HOSTSSH : GetHNRec->
929 Telnet ? IDC_HOSTTELNET : IDC_HOSTOTHER);
930 SendDlgItemMessage(dlg, IDC_HOSTTCPPORT, EM_LIMITTEXT, 5, 0);
931 SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TCPPort, FALSE);
932 #ifdef INET6
933 for (i = 0; ProtocolFamilyList[i]; ++i) {
934 SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_ADDSTRING,
935 0, (LPARAM) ProtocolFamilyList[i]);
936 }
937 SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, EM_LIMITTEXT,
938 ProtocolFamilyMaxLength - 1, 0);
939 SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_SETCURSEL, 0, 0);
940 #endif /* INET6 */
941
942 /////// SSH version
943 for (i = 0; ssh_version[i]; ++i) {
944 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_ADDSTRING,
945 0, (LPARAM) ssh_version[i]);
946 }
947 SendDlgItemMessage(dlg, IDC_SSH_VERSION, EM_LIMITTEXT,
948 NUM_ELEM(ssh_version) - 1, 0);
949
950 if (pvar->settings.ssh_protocol_version == 1) {
951 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 0, 0); // SSH1
952 } else {
953 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 1, 0); // SSH2
954 }
955
956 if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
957 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE); // enabled
958 } else {
959 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
960 }
961 /////// SSH version
962
963
964 j = 0;
965 w = 1;
966 strcpy(EntName, "COM");
967 for (i = 1; i <= GetHNRec->MaxComPort; i++) {
968 sprintf(&EntName[3], "%d", i);
969 SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_ADDSTRING,
970 0, (LPARAM) EntName);
971 j++;
972 if (GetHNRec->ComPort == i)
973 w = j;
974 }
975 if (j > 0)
976 SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_SETCURSEL, w - 1, 0);
977 else /* All com ports are already used */
978 GetHNRec->PortType = IdTCPIP;
979
980 if (GetHNRec->PortType == IdTCPIP) {
981 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
982
983 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
984 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, TRUE);
985 }
986 #ifdef INET6
987 else {
988 enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
989 FALSE);
990 enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
991 IDC_HOSTTCPPROTOCOL, FALSE);
992
993 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
994 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, FALSE); // disabled (2004.11.23 yutaka)
995 }
996 #else
997 else
998 enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
999 FALSE);
1000 #endif /* INET6 */
1001
1002 // Host dialog���t�H�[�J�X�������� (2004.10.2 yutaka)
1003 if (GetHNRec->PortType == IdTCPIP) {
1004 HWND hwnd = GetDlgItem(dlg, IDC_HOSTNAME);
1005 SetFocus(hwnd);
1006 } else {
1007 HWND hwnd = GetDlgItem(dlg, IDC_HOSTCOM);
1008 SetFocus(hwnd);
1009 }
1010
1011 // SetFocus()���t�H�[�J�X���������������AFALSE�������K�v�������B
1012 // TRUE���������ATABSTOP�������������������R���g���[�����I�������B
1013 // (2004.11.23 yutaka)
1014 return FALSE;
1015 //return TRUE;
1016
1017 case WM_COMMAND:
1018 switch (LOWORD(wParam)) {
1019 case IDOK:
1020 GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
1021 if (GetHNRec != NULL) {
1022 if (IsDlgButtonChecked(dlg, IDC_HOSTTCPIP)) {
1023 #ifdef INET6
1024 char afstr[BUFSIZ];
1025 #endif /* INET6 */
1026 i = GetDlgItemInt(dlg, IDC_HOSTTCPPORT, &Ok, FALSE);
1027 if (Ok) {
1028 GetHNRec->TCPPort = i;
1029 } else {
1030 MessageBox(dlg, "Teraterm",
1031 "The TCP port must be a number.",
1032 MB_OK | MB_ICONEXCLAMATION);
1033 return TRUE;
1034 }
1035 #ifdef INET6
1036 #define getaf(str) \
1037 ((strcmp((str), "IPv6") == 0) ? AF_INET6 : \
1038 ((strcmp((str), "IPv4") == 0) ? AF_INET : AF_UNSPEC))
1039 memset(afstr, 0, sizeof(afstr));
1040 GetDlgItemText(dlg, IDC_HOSTTCPPROTOCOL, afstr,
1041 sizeof(afstr));
1042 GetHNRec->ProtocolFamily = getaf(afstr);
1043 #endif /* INET6 */
1044 GetHNRec->PortType = IdTCPIP;
1045 GetDlgItemText(dlg, IDC_HOSTNAME, GetHNRec->HostName,
1046 HostNameMaxLength);
1047 GetHNRec->Telnet = FALSE;
1048 pvar->hostdlg_activated = TRUE;
1049 pvar->hostdlg_Enabled = FALSE;
1050 if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1051 GetHNRec->Telnet = TRUE;
1052 } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1053 pvar->hostdlg_Enabled = TRUE;
1054
1055 // check SSH protocol version
1056 memset(afstr, 0, sizeof(afstr));
1057 GetDlgItemText(dlg, IDC_SSH_VERSION, afstr, sizeof(afstr));
1058 if (_stricmp(afstr, "SSH1") == 0) {
1059 pvar->settings.ssh_protocol_version = 1;
1060 } else {
1061 pvar->settings.ssh_protocol_version = 2;
1062 }
1063 }
1064
1065 // host history check button
1066 if (SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_GETCHECK, 0, 0) == BST_CHECKED) {
1067 pvar->ts->HistoryList = 1;
1068 } else {
1069 pvar->ts->HistoryList = 0;
1070 }
1071
1072 } else {
1073 GetHNRec->PortType = IdSerial;
1074 GetHNRec->HostName[0] = 0;
1075 memset(EntName, 0, sizeof(EntName));
1076 GetDlgItemText(dlg, IDC_HOSTCOM, EntName,
1077 sizeof(EntName) - 1);
1078 GetHNRec->ComPort = (BYTE) (EntName[3]) - 0x30;
1079 if (strlen(EntName) > 4)
1080 GetHNRec->ComPort =
1081 GetHNRec->ComPort * 10 + (BYTE) (EntName[4]) -
1082 0x30;
1083 }
1084 }
1085 EndDialog(dlg, 1);
1086 return TRUE;
1087
1088 case IDCANCEL:
1089 EndDialog(dlg, 0);
1090 return TRUE;
1091
1092 case IDC_HOSTTCPIP:
1093 enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1094 TRUE);
1095 #ifdef INET6
1096 enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1097 IDC_HOSTTCPPROTOCOL, TRUE);
1098 #endif /* INET6 */
1099 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
1100
1101 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, TRUE); // disabled (2004.11.23 yutaka)
1102 if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1103 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
1104 } else {
1105 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1106 }
1107
1108 enable_dlg_items(dlg, IDC_HISTORY, IDC_HISTORY, TRUE); // disabled
1109
1110 return TRUE;
1111
1112 case IDC_HOSTSERIAL:
1113 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, TRUE);
1114 enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1115 FALSE);
1116 #ifdef INET6
1117 enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1118 IDC_HOSTTCPPROTOCOL, FALSE);
1119 #endif /* INET6 */
1120 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1121 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, FALSE); // disabled (2004.11.23 yutaka)
1122
1123 enable_dlg_items(dlg, IDC_HISTORY, IDC_HISTORY, FALSE); // disabled
1124
1125 return TRUE;
1126
1127 case IDC_HOSTSSH:
1128 enable_dlg_items(dlg, IDC_SSH_VERSION,
1129 IDC_SSH_VERSION, TRUE);
1130 goto hostssh_enabled;
1131
1132 case IDC_HOSTTELNET:
1133 case IDC_HOSTOTHER:
1134 enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1135 hostssh_enabled:
1136
1137 GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
1138
1139 if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1140 if (GetHNRec != NULL)
1141 SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TelPort,
1142 FALSE);
1143 } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1144 SetDlgItemInt(dlg, IDC_HOSTTCPPORT, 22, FALSE);
1145 }
1146 return TRUE;
1147
1148 case IDC_HOSTHELP:
1149 PostMessage(GetParent(dlg), WM_USER_DLGHELP2, 0, 0);
1150 }
1151 }
1152 return FALSE;
1153 }
1154
1155 static BOOL FAR PASCAL TTXGetHostName(HWND parent, PGetHNRec rec)
1156 {
1157 return (BOOL) DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_HOSTDLG),
1158 parent, TTXHostDlg, (LONG) rec);
1159 }
1160
1161 static void PASCAL FAR TTXGetUIHooks(TTXUIHooks FAR * hooks)
1162 {
1163 GET_VAR();
1164
1165 *hooks->GetHostName = TTXGetHostName;
1166 }
1167
1168 static void FAR PASCAL TTXReadINIFile(PCHAR fileName, PTTSet ts)
1169 {
1170 GET_VAR();
1171
1172 (pvar->ReadIniFile) (fileName, ts);
1173 read_ssh_options(pvar, fileName);
1174 pvar->settings = *pvar->ts_SSH;
1175 notify_verbose_message(pvar, "Reading INI file", LOG_LEVEL_VERBOSE);
1176 FWDUI_load_settings(pvar);
1177 }
1178
1179 static void FAR PASCAL TTXWriteINIFile(PCHAR fileName, PTTSet ts)
1180 {
1181 GET_VAR();
1182
1183 (pvar->WriteIniFile) (fileName, ts);
1184 *pvar->ts_SSH = pvar->settings;
1185 clear_local_settings(pvar);
1186 notify_verbose_message(pvar, "Writing INI file", LOG_LEVEL_VERBOSE);
1187 write_ssh_options(pvar, fileName, pvar->ts_SSH, TRUE);
1188 }
1189
1190 static void read_ssh_options_from_user_file(PTInstVar pvar,
1191 char FAR * user_file_name)
1192 {
1193 if (user_file_name[0] == '.') {
1194 read_ssh_options(pvar, user_file_name);
1195 } else {
1196 char buf[1024];
1197
1198 get_teraterm_dir_relative_name(buf, sizeof(buf), user_file_name);
1199 read_ssh_options(pvar, buf);
1200 }
1201
1202 pvar->settings = *pvar->ts_SSH;
1203 FWDUI_load_settings(pvar);
1204 }
1205
1206
1207 // @���u�����N���u�������B (2005.1.26 yutaka)
1208 static void replace_to_blank(char *src, char *dst, int dst_len)
1209 {
1210 int len, i;
1211
1212 len = strlen(src);
1213 if (dst_len < len) // buffer overflow check
1214 return;
1215
1216 for (i = 0 ; i < len ; i++) {
1217 if (src[i] == '@') { // @ ���o��������
1218 if (i < len - 1 && src[i + 1] == '@') { // �������� @ �����A�b�g�}�[�N���F������
1219 *dst++ = '@';
1220 i++;
1221 } else {
1222 *dst++ = ' '; // �������u��������
1223 }
1224 } else {
1225 *dst++ = src[i];
1226 }
1227 }
1228 *dst = '\0';
1229 }
1230
1231 // copy from ttermpro/ttset.c (2006.8.21 maya)
1232 void Dequote(PCHAR Source, PCHAR Dest)
1233 {
1234 int i, j;
1235 char q, c;
1236
1237 Dest[0] = 0;
1238 if (Source[0]==0) return;
1239 i = 0;
1240 /* quoting char */
1241 q = Source[i];
1242 /* only '"' is used as quoting char */
1243 if (q!='"')
1244 q = 0;
1245 else
1246 i++;
1247
1248 c = Source[i];
1249 i++;
1250 j = 0;
1251 while ((c!=0) && (c!=q))
1252 {
1253 Dest[j] = c;
1254 j++;
1255 c = Source[i];
1256 i++;
1257 }
1258
1259 Dest[j] = 0;
1260 }
1261
1262 /* returns 1 if the option text must be deleted */
1263 static int parse_option(PTInstVar pvar, char FAR * option)
1264 {
1265 if ((option[0] == '-' || option[0] == '/')) {
1266 if (MATCH_STR(option + 1, "ssh") == 0) {
1267 if (option[4] == 0) {
1268 pvar->settings.Enabled = 1;
1269 } else if (MATCH_STR(option + 4, "-L") == 0
1270 || MATCH_STR(option + 4, "-R") == 0
1271 || _stricmp(option + 4, "-X") == 0) {
1272 if (pvar->settings.DefaultForwarding[0] == 0) {
1273 strcpy(pvar->settings.DefaultForwarding, option + 5);
1274 } else {
1275 strcat(pvar->settings.DefaultForwarding, ";");
1276 strcat(pvar->settings.DefaultForwarding, option + 5);
1277 }
1278 } else if (MATCH_STR(option + 4, "-f=") == 0) {
1279 // �t�@�C������ `"' ���������������������o�� (2006.8.21 maya)
1280 char* buf = (char *)calloc(strlen(option), sizeof(char));
1281 Dequote(option + 7, buf);
1282 read_ssh_options_from_user_file(pvar, buf);
1283 free(buf);
1284 } else if (MATCH_STR(option + 4, "-v") == 0) {
1285 pvar->settings.LogLevel = LOG_LEVEL_VERBOSE;
1286 } else if (_stricmp(option + 4, "-autologin") == 0
1287 || _stricmp(option + 4, "-autologon") == 0) {
1288 pvar->settings.TryDefaultAuth = TRUE;
1289
1290 } else if (MATCH_STR(option + 4, "-consume=") == 0) {
1291 // �t�@�C������ `"' ���������������������o�� (2006.8.21 maya)
1292 char* buf = (char *)calloc(strlen(option), sizeof(char));
1293 Dequote(option + 13, buf);
1294 read_ssh_options_from_user_file(pvar, buf);
1295 free(buf);
1296 DeleteFile(option + 13);
1297
1298 // /ssh1 �� /ssh2 �I�v�V�������V�K���� (2006.9.16 maya)
1299 } else if (MATCH_STR(option + 4, "1") == 0) {
1300 pvar->settings.ssh_protocol_version = 1;
1301 } else if (MATCH_STR(option + 4, "2") == 0) {
1302 pvar->settings.ssh_protocol_version = 2;
1303
1304 } else {
1305 char buf[1024];
1306
1307 _snprintf(buf, sizeof(buf),
1308 "Unrecognized command-line option: %s", option);
1309 buf[sizeof(buf) - 1] = 0;
1310
1311 MessageBox(NULL, buf, "TTSSH", MB_OK | MB_ICONEXCLAMATION);
1312 }
1313
1314 return 1;
1315 } else if (MATCH_STR(option + 1, "t=") == 0) {
1316 if (strcmp(option + 3, "2") == 0) {
1317 pvar->settings.Enabled = 1;
1318 return 1;
1319 } else {
1320 pvar->settings.Enabled = 0;
1321 }
1322 } else if (MATCH_STR(option + 1, "f=") == 0) {
1323 // �t�@�C������ `"' ���������������������o�� (2006.8.21 maya)
1324 char* buf = (char *)calloc(strlen(option), sizeof(char));
1325 Dequote(option + 3, buf);
1326 read_ssh_options_from_user_file(pvar, buf);
1327 free(buf);
1328
1329 // /1 ������ /2 �I�v�V�������V�K���� (2004.10.3 yutaka)
1330 } else if (MATCH_STR(option + 1, "1") == 0) {
1331 // command line: /ssh /1 is SSH1 only
1332 pvar->settings.ssh_protocol_version = 1;
1333
1334 } else if (MATCH_STR(option + 1, "2") == 0) {
1335 // command line: /ssh /2 is SSH2 & SSH1
1336 pvar->settings.ssh_protocol_version = 2;
1337
1338 } else if (MATCH_STR(option + 1, "nossh") == 0) {
1339 // '/nossh' �I�v�V�����������B
1340 // TERATERM.INI ��SSH���L�������������������A������Cygterm���N��������������
1341 // �����������������B(2004.10.11 yutaka)
1342 pvar->settings.Enabled = 0;
1343
1344 } else if (MATCH_STR(option + 1, "telnet") == 0) {
1345 // '/telnet' ���w�������������������� '/nossh' ��������
1346 // SSH������������ (2006.9.16 maya)
1347 pvar->settings.Enabled = 0;
1348
1349 } else if (MATCH_STR(option + 1, "auth") == 0) {
1350 // SSH2�������O�C���I�v�V����������
1351 //
1352 // SYNOPSIS: /ssh /auth=passowrd /user=���[�U�� /passwd=�p�X���[�h
1353 // /ssh /auth=publickey /user=���[�U�� /passwd=�p�X���[�h /keyfile=�p�X
1354 // EXAMPLE: /ssh /auth=password /user=nike /passwd=a@bc
1355 // /ssh /auth=publickey /user=foo /passwd=bar /keyfile=d:\tmp\id_rsa
1356 // NOTICE: �p�X���[�h���p�X�������������������A�u�����N���������� @ ���g�������B
1357 //
1358 // (2004.11.30 yutaka)
1359 // (2005.1.26 yutaka) ���������B���J���F���T�|�[�g�B
1360 //
1361 pvar->ssh2_autologin = 1; // for SSH2 (2004.11.30 yutaka)
1362
1363 if (MATCH_STR(option + 5, "=password") == 0) { // �p�X���[�h/keyboard-interactive�F��
1364 //pvar->auth_state.cur_cred.method = SSH_AUTH_PASSWORD;
1365 pvar->ssh2_authmethod = SSH_AUTH_PASSWORD;
1366
1367 } else if (MATCH_STR(option + 5, "=publickey") == 0) { // ���J���F��
1368 //pvar->auth_state.cur_cred.method = SSH_AUTH_RSA;
1369 pvar->ssh2_authmethod = SSH_AUTH_RSA;
1370
1371 } else {
1372 // TODO:
1373
1374 }
1375
1376 } else if (MATCH_STR(option + 1, "user=") == 0) {
1377 replace_to_blank(option + 6, pvar->ssh2_username, sizeof(pvar->ssh2_username));
1378 //_snprintf(pvar->ssh2_username, sizeof(pvar->ssh2_username), "%s", option + 6);
1379
1380 } else if (MATCH_STR(option + 1, "passwd=") == 0) {
1381 replace_to_blank(option + 8, pvar->ssh2_password, sizeof(pvar->ssh2_password));
1382 //_snprintf(pvar->ssh2_password, sizeof(pvar->ssh2_password), "%s", option + 8);
1383
1384 } else if (MATCH_STR(option + 1, "keyfile=") == 0) {
1385 replace_to_blank(option + 9, pvar->ssh2_keyfile, sizeof(pvar->ssh2_keyfile));
1386
1387 } else if (MATCH_STR(option + 1, "ask4passwd") == 0) {
1388 // �p�X���[�h������ (2006.9.18 maya)
1389 pvar->ask4passwd = 1;
1390
1391 }
1392
1393 // �p�X���[�h�������������������O�C��������������
1394 // /auth ���F�����\�b�h���w�������������p������ (2006.9.18 maya)
1395 if (pvar->ask4passwd == 1) {
1396 pvar->ssh2_autologin = 0;
1397 }
1398
1399 }
1400
1401 return 0;
1402 }
1403
1404 static void FAR PASCAL TTXParseParam(PCHAR param, PTTSet ts,
1405 PCHAR DDETopic)
1406 {
1407 int i;
1408 BOOL inParam = FALSE;
1409 BOOL inQuotes = FALSE;
1410 PCHAR option = NULL;
1411 GET_VAR();
1412
1413 if (pvar->hostdlg_activated) {
1414 pvar->settings.Enabled = pvar->hostdlg_Enabled;
1415 }
1416
1417 for (i = 0; param[i] != 0; i++) {
1418 if (inQuotes ? param[i] ==
1419 '"' : (param[i] == ' ' || param[i] == '\t')) {
1420 if (option != NULL) {
1421 char ch = param[i];
1422
1423 param[i] = 0;
1424 if (parse_option
1425 (pvar, *option == '"' ? option + 1 : option)) {
1426 memset(option, ' ', i + 1 - (option - param));
1427 } else {
1428 param[i] = ch;
1429 }
1430 option = NULL;
1431 }
1432 inParam = FALSE;
1433 inQuotes = FALSE;
1434 } else if (!inParam) {
1435 if (param[i] == '"') {
1436 inQuotes = TRUE;
1437 inParam = TRUE;
1438 option = param + i;
1439 } else if (param[i] != ' ' && param[i] != '\t') {
1440 inParam = TRUE;
1441 option = param + i;
1442 }
1443 }
1444 }
1445
1446 if (option != NULL) {
1447 if (parse_option(pvar, option)) {
1448 memset(option, ' ', i - (option - param));
1449 }
1450 }
1451
1452 FWDUI_load_settings(pvar);
1453
1454 (pvar->ParseParam) (param, ts, DDETopic);
1455
1456 }
1457
1458 static void PASCAL FAR TTXGetSetupHooks(TTXSetupHooks FAR * hooks)
1459 {
1460 GET_VAR();
1461
1462 pvar->ReadIniFile = *hooks->ReadIniFile;
1463 pvar->WriteIniFile = *hooks->WriteIniFile;
1464 pvar->ParseParam = *hooks->ParseParam;
1465
1466 *hooks->ReadIniFile = TTXReadINIFile;
1467 *hooks->WriteIniFile = TTXWriteINIFile;
1468 *hooks->ParseParam = TTXParseParam;
1469 }
1470
1471 static void PASCAL FAR TTXSetWinSize(int rows, int cols)
1472 {
1473 GET_VAR();
1474
1475 SSH_notify_win_size(pvar, cols, rows);
1476 }
1477
1478 static void insertMenuBeforeItem(HMENU menu, WORD beforeItemID, WORD flags,
1479 WORD newItemID, char FAR * text)
1480 {
1481 int i, j;
1482
1483 for (i = GetMenuItemCount(menu) - 1; i >= 0; i--) {
1484 HMENU submenu = GetSubMenu(menu, i);
1485
1486 for (j = GetMenuItemCount(submenu) - 1; j >= 0; j--) {
1487 if (GetMenuItemID(submenu, j) == beforeItemID) {
1488 InsertMenu(submenu, j, MF_BYPOSITION | flags, newItemID,
1489 text);
1490 return;
1491 }
1492 }
1493 }
1494 }
1495
1496 static void PASCAL FAR TTXModifyMenu(HMENU menu)
1497 {
1498 GET_VAR();
1499
1500 /* inserts before ID_HELP_ABOUT */
1501 insertMenuBeforeItem(menu, 50990, MF_ENABLED, ID_ABOUTMENU,
1502 "About &TTSSH...");
1503
1504 /* inserts before ID_SETUP_TCPIP */
1505 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHSETUPMENU,
1506 "SS&H...");
1507 /* inserts before ID_SETUP_TCPIP */
1508 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHAUTHSETUPMENU,
1509 "SSH &Authentication...");
1510 /* inserts before ID_SETUP_TCPIP */
1511 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHFWDSETUPMENU,
1512 "SSH F&orwarding...");
1513
1514 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHKEYGENMENU,
1515 "SSH KeyGenerator...");
1516 }
1517
1518 static void append_about_text(HWND dlg, char FAR * prefix, char FAR * msg)
1519 {
1520 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1521 (LPARAM) prefix);
1522 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0, (LPARAM) msg);
1523 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1524 (LPARAM) (char FAR *) "\r\n");
1525 }
1526
1527 // ���s�t�@�C�������o�[�W�������������� (2005.2.28 yutaka)
1528 void get_file_version(char *exefile, int *major, int *minor, int *release, int *build)
1529 {
1530 typedef struct {
1531 WORD wLanguage;
1532 WORD wCodePage;
1533 } LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
1534 LPLANGANDCODEPAGE lplgcode;
1535 UINT unLen;
1536 DWORD size;
1537 char *buf = NULL;
1538 BOOL ret;
1539 int i;
1540 char fmt[80];
1541 char *pbuf;
1542
1543 size = GetFileVersionInfoSize(exefile, NULL);
1544 if (size == 0) {
1545 goto error;
1546 }
1547 buf = malloc(size);
1548 ZeroMemory(buf, size);
1549
1550 if (GetFileVersionInfo(exefile, 0, size, buf) == FALSE) {
1551 goto error;
1552 }
1553
1554 ret = VerQueryValue(buf,
1555 "\\VarFileInfo\\Translation",
1556 (LPVOID *)&lplgcode, &unLen);
1557 if (ret == FALSE)
1558 goto error;
1559
1560 for (i = 0 ; i < (int)(unLen / sizeof(LANGANDCODEPAGE)) ; i++) {
1561 _snprintf(fmt, sizeof(fmt), "\\StringFileInfo\\%04x%04x\\FileVersion",
1562 lplgcode[i].wLanguage, lplgcode[i].wCodePage);
1563 VerQueryValue(buf, fmt, &pbuf, &unLen);
1564 if (unLen > 0) { // get success
1565 int n, a, b, c, d;
1566
1567 n = sscanf(pbuf, "%d, %d, %d, %d", &a, &b, &c, &d);
1568 if (n == 4) { // convert success
1569 *major = a;
1570 *minor = b;
1571 *release = c;
1572 *build = d;
1573 break;
1574 }
1575 }
1576 }
1577
1578 free(buf);
1579 return;
1580
1581 error:
1582 free(buf);
1583 *major = *minor = *release = *build = 0;
1584 }
1585
1586 static void init_about_dlg(PTInstVar pvar, HWND dlg)
1587 {
1588 char buf[1024];
1589 int a, b, c, d;
1590
1591 // TTSSH���o�[�W�������������� (2005.2.28 yutaka)
1592 get_file_version("ttxssh.dll", &a, &b, &c, &d);
1593 _snprintf(buf, sizeof(buf), "TTSSH\r\nTeraterm Secure Shell extension, %d.%d", a, b);
1594 SendMessage(GetDlgItem(dlg, IDC_TTSSH_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1595
1596 // OpenSSL���o�[�W�������������� (2005.1.24 yutaka)
1597 // ���������� (2005.5.11 yutaka)
1598 #ifdef OPENSSL_VERSION_TEXT
1599 SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)OPENSSL_VERSION_TEXT);
1600 #else
1601 SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)"Unknown");
1602 #endif
1603
1604 // zlib���o�[�W�������������� (2005.5.11 yutaka)
1605 #ifdef ZLIB_VERSION
1606 _snprintf(buf, sizeof(buf), "ZLib %s", ZLIB_VERSION);
1607 #else
1608 _snprintf(buf, sizeof(buf), "ZLib Unknown");
1609 #endif
1610 SendMessage(GetDlgItem(dlg, IDC_ZLIB_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1611
1612
1613 // TTSSH�_�C�A���O���\������SSH������������ (2004.10.30 yutaka)
1614 if (pvar->socket != INVALID_SOCKET) {
1615 if (SSHv1(pvar)) {
1616 SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1617 append_about_text(dlg, "Server ID: ", buf);
1618 SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1619 append_about_text(dlg, "Using protocol: ", buf);
1620 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1621 append_about_text(dlg, "Encryption: ", buf);
1622 CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1623 append_about_text(dlg, "Server keys: ", buf);
1624 AUTH_get_auth_info(pvar, buf, sizeof(buf));
1625 append_about_text(dlg, "Authentication: ", buf);
1626 SSH_get_compression_info(pvar, buf, sizeof(buf));
1627 append_about_text(dlg, "Compression: ", buf);
1628
1629 } else { // SSH2
1630 SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1631 append_about_text(dlg, "Server ID: ", buf);
1632
1633 append_about_text(dlg, "Client ID: ", pvar->client_version_string);
1634
1635 SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1636 append_about_text(dlg, "Using protocol: ", buf);
1637
1638 if (pvar->kex_type == KEX_DH_GRP1_SHA1) {
1639 strcpy(buf, KEX_DH1);
1640 } else if (pvar->kex_type == KEX_DH_GRP14_SHA1) {
1641 strcpy(buf, KEX_DH14);
1642 } else {
1643 strcpy(buf, KEX_DHGEX);
1644 }
1645 append_about_text(dlg, "KEX: ", buf);
1646
1647 if (pvar->hostkey_type == KEY_DSA) {
1648 strcpy(buf, "ssh-dss");
1649 } else {
1650 strcpy(buf, "ssh-rsa");
1651 }
1652 append_about_text(dlg, "Host Key: ", buf);
1653
1654 // add HMAC algorithm (2004.12.17 yutaka)
1655 buf[0] = '\0';
1656 if (pvar->ctos_hmac == HMAC_SHA1) {
1657 strcat(buf, "hmac-sha1");
1658 } else if (pvar->ctos_hmac == HMAC_MD5) {
1659 strcat(buf, "hmac-md5");
1660 }
1661 strcat(buf, " to server, ");
1662 if (pvar->stoc_hmac == HMAC_SHA1) {
1663 strcat(buf, "hmac-sha1");
1664 } else if (pvar->stoc_hmac == HMAC_MD5) {
1665 strcat(buf, "hmac-md5");
1666 }
1667 strcat(buf, " from server");
1668 append_about_text(dlg, "HMAC: ", buf);
1669
1670 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1671 append_about_text(dlg, "Encryption: ", buf);
1672 CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1673 append_about_text(dlg, "Server keys: ", buf);
1674 AUTH_get_auth_info(pvar, buf, sizeof(buf));
1675 append_about_text(dlg, "Authentication: ", buf);
1676
1677 SSH_get_compression_info(pvar, buf, sizeof(buf));
1678 if (pvar->ctos_compression == COMP_DELAYED) { // �x���p�P�b�g���k������ (2006.6.23 yutaka)
1679 append_about_text(dlg, "Delayed Compression: ", buf);
1680 } else {
1681 append_about_text(dlg, "Compression: ", buf);
1682 }
1683
1684 }
1685 }
1686 }
1687
1688 static BOOL CALLBACK TTXAboutDlg(HWND dlg, UINT msg, WPARAM wParam,
1689 LPARAM lParam)
1690 {
1691 switch (msg) {
1692 case WM_INITDIALOG:
1693 init_about_dlg((PTInstVar) lParam, dlg);
1694 return TRUE;
1695 case WM_COMMAND:
1696 switch (LOWORD(wParam)) {
1697 case IDOK:
1698 EndDialog(dlg, 1);
1699 return TRUE;
1700 case IDCANCEL: /* there isn't a cancel button, but other Windows
1701 UI things can send this message */
1702 EndDialog(dlg, 0);
1703 return TRUE;
1704 }
1705 break;
1706 }
1707
1708 return FALSE;
1709 }
1710
1711 static char FAR *get_cipher_name(int cipher)
1712 {
1713 switch (cipher) {
1714 case SSH_CIPHER_NONE:
1715 return "<ciphers below this line are disabled>";
1716 case SSH_CIPHER_RC4:
1717 return "RC4";
1718 case SSH_CIPHER_3DES:
1719 return "3DES";
1720 case SSH_CIPHER_DES:
1721 return "DES";
1722 case SSH_CIPHER_IDEA:
1723 return "IDEA";
1724 case SSH_CIPHER_TSS:
1725 return "TSS";
1726 case SSH_CIPHER_BLOWFISH:
1727 return "Blowfish";
1728
1729 // for SSH2(yutaka)
1730 case SSH_CIPHER_AES128:
1731 return "AES128(SSH2)";
1732 case SSH_CIPHER_3DES_CBC:
1733 return "3DES-CBC(SSH2)";
1734
1735 default:
1736 return NULL;
1737 }
1738 }
1739
1740 static void set_move_button_status(HWND dlg)
1741 {
1742 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1743 int curPos = (int) SendMessage(cipherControl, LB_GETCURSEL, 0, 0);
1744 int maxPos = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0) - 1;
1745
1746 EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERUP), curPos > 0
1747 && curPos <= maxPos);
1748 EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERDOWN), curPos >= 0
1749 && curPos < maxPos);
1750 }
1751
1752 static void init_setup_dlg(PTInstVar pvar, HWND dlg)
1753 {
1754 HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1755 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1756 int i;
1757 int ch;
1758
1759 SendMessage(compressionControl, TBM_SETRANGE, TRUE, MAKELONG(0, 9));
1760 SendMessage(compressionControl, TBM_SETPOS, TRUE,
1761 pvar->settings.CompressionLevel);
1762
1763 normalize_cipher_order(pvar->settings.CipherOrder);
1764
1765 for (i = 0; pvar->settings.CipherOrder[i] != 0; i++) {
1766 int cipher = pvar->settings.CipherOrder[i] - '0';
1767 char FAR *name = get_cipher_name(cipher);
1768
1769 if (name != NULL) {
1770 SendMessage(cipherControl, LB_ADDSTRING, 0, (LPARAM) name);
1771 }
1772 }
1773
1774 SendMessage(cipherControl, LB_SETCURSEL, 0, 0);
1775 set_move_button_status(dlg);
1776
1777 for (i = 0; (ch = pvar->settings.KnownHostsFiles[i]) != 0 && ch != ';';
1778 i++) {
1779 }
1780 if (ch != 0) {
1781 pvar->settings.KnownHostsFiles[i] = 0;
1782 SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1783 pvar->settings.KnownHostsFiles);
1784 pvar->settings.KnownHostsFiles[i] = ch;
1785 SetDlgItemText(dlg, IDC_READONLYFILENAME,
1786 pvar->settings.KnownHostsFiles + i + 1);
1787 } else {
1788 SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1789 pvar->settings.KnownHostsFiles);
1790 }
1791
1792 // SSH2 HeartBeat(keep-alive)������ (2005.2.22 yutaka)
1793 {
1794 char buf[10];
1795 _snprintf(buf, sizeof(buf), "%d", pvar->settings.ssh_heartbeat_overtime);
1796 SetDlgItemText(dlg, IDC_HEARTBEAT_EDIT, buf);
1797 }
1798
1799 }
1800
1801 void get_teraterm_dir_relative_name(char FAR * buf, int bufsize,
1802 char FAR * basename)
1803 {
1804 int filename_start = 0;
1805 int i;
1806 int ch;
1807
1808 if (basename[0] == '\\' || basename[0] == '/'
1809 || (basename[0] != 0 && basename[1] == ':')) {
1810 strncpy(buf, basename, bufsize);
1811 buf[bufsize - 1] = 0;
1812 return;
1813 }
1814
1815 GetModuleFileName(NULL, buf, bufsize);
1816 for (i = 0; (ch = buf[i]) != 0; i++) {
1817 if (ch == '\\' || ch == '/' || ch == ':') {
1818 filename_start = i + 1;
1819 }
1820 }
1821
1822 if (bufsize > filename_start) {
1823 strncpy(buf + filename_start, basename, bufsize - filename_start);
1824 }
1825 buf[bufsize - 1] = 0;
1826 }
1827
1828 int copy_teraterm_dir_relative_path(char FAR * dest, int destsize,
1829 char FAR * basename)
1830 {
1831 char buf[1024];
1832 int filename_start = 0;
1833 int i;
1834 int ch, ch2;
1835
1836 if (basename[0] != '\\' && basename[0] != '/'
1837 && (basename[0] == 0 || basename[1] != ':')) {
1838 strncpy(dest, basename, destsize);
1839 dest[destsize - 1] = 0;
1840 return strlen(dest);
1841 }
1842
1843 GetModuleFileName(NULL, buf, sizeof(buf));
1844 for (i = 0; (ch = buf[i]) != 0; i++) {
1845 if (ch == '\\' || ch == '/' || ch == ':') {
1846 filename_start = i + 1;
1847 }
1848 }
1849
1850 for (i = 0; i < filename_start; i++) {
1851 ch = toupper(buf[i]);
1852 ch2 = toupper(basename[i]);
1853
1854 if (ch == ch2
1855 || ((ch == '\\' || ch == '/')
1856 && (ch2 == '\\' || ch2 == '/'))) {
1857 } else {
1858 break;
1859 }
1860 }
1861
1862 if (i == filename_start) {
1863 strncpy(dest, basename + i, destsize);
1864 } else {
1865 strncpy(dest, basename, destsize);
1866 }
1867 dest[destsize - 1] = 0;
1868 return strlen(dest);
1869 }
1870
1871 static void complete_setup_dlg(PTInstVar pvar, HWND dlg)
1872 {
1873 char buf[4096];
1874 char buf2[1024];
1875 HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1876 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1877 int i, j, buf2index, bufindex;
1878 int count = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0);
1879
1880 pvar->settings.CompressionLevel =
1881 (int) SendMessage(compressionControl, TBM_GETPOS, 0, 0);
1882
1883 buf2index = 0;
1884 for (i = 0; i < count; i++) {
1885 int len = SendMessage(cipherControl, LB_GETTEXTLEN, i, 0);
1886
1887 if (len > 0 && len < sizeof(buf)) { /* should always be true */
1888 buf[0] = 0;
1889 SendMessage(cipherControl, LB_GETTEXT, i, (LPARAM) buf);
1890 for (j = 0;
1891 j <= SSH_CIPHER_MAX
1892 && strcmp(buf, get_cipher_name(j)) != 0; j++) {
1893 }
1894 if (j <= SSH_CIPHER_MAX) {
1895 buf2[buf2index] = '0' + j;
1896 buf2index++;
1897 }
1898 }
1899 }
1900 buf2[buf2index] = 0;
1901 normalize_cipher_order(buf2);
1902 strcpy(pvar->settings.CipherOrder, buf2);
1903
1904 buf[0] = 0;
1905 GetDlgItemText(dlg, IDC_READWRITEFILENAME, buf, sizeof(buf));
1906 j = copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles,
1907 sizeof(pvar->settings.
1908 KnownHostsFiles), buf);
1909 buf[0] = 0;
1910 bufindex = 0;
1911 GetDlgItemText(dlg, IDC_READONLYFILENAME, buf, sizeof(buf));
1912 for (i = 0; buf[i] != 0; i++) {
1913 if (buf[i] == ';') {
1914 buf[i] = 0;
1915 if (j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1916 pvar->settings.KnownHostsFiles[j] = ';';
1917 j++;
1918 j += copy_teraterm_dir_relative_path(pvar->settings.
1919 KnownHostsFiles + j,
1920 sizeof(pvar->settings.
1921 KnownHostsFiles)
1922 - j, buf + bufindex);
1923 }
1924 bufindex = i + 1;
1925 }
1926 }
1927 if (bufindex < i && j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1928 pvar->settings.KnownHostsFiles[j] = ';';
1929 j++;
1930 copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles + j,
1931 sizeof(pvar->settings.
1932 KnownHostsFiles) - j,
1933 buf + bufindex);
1934 }
1935
1936 // get SSH HeartBeat(keep-alive)
1937 SendMessage(GetDlgItem(dlg, IDC_HEARTBEAT_EDIT), WM_GETTEXT, sizeof(buf), (LPARAM)buf);
1938 i = atoi(buf);
1939 if (i < 0)
1940 i = 60;
1941 pvar->settings.ssh_heartbeat_overtime = i;
1942
1943 }
1944
1945 static void move_cur_sel_delta(HWND listbox, int delta)
1946 {
1947 int curPos = (int) SendMessage(listbox, LB_GETCURSEL, 0, 0);
1948 int maxPos = (int) SendMessage(listbox, LB_GETCOUNT, 0, 0) - 1;
1949 int newPos = curPos + delta;
1950 char buf[1024];
1951
1952 if (curPos >= 0 && newPos >= 0 && newPos <= maxPos) {
1953 int len = SendMessage(listbox, LB_GETTEXTLEN, curPos, 0);
1954
1955 if (len > 0 && len < sizeof(buf)) { /* should always be true */
1956 buf[0] = 0;
1957 SendMessage(listbox, LB_GETTEXT, curPos, (LPARAM) buf);
1958 SendMessage(listbox, LB_DELETESTRING, curPos, 0);
1959 SendMessage(listbox, LB_INSERTSTRING, newPos,
1960 (LPARAM) (char FAR *) buf);
1961 SendMessage(listbox, LB_SETCURSEL, newPos, 0);
1962 }
1963 }
1964 }
1965
1966 static int get_keys_file_name(HWND parent, char FAR * buf, int bufsize,
1967 int readonly)
1968 {
1969 #ifdef TERATERM32
1970 OPENFILENAME params;
1971 char fullname_buf[2048] = "ssh_known_hosts";
1972
1973 params.lStructSize = sizeof(OPENFILENAME);
1974 params.hwndOwner = parent;
1975 params.lpstrFilter = NULL;
1976 params.lpstrCustomFilter = NULL;
1977 params.nFilterIndex = 0;
1978 buf[0] = 0;
1979 params.lpstrFile = fullname_buf;
1980 params.nMaxFile = sizeof(fullname_buf);
1981 params.lpstrFileTitle = NULL;
1982 params.lpstrInitialDir = NULL;
1983 params.lpstrTitle =
1984 readonly ? "Choose a read-only known-hosts file to add" :
1985 "Choose a read/write known-hosts file";
1986 params.Flags = (readonly ? OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST : 0)
1987 | OFN_HIDEREADONLY | (!readonly ? OFN_NOREADONLYRETURN : 0);
1988 params.lpstrDefExt = NULL;
1989
1990 if (GetOpenFileName(&params) != 0) {
1991 copy_teraterm_dir_relative_path(buf, bufsize, fullname_buf);
1992 return 1;
1993 } else {
1994 int err = CommDlgExtendedError();
1995
1996 if (err != 0) {
1997 char buf[1024];
1998
1999 _snprintf(buf, sizeof(buf),
2000 "Cannot show file dialog box: error %d", err);
2001 buf[sizeof(buf) - 1] = 0;
2002 MessageBox(parent, buf, "TTSSH Error",
2003 MB_OK | MB_ICONEXCLAMATION);
2004 }
2005
2006 return 0;
2007 }
2008 #else
2009 return 0;
2010 #endif
2011 }
2012
2013 static void choose_read_write_file(HWND dlg)
2014 {
2015 char buf[1024];
2016
2017 if (get_keys_file_name(dlg, buf, sizeof(buf), 0)) {
2018 SetDlgItemText(dlg, IDC_READWRITEFILENAME, buf);
2019 }
2020 }
2021
2022 static void choose_read_only_file(HWND dlg)
2023 {
2024 char buf[1024];
2025 char buf2[4096];
2026
2027 if (get_keys_file_name(dlg, buf, sizeof(buf), 1)) {
2028 buf2[0] = 0;
2029 GetDlgItemText(dlg, IDC_READONLYFILENAME, buf2, sizeof(buf2));
2030 if (buf2[0] != 0 && buf2[strlen(buf2) - 1] != ';') {
2031 strncat(buf2, ";", sizeof(buf2));
2032 }
2033 strncat(buf2, buf, sizeof(buf2));
2034 SetDlgItemText(dlg, IDC_READONLYFILENAME, buf2);
2035 }
2036 }
2037
2038 static BOOL CALLBACK TTXSetupDlg(HWND dlg, UINT msg, WPARAM wParam,
2039 LPARAM lParam)
2040 {
2041 switch (msg) {
2042 case WM_INITDIALOG:
2043 SetWindowLong(dlg, DWL_USER, lParam);
2044 init_setup_dlg((PTInstVar) lParam, dlg);
2045 return TRUE;
2046 case WM_COMMAND:
2047 switch (LOWORD(wParam)) {
2048 case IDOK:
2049 complete_setup_dlg((PTInstVar) GetWindowLong(dlg, DWL_USER),
2050 dlg);
2051 EndDialog(dlg, 1);
2052 return TRUE;
2053 case IDCANCEL: /* there isn't a cancel button, but other Windows
2054 UI things can send this message */
2055 EndDialog(dlg, 0);
2056 return TRUE;
2057 case IDC_SSHMOVECIPHERUP:
2058 move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), -1);
2059 set_move_button_status(dlg);
2060 SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
2061 return TRUE;
2062 case IDC_SSHMOVECIPHERDOWN:
2063 move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), 1);
2064 set_move_button_status(dlg);
2065 SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
2066 return TRUE;
2067 case IDC_SSHCIPHERPREFS:
2068 set_move_button_status(dlg);
2069 return TRUE;
2070 case IDC_CHOOSEREADWRITEFILE:
2071 choose_read_write_file(dlg);
2072 return TRUE;
2073 case IDC_CHOOSEREADONLYFILE:
2074 choose_read_only_file(dlg);
2075 return TRUE;
2076 }
2077 break;
2078 }
2079
2080 return FALSE;
2081 }
2082
2083
2084 //
2085 // SSH key generator dialog (2005.4.10 yutaka)
2086 //
2087
2088 typedef struct {
2089 RSA *rsa;
2090 DSA *dsa;
2091 } ssh_private_key_t;
2092
2093 static ssh_private_key_t private_key = {NULL, NULL};
2094
2095 typedef struct {
2096 RSA *rsa;
2097 DSA *dsa;
2098 } ssh_public_key_t;
2099
2100 static ssh_public_key_t public_key = {NULL, NULL};;
2101
2102 static void free_ssh_key(void)
2103 {
2104 // DSA_free(), RSA_free()��NULL���n�����������������B
2105 DSA_free(private_key.dsa);
2106 private_key.dsa = NULL;
2107 DSA_free(public_key.dsa);
2108 public_key.dsa = NULL;
2109
2110 RSA_free(private_key.rsa);
2111 private_key.rsa = NULL;
2112 RSA_free(public_key.rsa);
2113 public_key.rsa = NULL;
2114 }
2115
2116
2117 static BOOL generate_ssh_key(enum hostkey_type type)
2118 {
2119 int bits = 1024;
2120
2121 // if SSH key already is generated, should free the resource.
2122 free_ssh_key();
2123
2124 if (type == KEY_RSA1 || type == KEY_RSA) {
2125 RSA *priv = NULL;
2126 RSA *pub = NULL;
2127
2128 // private key
2129 priv = RSA_generate_key(bits, 35, NULL, NULL);
2130 if (priv == NULL)
2131 goto error;
2132 private_key.rsa = priv;
2133
2134 // public key
2135 pub = RSA_new();
2136 pub->n = BN_new();
2137 pub->e = BN_new();
2138 if (pub->n == NULL || pub->e == NULL) {
2139 RSA_free(pub);
2140 goto error;
2141 }
2142
2143 BN_copy(pub->n, priv->n);
2144 BN_copy(pub->e, priv->e);
2145 public_key.rsa = pub;
2146
2147 } else if (type == KEY_DSA) {
2148 DSA *priv = NULL;
2149 DSA *pub = NULL;
2150
2151 // private key
2152 priv = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
2153 if (priv == NULL)
2154 goto error;
2155 if (!DSA_generate_key(priv)) {
2156 // TODO: free 'priv'?
2157 goto error;
2158 }
2159 private_key.dsa = priv;
2160
2161 // public key
2162 pub = DSA_new();
2163 if (pub == NULL)
2164 goto error;
2165 pub->p = BN_new();
2166 pub->q = BN_new();
2167 pub->g = BN_new();
2168 pub->pub_key = BN_new();
2169 if (pub->p == NULL || pub->q == NULL || pub->g == NULL || pub->pub_key == NULL) {
2170 DSA_free(pub);
2171 goto error;
2172 }
2173
2174 BN_copy(pub->p, priv->p);
2175 BN_copy(pub->q, priv->q);
2176 BN_copy(pub->g, priv->g);
2177 BN_copy(pub->pub_key, priv->pub_key);
2178 public_key.dsa = pub;
2179
2180 } else {
2181 goto error;
2182 }
2183
2184 return TRUE;
2185
2186 error:
2187 free_ssh_key();
2188 return FALSE;
2189 }
2190
2191
2192 //
2193 // RC4
2194 //
2195
2196 /* Size of key to use */
2197 #define SEED_SIZE 20
2198
2199 /* Number of bytes to reseed after */
2200 #define REKEY_BYTES (1 << 24)
2201
2202 static int rc4_ready = 0;
2203 static RC4_KEY rc4;
2204
2205 static void seed_rng(void)
2206 {
2207 if (RAND_status() != 1)
2208 return;
2209 }
2210
2211 static void arc4random_stir(void)
2212 {
2213 unsigned char rand_buf[SEED_SIZE];
2214 int i;
2215
2216 memset(&rc4, 0, sizeof(rc4));
2217 if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0) {
2218 //fatal("Couldn't obtain random bytes (error %ld)",
2219 // ERR_get_error());
2220 }
2221 RC4_set_key(&rc4, sizeof(rand_buf), rand_buf);
2222
2223 /*
2224 * Discard early keystream, as per recommendations in:
2225 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
2226 */
2227 for(i = 0; i <= 256; i += sizeof(rand_buf))
2228 RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf);
2229
2230 memset(rand_buf, 0, sizeof(rand_buf));
2231
2232 rc4_ready = REKEY_BYTES;
2233 }
2234
2235 static unsigned int arc4random(void)
2236 {
2237 unsigned int r = 0;
2238 static int first_time = 1;
2239
2240 if (rc4_ready <= 0) {
2241 if (first_time) {
2242 seed_rng();
2243 }
2244 first_time = 0;
2245 arc4random_stir();
2246 }
2247
2248 RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r);
2249
2250 rc4_ready -= sizeof(r);
2251
2252 return(r);
2253 }
2254
2255 //
2256 // SSH1 3DES
2257 //
2258 /*
2259 * This is used by SSH1:
2260 *
2261 * What kind of triple DES are these 2 routines?
2262 *
2263 * Why is there a redundant initialization vector?
2264 *
2265 * If only iv3 was used, then, this would till effect have been
2266 * outer-cbc. However, there is also a private iv1 == iv2 which
2267 * perhaps makes differential analysis easier. On the other hand, the
2268 * private iv1 probably makes the CRC-32 attack ineffective. This is a
2269 * result of that there is no longer any known iv1 to use when
2270 * choosing the X block.
2271 */
2272 struct ssh1_3des_ctx
2273 {
2274 EVP_CIPHER_CTX k1, k2, k3;
2275 };
2276
2277 static int ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, int enc)
2278 {
2279 struct ssh1_3des_ctx *c;
2280 u_char *k1, *k2, *k3;
2281
2282 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
2283 c = malloc(sizeof(*c));
2284 EVP_CIPHER_CTX_set_app_data(ctx, c);
2285 }
2286 if (key == NULL)
2287 return (1);
2288 if (enc == -1)
2289 enc = ctx->encrypt;
2290 k1 = k2 = k3 = (u_char *) key;
2291 k2 += 8;
2292 if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
2293 if (enc)
2294 k3 += 16;
2295 else
2296 k1 += 16;
2297 }
2298 EVP_CIPHER_CTX_init(&c->k1);
2299 EVP_CIPHER_CTX_init(&c->k2);
2300 EVP_CIPHER_CTX_init(&c->k3);
2301 if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
2302 EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
2303 EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
2304 memset(c, 0, sizeof(*c));
2305 free(c);
2306 EVP_CIPHER_CTX_set_app_data(ctx, NULL);
2307 return (0);
2308 }
2309 return (1);
2310 }
2311
2312 static int ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len)
2313 {
2314 struct ssh1_3des_ctx *c;
2315
2316 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
2317 //error("ssh1_3des_cbc: no context");
2318 return (0);
2319 }
2320 if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
2321 EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
2322 EVP_Cipher(&c->k3, dest, dest, len) == 0)
2323 return (0);
2324 return (1);
2325 }
2326
2327 static int ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
2328 {
2329 struct ssh1_3des_ctx *c;
2330
2331 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
2332 EVP_CIPHER_CTX_cleanup(&c->k1);
2333 EVP_CIPHER_CTX_cleanup(&c->k2);
2334 EVP_CIPHER_CTX_cleanup(&c->k3);
2335 memset(c, 0, sizeof(*c));
2336 free(c);
2337 EVP_CIPHER_CTX_set_app_data(ctx, NULL);
2338 }
2339 return (1);
2340 }
2341
2342 void ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
2343 {
2344 struct ssh1_3des_ctx *c;
2345
2346 if (len != 24)
2347 //fatal("%s: bad 3des iv length: %d", __func__, len);
2348 ;
2349
2350 if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
2351 //fatal("%s: no 3des context", __func__);
2352 ;
2353
2354 if (doset) {
2355 //debug3("%s: Installed 3DES IV", __func__);
2356 memcpy(c->k1.iv, iv, 8);
2357 memcpy(c->k2.iv, iv + 8, 8);
2358 memcpy(c->k3.iv, iv + 16, 8);
2359 } else {
2360 //debug3("%s: Copying 3DES IV", __func__);
2361 memcpy(iv, c->k1.iv, 8);
2362 memcpy(iv + 8, c->k2.iv, 8);
2363 memcpy(iv + 16, c->k3.iv, 8);
2364 }
2365 }
2366
2367 const EVP_CIPHER *evp_ssh1_3des(void)
2368 {
2369 static EVP_CIPHER ssh1_3des;
2370
2371 memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
2372 ssh1_3des.nid = NID_undef;
2373 ssh1_3des.block_size = 8;
2374 ssh1_3des.iv_len = 0;
2375 ssh1_3des.key_len = 16;
2376 ssh1_3des.init = ssh1_3des_init;
2377 ssh1_3des.cleanup = ssh1_3des_cleanup;
2378 ssh1_3des.do_cipher = ssh1_3des_cbc;
2379 ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
2380 return (&ssh1_3des);
2381 }
2382
2383 static void ssh_make_comment(char *comment, int maxlen)
2384 {
2385 char user[UNLEN + 1], host[128];
2386 DWORD dwSize;
2387 WSADATA wsaData;
2388 int ret;
2389
2390 // get Windows logon user name
2391 dwSize = sizeof(user);
2392 if (GetUserName(user, &dwSize) == 0) {
2393 strcpy(user, "yutaka");
2394 }
2395
2396 // get local hostname (by WinSock)
2397 ret = WSAStartup(MAKEWORD(2,2), &wsaData);
2398 if (ret == 0) {
2399 if (gethostname(host, sizeof(host)) != 0) {
2400 ret = WSAGetLastError();
2401 }
2402 WSACleanup();
2403 }
2404 if (ret != 0) {
2405 strcpy(host, "sai");
2406 }
2407
2408 _snprintf(comment, maxlen, "%s@%s", user, host);
2409 }
2410
2411 // uuencode (rfc1521)
2412 int uuencode(unsigned char *src, int srclen, unsigned char *target, int targsize)
2413 {
2414 char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2415 char pad = '=';
2416 int datalength = 0;
2417 unsigned char input[3];
2418 unsigned char output[4];
2419 int i;
2420
2421 while (srclen > 2) {
2422 input[0] = *src++;
2423 input[1] = *src++;
2424 input[2] = *src++;
2425 srclen -= 3;
2426
2427 output[0] = input[0] >> 2;
2428 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
2429 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
2430 output[3] = input[2] & 0x3f;
2431 if (output[0] >= 64 ||
2432 output[1] >= 64 ||
2433 output[2] >= 64 ||
2434 output[3] >= 64)
2435 return -1;
2436
2437 if (datalength + 4 > targsize)
2438 return (-1);
2439 target[datalength++] = base64[output[0]];
2440 target[datalength++] = base64[output[1]];
2441 target[datalength++] = base64[output[2]];
2442 target[datalength++] = base64[output[3]];
2443 }
2444
2445 if (srclen != 0) {
2446 /* Get what's left. */
2447 input[0] = input[1] = input[2] = '\0';
2448 for (i = 0; i < srclen; i++)
2449 input[i] = *src++;
2450
2451 output[0] = input[0] >> 2;
2452 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
2453 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
2454 if (output[0] >= 64 ||
2455 output[1] >= 64 ||
2456 output[2] >= 64)
2457 return -1;
2458
2459 if (datalength + 4 > targsize)
2460 return (-1);
2461 target[datalength++] = base64[output[0]];
2462 target[datalength++] = base64[output[1]];
2463 if (srclen == 1)
2464 target[datalength++] = pad;
2465 else
2466 target[datalength++] = base64[output[2]];
2467 target[datalength++] = pad;
2468 }
2469 if (datalength >= targsize)
2470 return (-1);
2471 target[datalength] = '\0'; /* Returned value doesn't count \0. */
2472
2473 return (datalength); // success
2474 }
2475
2476 static BOOL CALLBACK TTXKeyGenerator(HWND dlg, UINT msg, WPARAM wParam,
2477 LPARAM lParam)
2478 {
2479 static enum hostkey_type key_type;
2480
2481 switch (msg) {
2482 case WM_INITDIALOG:
2483 {
2484 // default key type
2485 SendMessage(GetDlgItem(dlg, IDC_RSA_TYPE), BM_SETCHECK, BST_CHECKED, 0);
2486 key_type = KEY_RSA;
2487
2488 // passphrase edit box disabled(default)
2489 EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE);
2490 EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE);
2491
2492 // file saving dialog disabled(default)
2493 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE);
2494 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE);
2495
2496 }
2497 return TRUE;
2498
2499 case WM_COMMAND:
2500 switch (LOWORD(wParam)) {
2501 case IDOK: // key generate button pressed
2502 // passphrase edit box disabled(default)
2503 EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE);
2504 EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE);
2505
2506 // file saving dialog disabled(default)
2507 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE);
2508 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE);
2509
2510 if (generate_ssh_key(key_type)) {
2511 // passphrase edit box disabled(default)
2512 EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), TRUE);
2513 EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), TRUE);
2514
2515 // file saving dialog disabled(default)
2516 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), TRUE);
2517 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), TRUE);
2518 }
2519 return TRUE;
2520
2521 case IDCANCEL:
2522 // don't forget to free SSH resource!
2523 free_ssh_key();
2524 EndDialog(dlg, 0); // dialog close
2525 return TRUE;
2526
2527 // if radio button pressed...
2528 case IDC_RSA1_TYPE | (BN_CLICKED << 16):
2529 key_type = KEY_RSA1;
2530 break;
2531
2532 case IDC_RSA_TYPE | (BN_CLICKED << 16):
2533 key_type = KEY_RSA;
2534 break;
2535
2536 case IDC_DSA_TYPE | (BN_CLICKED << 16):
2537 key_type = KEY_DSA;
2538 break;
2539
2540 // saving public key file
2541 case IDC_SAVE_PUBLIC_KEY:
2542 {
2543 int ret;
2544 OPENFILENAME ofn;
2545 char filename[MAX_PATH];
2546 FILE *fp;
2547 char comment[1024]; // comment string in private key
2548
2549 arc4random_stir();
2550
2551 // saving file dialog
2552 ZeroMemory(&ofn, sizeof(ofn));
2553 ofn.lStructSize = sizeof(ofn);
2554 ofn.hwndOwner = dlg;
2555 if (key_type == KEY_RSA1) {
2556 ofn.lpstrFilter = "SSH1 RSA key(identity.pub)\0identity.pub\0All Files(*.*)\0*.*\0\0";
2557 _snprintf(filename, sizeof(filename), "identity.pub");
2558 } else if (key_type == KEY_RSA) {
2559 ofn.lpstrFilter = "SSH2 RSA key(id_rsa.pub)\0id_rsa.pub\0All Files(*.*)\0*.*\0\0";
2560 _snprintf(filename, sizeof(filename), "id_rsa.pub");
2561 } else {
2562 ofn.lpstrFilter = "SSH2 DSA key(id_dsa.pub)\0id_dsa.pub\0All Files(*.*)\0*.*\0\0";
2563 _snprintf(filename, sizeof(filename), "id_dsa.pub");
2564 }
2565 ofn.lpstrFile = filename;
2566 ofn.nMaxFile = sizeof(filename);
2567 ofn.lpstrTitle = "Save public key as:";
2568 if (GetSaveFileName(&ofn) == 0) { // failure
2569 ret = CommDlgExtendedError();
2570 break;
2571 }
2572
2573 ssh_make_comment(comment, sizeof(comment));
2574
2575 // saving public key file
2576 fp = fopen(filename, "wb");
2577 if (fp == NULL) {
2578 MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2579 break;
2580 }
2581
2582 if (key_type == KEY_RSA1) { // SSH1 RSA
2583 RSA *rsa = public_key.rsa;
2584 int bits;
2585 char *buf;
2586
2587 bits = BN_num_bits(rsa->n);
2588 fprintf(fp, "%u", bits);
2589
2590 buf = BN_bn2dec(rsa->e);
2591 fprintf(fp, " %s", buf);
2592 OPENSSL_free(buf);
2593
2594 buf = BN_bn2dec(rsa->n);
2595 fprintf(fp, " %s", buf);
2596 OPENSSL_free(buf);
2597
2598 } else { // SSH2 RSA, DSA
2599 buffer_t *b;
2600 char *keyname;
2601 DSA *dsa = public_key.dsa;
2602 RSA *rsa = public_key.rsa;
2603 int len;
2604 char *blob;
2605 char *uuenc; // uuencode data
2606 int uulen;
2607
2608 b = buffer_init();
2609 if (b == NULL)
2610 goto public_error;
2611
2612 if (key_type == KEY_DSA) { // DSA
2613 keyname = "ssh-dss";
2614 buffer_put_string(b, keyname, strlen(keyname));
2615 buffer_put_bignum2(b, dsa->p);
2616 buffer_put_bignum2(b, dsa->q);
2617 buffer_put_bignum2(b, dsa->g);
2618 buffer_put_bignum2(b, dsa->pub_key);
2619
2620 } else { // RSA
2621 keyname = "ssh-rsa";
2622 buffer_put_string(b, keyname, strlen(keyname));
2623 buffer_put_bignum2(b, rsa->e);
2624 buffer_put_bignum2(b, rsa->n);
2625 }
2626
2627 blob = buffer_ptr(b);
2628 len = buffer_len(b);
2629 uuenc = malloc(len * 2);
2630 if (uuenc == NULL) {
2631 buffer_free(b);
2632 goto public_error;
2633 }
2634 uulen = uuencode(blob, len, uuenc, len * 2);
2635 if (uulen > 0) {
2636 fprintf(fp, "%s %s", keyname, uuenc);
2637 }
2638 free(uuenc);
2639 buffer_free(b);
2640 }
2641
2642 // writing a comment(+LF)
2643 fprintf(fp, " %s", comment);
2644 fputc(0x0a, fp);
2645
2646 public_error:
2647 fclose(fp);
2648
2649 }
2650 break;
2651
2652 // saving private key file
2653 case IDC_SAVE_PRIVATE_KEY:
2654 {
2655 char buf[1024], buf_conf[1024]; // passphrase
2656 int ret;
2657 OPENFILENAME ofn;
2658 char filename[MAX_PATH];
2659 char comment[1024]; // comment string in private key
2660
2661 // �p�X�t���[�Y���`�F�b�N���s���B�p�X�t���[�Y���������t�@�C�����t�����B
2662 SendMessage(GetDlgItem(dlg, IDC_KEY_EDIT), WM_GETTEXT, sizeof(buf), (LPARAM)buf);
2663 SendMessage(GetDlgItem(dlg, IDC_CONFIRM_EDIT), WM_GETTEXT, sizeof(buf_conf), (LPARAM)buf_conf);
2664
2665 // check matching
2666 if (strcmp(buf, buf_conf) != 0) {
2667 MessageBox(dlg, "Two passphrases don't match.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2668 break;
2669 }
2670
2671 // check empty-passphrase (this is warning level)
2672 if (buf[0] == '\0') {
2673 ret = MessageBox(dlg, "Are you sure that you want to use a empty passphrase?", "WARNING", MB_YESNO | MB_ICONWARNING);
2674 if (ret == IDNO)
2675 break;
2676 }
2677
2678 ssh_make_comment(comment, sizeof(comment));
2679
2680 // saving file dialog
2681 ZeroMemory(&ofn, sizeof(ofn));
2682 ofn.lStructSize = sizeof(ofn);
2683 ofn.hwndOwner = dlg;
2684 if (key_type == KEY_RSA1) {
2685 ofn.lpstrFilter = "SSH1 RSA key(identity)\0identity\0All Files(*.*)\0*.*\0\0";
2686 _snprintf(filename, sizeof(filename), "identity");
2687 } else if (key_type == KEY_RSA) {
2688 ofn.lpstrFilter = "SSH2 RSA key(id_rsa)\0id_rsa\0All Files(*.*)\0*.*\0\0";
2689 _snprintf(filename, sizeof(filename), "id_rsa");
2690 } else {
2691 ofn.lpstrFilter = "SSH2 DSA key(id_dsa)\0id_dsa\0All Files(*.*)\0*.*\0\0";
2692 _snprintf(filename, sizeof(filename), "id_dsa");
2693 }
2694 ofn.lpstrFile = filename;
2695 ofn.nMaxFile = sizeof(filename);
2696 ofn.lpstrTitle = "Save private key as:";
2697 if (GetSaveFileName(&ofn) == 0) { // failure
2698 ret = CommDlgExtendedError();
2699 break;
2700 }
2701
2702 // saving private key file
2703 if (key_type == KEY_RSA1) { // SSH1 RSA
2704 int cipher_num;
2705 buffer_t *b, *enc;
2706 unsigned int rnd;
2707 unsigned char tmp[128];
2708 RSA *rsa;
2709 int i, len;
2710 char authfile_id_string[] = "SSH PRIVATE KEY FILE FORMAT 1.1";
2711 MD5_CTX md;
2712 unsigned char digest[16];
2713 char *passphrase = buf;
2714 EVP_CIPHER_CTX cipher_ctx;
2715 FILE *fp;
2716 char wrapped[4096];
2717
2718 if (passphrase[0] == '\0') { // passphrase is empty
2719 cipher_num = SSH_CIPHER_NONE;
2720 } else {
2721 cipher_num = SSH_CIPHER_3DES; // 3DES-CBC
2722 }
2723
2724 b = buffer_init();
2725 if (b == NULL)
2726 break;
2727 enc = buffer_init();
2728 if (enc == NULL) {
2729 buffer_free(b);
2730 break;
2731 }
2732
2733 // set random value
2734 rnd = arc4random();
2735 tmp[0] = rnd & 0xff;
2736 tmp[1] = (rnd >> 8) & 0xff;
2737 tmp[2] = tmp[0];
2738 tmp[3] = tmp[1];
2739 buffer_append(b, tmp, 4);
2740
2741 // set private key
2742 rsa = private_key.rsa;
2743 buffer_put_bignum(b, rsa->d);
2744 buffer_put_bignum(b, rsa->iqmp);
2745 buffer_put_bignum(b, rsa->q);
2746 buffer_put_bignum(b, rsa->p);
2747
2748 // padding with 8byte align
2749 while (buffer_len(b) % 8) {
2750 buffer_put_char(b, 0);
2751 }
2752
2753 //
2754 // step(2)
2755 //
2756 // encrypted buffer
2757 /* First store keyfile id string. */
2758 for (i = 0 ; authfile_id_string[i] ; i++) {
2759 buffer_put_char(enc, authfile_id_string[i]);
2760 }
2761 buffer_put_char(enc, 0x0a); // LF
2762 buffer_put_char(enc, 0);
2763
2764 /* Store cipher type. */
2765 buffer_put_char(enc, cipher_num);
2766 buffer_put_int(enc, 0); // type is 'int'!! (For future extension)
2767
2768 /* Store public key. This will be in plain text. */
2769 buffer_put_int(enc, BN_num_bits(rsa->n));
2770 buffer_put_bignum(enc, rsa->n);
2771 buffer_put_bignum(enc, rsa->e);
2772 buffer_put_string(enc, comment, strlen(comment));
2773
2774 // setup the MD5ed passphrase to cipher encryption key
2775 MD5_Init(&md);
2776 MD5_Update(&md, (const unsigned char *)passphrase, strlen(passphrase));
2777 MD5_Final(digest, &md);
2778 if (cipher_num == SSH_CIPHER_NONE) {
2779 cipher_init_SSH2(&cipher_ctx, digest, 16, NULL, 0, CIPHER_ENCRYPT, EVP_enc_null);
2780 } else {
2781 cipher_init_SSH2(&cipher_ctx, digest, 16, NULL, 0, CIPHER_ENCRYPT, evp_ssh1_3des);
2782 }
2783 len = buffer_len(b);
2784 if (len % 8) { // fatal error
2785 goto error;
2786 }
2787
2788 // check buffer overflow
2789 if (buffer_overflow_verify(enc, len) && (sizeof(wrapped) < len)) {
2790 goto error;
2791 }
2792
2793 if (EVP_Cipher(&cipher_ctx, wrapped, buffer_ptr(b), len) == 0) {
2794 goto error;
2795 }
2796 if (EVP_CIPHER_CTX_cleanup(&cipher_ctx) == 0) {
2797 goto error;
2798 }
2799
2800 buffer_append(enc, wrapped, len);
2801
2802 // saving private key file (binary mode)
2803 fp = fopen(filename, "wb");
2804 if (fp == NULL) {
2805 MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2806 break;
2807 }
2808 fwrite(buffer_ptr(enc), buffer_len(enc), 1, fp);
2809
2810 fclose(fp);
2811
2812 error:;
2813 buffer_free(b);
2814 buffer_free(enc);
2815
2816 } else { // SSH2 RSA, DSA
2817 int len;
2818 FILE *fp;
2819 const EVP_CIPHER *cipher;
2820
2821 len = strlen(buf);
2822 // TODO: range check (len >= 4)
2823
2824 cipher = NULL;
2825 if (len > 0) {
2826 cipher = EVP_des_ede3_cbc();
2827 }
2828
2829 fp = fopen(filename, "w");
2830 if (fp == NULL) {
2831 MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2832 break;
2833 }
2834
2835 if (key_type == KEY_RSA) { // RSA
2836 ret = PEM_write_RSAPrivateKey(fp, private_key.rsa, cipher, buf, len, NULL, NULL);
2837 } else { // DSA
2838 ret = PEM_write_DSAPrivateKey(fp, private_key.dsa, cipher, buf, len, NULL, NULL);
2839 }
2840 if (ret == 0) {
2841 MessageBox(dlg, "Can't write key file", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2842 }
2843 fclose(fp);
2844 }
2845
2846
2847 }
2848 break;
2849
2850 }
2851 break;
2852 }
2853
2854 return FALSE;
2855 }
2856
2857
2858 static int PASCAL FAR TTXProcessCommand(HWND hWin, WORD cmd)
2859 {
2860 GET_VAR();
2861
2862 if (pvar->fatal_error) {
2863 return 0;
2864 }
2865
2866 switch (cmd) {
2867 case ID_SSHKEYGENMENU:
2868 if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHKEYGEN), hWin, TTXKeyGenerator,
2869 (LPARAM) pvar) == -1) {
2870 MessageBox(hWin, "Cannot create Key Generator window.",
2871 "TTSSH Error", MB_OK | MB_ICONEXCLAMATION);
2872 }
2873 return 1;
2874
2875 case ID_ABOUTMENU:
2876 if (DialogBoxParam
2877 (hInst, MAKEINTRESOURCE(IDD_ABOUTDIALOG), hWin, TTXAboutDlg,
2878 (LPARAM) pvar)
2879 == -1) {
2880 MessageBox(hWin, "Cannot create About box window.",
2881 "TTSSH Error", MB_OK | MB_ICONEXCLAMATION);
2882 }
2883 return 1;
2884 case ID_SSHAUTH:
2885 AUTH_do_cred_dialog(pvar);
2886 return 1;
2887 case ID_SSHSETUPMENU:
2888 if (DialogBoxParam
2889 (hInst, MAKEINTRESOURCE(IDD_SSHSETUP), hWin, TTXSetupDlg,
2890 (LPARAM) pvar)
2891 == -1) {
2892 MessageBox(hWin, "Cannot create TTSSH Setup window.",
2893 "TTSSH Error", MB_OK | MB_ICONEXCLAMATION);
2894 }
2895 return 1;
2896 case ID_SSHAUTHSETUPMENU:
2897 AUTH_do_default_cred_dialog(pvar);
2898 return 1;
2899 case ID_SSHFWDSETUPMENU:
2900 FWDUI_do_forwarding_dialog(pvar);
2901 return 1;
2902 case ID_SSHUNKNOWNHOST:
2903 HOSTS_do_unknown_host_dialog(hWin, pvar);
2904 return 1;
2905 case ID_SSHDIFFERENTHOST:
2906 HOSTS_do_different_host_dialog(hWin, pvar);
2907 return 1;
2908 case ID_SSHASYNCMESSAGEBOX:
2909 if (pvar->err_msg != NULL) {
2910 char FAR *msg = pvar->err_msg;
2911
2912 /* Could there be a buffer overrun bug anywhere in Win32
2913 MessageBox? Who knows? I'm paranoid. */
2914 if (strlen(msg) > 2048) {
2915 msg[2048] = 0;
2916 }
2917
2918 pvar->showing_err = TRUE;
2919 pvar->err_msg = NULL;
2920 #if 1
2921 // XXX: "SECURITY WARINIG" dialog�� ESC �L�[�������������A
2922 // �������A�v���P�[�V�����G���[�����������A���LAPI�������B(2004.12.16 yutaka)
2923 if (!SSHv1(pvar)) {
2924 MessageBox(NULL, msg, "TTSSH",
2925 MB_TASKMODAL | MB_ICONEXCLAMATION);
2926 }
2927 #else
2928 MessageBox(NULL, msg, "TTSSH",
2929 MB_TASKMODAL | MB_ICONEXCLAMATION);
2930 #endif
2931 free(msg);
2932 pvar->showing_err = FALSE;
2933
2934 if (pvar->err_msg != NULL) {
2935 PostMessage(hWin, WM_COMMAND, ID_SSHASYNCMESSAGEBOX, 0);
2936 } else {
2937 AUTH_notify_end_error(pvar);
2938 }
2939 }
2940 return 1;
2941 default:
2942 return 0;
2943 }
2944 }
2945
2946
2947 // ������TeraTerm Menu���R�[�h(ttpmenu.cpp)�������B
2948 // ������ @ ���u���������B@���g��@@�������B(2005.1.28 yutaka)
2949 static void replace_blank_to_mark(char *str, char *dst, int dst_len)
2950 {
2951 int i, len, n;
2952
2953 len = strlen(str);
2954 n = 0;
2955 for (i = 0 ; i < len ; i++) {
2956 if (str[i] == '@')
2957 n++;
2958 }
2959 if (dst_len < (len + 2*n))
2960 return;
2961
2962 for (i = 0 ; i < len ; i++) {
2963 if (str[i] == '@') {
2964 *dst++ = '@';
2965 *dst++ = '@';
2966
2967 } else if (str[i] == ' ') {
2968 *dst++ = '@';
2969
2970 } else {
2971 *dst++ = str[i];
2972
2973 }
2974 }
2975 *dst = '\0';
2976
2977 }
2978
2979 static void PASCAL FAR TTXSetCommandLine(PCHAR cmd, int cmdlen,
2980 PGetHNRec rec)
2981 {
2982 char tmpFile[MAX_PATH];
2983 char tmpPath[1024];
2984 char buf[1024];
2985 int i;
2986 GET_VAR();
2987
2988 GetTempPath(sizeof(tmpPath), tmpPath);
2989 GetTempFileName(tmpPath, "TTX", 0, tmpFile);
2990
2991 for (i = 0; cmd[i] != ' ' && cmd[i] != 0; i++) {
2992 }
2993
2994 if (i < cmdlen) {
2995 strncpy(buf, cmd + i, sizeof(buf));
2996 cmd[i] = 0;
2997
2998 write_ssh_options(pvar, tmpFile, &pvar->settings, FALSE);
2999
3000 strncat(cmd, " /ssh-consume=", cmdlen);
3001 strncat(cmd, tmpFile, cmdlen);
3002
3003 strncat(cmd, buf, cmdlen);
3004
3005 if (pvar->hostdlg_Enabled) {
3006 strncat(cmd, " /ssh", cmdlen);
3007
3008 // add option of SSH protcol version (2004.10.11 yutaka)
3009 if (pvar->settings.ssh_protocol_version == 2) {
3010 strncat(cmd, " /2", cmdlen);
3011 } else {
3012 strncat(cmd, " /1", cmdlen);
3013 }
3014
3015 }
3016
3017 // �Z�b�V�����������������A�������O�C���p�p�����[�^���t�����B(2005.4.8 yutaka)
3018 if (strstr(buf, "DUPLICATE")) {
3019 char mark[MAX_PATH];
3020 char tmp[MAX_PATH*2];
3021
3022 // �������O�C�������������L�t���O��0�������A�K�v���R�}���h���t�������B
3023 if (!pvar->hostdlg_Enabled) {
3024 _snprintf(tmp, sizeof(tmp), " /ssh /%d", pvar->settings.ssh_protocol_version);
3025 strncat(cmd, tmp, cmdlen);
3026 }
3027
3028 // �p�X���[�h���o�����������������A�R�}���h���C�����n���B(2006.8.3 yutaka)
3029 if (pvar->settings.remember_password &&
3030 pvar->auth_state.cur_cred.method == SSH_AUTH_PASSWORD) {
3031 replace_blank_to_mark(pvar->auth_state.cur_cred.password, mark, sizeof(mark));
3032 _snprintf(tmp, sizeof(tmp), " /auth=password /user=%s /passwd=%s", pvar->auth_state.user, mark);
3033 strncat(cmd, tmp, cmdlen);
3034
3035 } else if (pvar->settings.remember_password &&
3036 pvar->auth_state.cur_cred.method == SSH_AUTH_RSA) {
3037 replace_blank_to_mark(pvar->auth_state.cur_cred.password, mark, sizeof(mark));
3038 _snprintf(tmp, sizeof(tmp), " /auth=publickey /user=%s /passwd=%s", pvar->auth_state.user, mark);
3039 strncat(cmd, tmp, cmdlen);
3040
3041 replace_blank_to_mark(pvar->session_settings.DefaultRSAPrivateKeyFile, mark, sizeof(mark));
3042 _snprintf(tmp, sizeof(tmp), " /keyfile=%s", mark);
3043 strncat(cmd, tmp, cmdlen);
3044
3045 } else if (pvar->auth_state.cur_cred.method == SSH_AUTH_TIS) {
3046 // keyboard-interactive�F���������������������B
3047
3048 } else {
3049 // don't come here
3050
3051 }
3052
3053 }
3054
3055 }
3056 }
3057
3058 /* This function is called when Teraterm is quitting. You can use it to clean
3059 up.
3060
3061 This function is called for each extension, in reverse load order (see
3062 below).
3063 */
3064 static void PASCAL FAR TTXEnd(void)
3065 {
3066 GET_VAR();
3067
3068 uninit_TTSSH(pvar);
3069
3070 if (pvar->err_msg != NULL) {
3071 /* Could there be a buffer overrun bug anywhere in Win32
3072 MessageBox? Who knows? I'm paranoid. */
3073 if (strlen(pvar->err_msg) > 2048) {
3074 pvar->err_msg[2048] = 0;
3075 }
3076
3077 MessageBox(NULL, pvar->err_msg, "TTSSH",
3078 MB_TASKMODAL | MB_ICONEXCLAMATION);