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 2911 - (show annotations) (download) (as text)
Fri Oct 6 16:35:25 2006 UTC (17 years, 6 months ago) by maya
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 90816 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) strncmp((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 /* returns 1 if the option text must be deleted */
1232 static int parse_option(PTInstVar pvar, char FAR * option)
1233 {
1234 if ((option[0] == '-' || option[0] == '/')) {
1235 if (MATCH_STR(option + 1, "ssh") == 0) {
1236 if (option[4] == 0) {
1237 pvar->settings.Enabled = 1;
1238 } else if (MATCH_STR(option + 4, "-L") == 0
1239 || MATCH_STR(option + 4, "-R") == 0
1240 || _stricmp(option + 4, "-X") == 0) {
1241 if (pvar->settings.DefaultForwarding[0] == 0) {
1242 strcpy(pvar->settings.DefaultForwarding, option + 5);
1243 } else {
1244 strcat(pvar->settings.DefaultForwarding, ";");
1245 strcat(pvar->settings.DefaultForwarding, option + 5);
1246 }
1247 } else if (MATCH_STR(option + 4, "-f=") == 0) {
1248 read_ssh_options_from_user_file(pvar, option + 7);
1249 } else if (MATCH_STR(option + 4, "-v") == 0) {
1250 pvar->settings.LogLevel = LOG_LEVEL_VERBOSE;
1251 } else if (_stricmp(option + 4, "-autologin") == 0
1252 || _stricmp(option + 4, "-autologon") == 0) {
1253 pvar->settings.TryDefaultAuth = TRUE;
1254
1255 } else if (MATCH_STR(option + 4, "-consume=") == 0) {
1256 read_ssh_options_from_user_file(pvar, option + 13);
1257 DeleteFile(option + 13);
1258
1259 // /ssh1 �� /ssh2 �I�v�V�������V�K���� (2006.9.16 maya)
1260 } else if (MATCH_STR(option + 4, "1") == 0) {
1261 pvar->settings.ssh_protocol_version = 1;
1262 } else if (MATCH_STR(option + 4, "2") == 0) {
1263 pvar->settings.ssh_protocol_version = 2;
1264
1265 } else {
1266 char buf[1024];
1267
1268 _snprintf(buf, sizeof(buf),
1269 "Unrecognized command-line option: %s", option);
1270 buf[sizeof(buf) - 1] = 0;
1271
1272 MessageBox(NULL, buf, "TTSSH", MB_OK | MB_ICONEXCLAMATION);
1273 }
1274
1275 return 1;
1276 } else if (MATCH_STR(option + 1, "t=") == 0) {
1277 if (strcmp(option + 3, "2") == 0) {
1278 pvar->settings.Enabled = 1;
1279 return 1;
1280 } else {
1281 pvar->settings.Enabled = 0;
1282 }
1283 } else if (MATCH_STR(option + 1, "f=") == 0) {
1284 read_ssh_options_from_user_file(pvar, option + 3);
1285
1286 // /1 ������ /2 �I�v�V�������V�K���� (2004.10.3 yutaka)
1287 } else if (MATCH_STR(option + 1, "1") == 0) {
1288 // command line: /ssh /1 is SSH1 only
1289 pvar->settings.ssh_protocol_version = 1;
1290
1291 } else if (MATCH_STR(option + 1, "2") == 0) {
1292 // command line: /ssh /2 is SSH2 & SSH1
1293 pvar->settings.ssh_protocol_version = 2;
1294
1295 } else if (MATCH_STR(option + 1, "nossh") == 0) {
1296 // '/nossh' �I�v�V�����������B
1297 // TERATERM.INI ��SSH���L�������������������A������Cygterm���N��������������
1298 // �����������������B(2004.10.11 yutaka)
1299 pvar->settings.Enabled = 0;
1300
1301 } else if (MATCH_STR(option + 1, "telnet") == 0) {
1302 // '/telnet' ���w�������������������� '/nossh' ��������
1303 // SSH������������ (2006.9.16 maya)
1304 pvar->settings.Enabled = 0;
1305
1306 } else if (MATCH_STR(option + 1, "auth") == 0) {
1307 // SSH2�������O�C���I�v�V����������
1308 //
1309 // SYNOPSIS: /ssh /auth=passowrd /user=���[�U�� /passwd=�p�X���[�h
1310 // /ssh /auth=publickey /user=���[�U�� /passwd=�p�X���[�h /keyfile=�p�X
1311 // EXAMPLE: /ssh /auth=password /user=nike /passwd=a@bc
1312 // /ssh /auth=publickey /user=foo /passwd=bar /keyfile=d:\tmp\id_rsa
1313 // NOTICE: �p�X���[�h���p�X�������������������A�u�����N���������� @ ���g�������B
1314 //
1315 // (2004.11.30 yutaka)
1316 // (2005.1.26 yutaka) ���������B���J���F���T�|�[�g�B
1317 //
1318 pvar->ssh2_autologin = 1; // for SSH2 (2004.11.30 yutaka)
1319
1320 if (MATCH_STR(option + 5, "=password") == 0) { // �p�X���[�h/keyboard-interactive�F��
1321 //pvar->auth_state.cur_cred.method = SSH_AUTH_PASSWORD;
1322 pvar->ssh2_authmethod = SSH_AUTH_PASSWORD;
1323
1324 } else if (MATCH_STR(option + 5, "=publickey") == 0) { // ���J���F��
1325 //pvar->auth_state.cur_cred.method = SSH_AUTH_RSA;
1326 pvar->ssh2_authmethod = SSH_AUTH_RSA;
1327
1328 } else {
1329 // TODO:
1330
1331 }
1332
1333 } else if (MATCH_STR(option + 1, "user=") == 0) {
1334 replace_to_blank(option + 6, pvar->ssh2_username, sizeof(pvar->ssh2_username));
1335 //_snprintf(pvar->ssh2_username, sizeof(pvar->ssh2_username), "%s", option + 6);
1336
1337 } else if (MATCH_STR(option + 1, "passwd=") == 0) {
1338 replace_to_blank(option + 8, pvar->ssh2_password, sizeof(pvar->ssh2_password));
1339 //_snprintf(pvar->ssh2_password, sizeof(pvar->ssh2_password), "%s", option + 8);
1340
1341 } else if (MATCH_STR(option + 1, "keyfile=") == 0) {
1342 replace_to_blank(option + 9, pvar->ssh2_keyfile, sizeof(pvar->ssh2_keyfile));
1343
1344 } else if (MATCH_STR(option + 1, "ask4passwd") == 0) {
1345 // �p�X���[�h������ (2006.9.18 maya)
1346 pvar->ask4passwd = 1;
1347
1348 }
1349
1350 // �p�X���[�h�������������������O�C��������������
1351 // /auth ���F�����\�b�h���w�������������p������ (2006.9.18 maya)
1352 if (pvar->ask4passwd == 1) {
1353 pvar->ssh2_autologin = 0;
1354 }
1355
1356 }
1357
1358 return 0;
1359 }
1360
1361 static void FAR PASCAL TTXParseParam(PCHAR param, PTTSet ts,
1362 PCHAR DDETopic)
1363 {
1364 // �X�y�[�X�������t�@�C�������F�������������C�� (2006.10.7 maya)
1365 int i;
1366 BOOL inParam = FALSE;
1367 BOOL inQuotes = FALSE;
1368 BOOL inFileParam = FALSE;
1369 PCHAR option = NULL;
1370 GET_VAR();
1371
1372 if (pvar->hostdlg_activated) {
1373 pvar->settings.Enabled = pvar->hostdlg_Enabled;
1374 }
1375
1376 for (i = 0; param[i] != 0; i++) {
1377 if (inQuotes ? param[i] == '"'
1378 : (param[i] == ' ' || param[i] == '\t')) {
1379 if (option != NULL) {
1380 char ch = param[i];
1381 PCHAR Equal;
1382
1383 param[i] = 0;
1384 Equal = strchr(option, '=');
1385 if (inFileParam && Equal != NULL && *(Equal + 1) == '"') {
1386 char *buf = (char *)calloc(strlen(option), sizeof(char));
1387 strncat(buf, option, Equal - option + 1);
1388 strcat(buf, Equal + 2);
1389 if (parse_option
1390 (pvar, *buf == '"' ? buf + 1 : buf)) {
1391 memset(option, ' ', i + 1 - (option - param));
1392 } else {
1393 param[i] = ch;
1394 }
1395 free(buf);
1396 }
1397 else {
1398 if (parse_option
1399 (pvar, *option == '"' ? option + 1 : option)) {
1400 memset(option, ' ', i + 1 - (option - param));
1401 } else {
1402 param[i] = ch;
1403 }
1404 }
1405 option = NULL;
1406 }
1407 inParam = FALSE;
1408 inQuotes = FALSE;
1409 inFileParam = FALSE;
1410 } else if (!inParam) {
1411 if (param[i] == '"') {
1412 inQuotes = TRUE;
1413 inParam = TRUE;
1414 option = param + i;
1415 } else if (param[i] != ' ' && param[i] != '\t') {
1416 inParam = TRUE;
1417 option = param + i;
1418 }
1419 } else {
1420 if (option == NULL) {
1421 continue;
1422 }
1423 if ((option[0] == '-' || option[0] == '/') &&
1424 (MATCH_STR(option + 1, "ssh-f=") == 0 ||
1425 MATCH_STR(option + 1, "ssh-consume=") == 0 ||
1426 MATCH_STR(option + 1, "f=") == 0)) {
1427 if (param[i] == '"') {
1428 inQuotes = TRUE;
1429 }
1430 inFileParam = TRUE;
1431 }
1432 }
1433 }
1434
1435 if (option != NULL) {
1436 PCHAR Equal = strchr(option, '=');
1437 if (inFileParam && Equal != NULL && *(Equal + 1) == '"') {
1438 char *buf = (char *)calloc(strlen(option), sizeof(char));
1439 strncat(buf, option, Equal - option + 1);
1440 strcat(buf, Equal + 2);
1441 if (parse_option
1442 (pvar, *buf == '"' ? buf + 1 : buf)) {
1443 memset(option, ' ', i + 1 - (option - param));
1444 }
1445 free(buf);
1446 }
1447 else {
1448 if (parse_option(pvar, option)) {
1449 memset(option, ' ', i - (option - param));
1450 }
1451 }
1452 }
1453
1454 FWDUI_load_settings(pvar);
1455
1456 (pvar->ParseParam) (param, ts, DDETopic);
1457
1458 }
1459
1460 static void PASCAL FAR TTXGetSetupHooks(TTXSetupHooks FAR * hooks)
1461 {
1462 GET_VAR();
1463
1464 pvar->ReadIniFile = *hooks->ReadIniFile;
1465 pvar->WriteIniFile = *hooks->WriteIniFile;
1466 pvar->ParseParam = *hooks->ParseParam;
1467
1468 *hooks->ReadIniFile = TTXReadINIFile;
1469 *hooks->WriteIniFile = TTXWriteINIFile;
1470 *hooks->ParseParam = TTXParseParam;
1471 }
1472
1473 static void PASCAL FAR TTXSetWinSize(int rows, int cols)
1474 {
1475 GET_VAR();
1476
1477 SSH_notify_win_size(pvar, cols, rows);
1478 }
1479
1480 static void insertMenuBeforeItem(HMENU menu, WORD beforeItemID, WORD flags,
1481 WORD newItemID, char FAR * text)
1482 {
1483 int i, j;
1484
1485 for (i = GetMenuItemCount(menu) - 1; i >= 0; i--) {
1486 HMENU submenu = GetSubMenu(menu, i);
1487
1488 for (j = GetMenuItemCount(submenu) - 1; j >= 0; j--) {
1489 if (GetMenuItemID(submenu, j) == beforeItemID) {
1490 InsertMenu(submenu, j, MF_BYPOSITION | flags, newItemID,
1491 text);
1492 return;
1493 }
1494 }
1495 }
1496 }
1497
1498 static void PASCAL FAR TTXModifyMenu(HMENU menu)
1499 {
1500 GET_VAR();
1501
1502 /* inserts before ID_HELP_ABOUT */
1503 insertMenuBeforeItem(menu, 50990, MF_ENABLED, ID_ABOUTMENU,
1504 "About &TTSSH...");
1505
1506 /* inserts before ID_SETUP_TCPIP */
1507 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHSETUPMENU,
1508 "SS&H...");
1509 /* inserts before ID_SETUP_TCPIP */
1510 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHAUTHSETUPMENU,
1511 "SSH &Authentication...");
1512 /* inserts before ID_SETUP_TCPIP */
1513 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHFWDSETUPMENU,
1514 "SSH F&orwarding...");
1515
1516 insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHKEYGENMENU,
1517 "SSH KeyGenerator...");
1518 }
1519
1520 static void append_about_text(HWND dlg, char FAR * prefix, char FAR * msg)
1521 {
1522 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1523 (LPARAM) prefix);
1524 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0, (LPARAM) msg);
1525 SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1526 (LPARAM) (char FAR *) "\r\n");
1527 }
1528
1529 // ���s�t�@�C�������o�[�W�������������� (2005.2.28 yutaka)
1530 void get_file_version(char *exefile, int *major, int *minor, int *release, int *build)
1531 {
1532 typedef struct {
1533 WORD wLanguage;
1534 WORD wCodePage;
1535 } LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
1536 LPLANGANDCODEPAGE lplgcode;
1537 UINT unLen;
1538 DWORD size;
1539 char *buf = NULL;
1540 BOOL ret;
1541 int i;
1542 char fmt[80];
1543 char *pbuf;
1544
1545 size = GetFileVersionInfoSize(exefile, NULL);
1546 if (size == 0) {
1547 goto error;
1548 }
1549 buf = malloc(size);
1550 ZeroMemory(buf, size);
1551
1552 if (GetFileVersionInfo(exefile, 0, size, buf) == FALSE) {
1553 goto error;
1554 }
1555
1556 ret = VerQueryValue(buf,
1557 "\\VarFileInfo\\Translation",
1558 (LPVOID *)&lplgcode, &unLen);
1559 if (ret == FALSE)
1560 goto error;
1561
1562 for (i = 0 ; i < (int)(unLen / sizeof(LANGANDCODEPAGE)) ; i++) {
1563 _snprintf(fmt, sizeof(fmt), "\\StringFileInfo\\%04x%04x\\FileVersion",
1564 lplgcode[i].wLanguage, lplgcode[i].wCodePage);
1565 VerQueryValue(buf, fmt, &pbuf, &unLen);
1566 if (unLen > 0) { // get success
1567 int n, a, b, c, d;
1568
1569 n = sscanf(pbuf, "%d, %d, %d, %d", &a, &b, &c, &d);
1570 if (n == 4) { // convert success
1571 *major = a;
1572 *minor = b;
1573 *release = c;
1574 *build = d;
1575 break;
1576 }
1577 }
1578 }
1579
1580 free(buf);
1581 return;
1582
1583 error:
1584 free(buf);
1585 *major = *minor = *release = *build = 0;
1586 }
1587
1588 static void init_about_dlg(PTInstVar pvar, HWND dlg)
1589 {
1590 char buf[1024];
1591 int a, b, c, d;
1592
1593 // TTSSH���o�[�W�������������� (2005.2.28 yutaka)
1594 get_file_version("ttxssh.dll", &a, &b, &c, &d);
1595 _snprintf(buf, sizeof(buf), "TTSSH\r\nTeraterm Secure Shell extension, %d.%d", a, b);
1596 SendMessage(GetDlgItem(dlg, IDC_TTSSH_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1597
1598 // OpenSSL���o�[�W�������������� (2005.1.24 yutaka)
1599 // ���������� (2005.5.11 yutaka)
1600 #ifdef OPENSSL_VERSION_TEXT
1601 SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)OPENSSL_VERSION_TEXT);
1602 #else
1603 SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)"Unknown");
1604 #endif
1605
1606 // zlib���o�[�W�������������� (2005.5.11 yutaka)
1607 #ifdef ZLIB_VERSION
1608 _snprintf(buf, sizeof(buf), "ZLib %s", ZLIB_VERSION);
1609 #else
1610 _snprintf(buf, sizeof(buf), "ZLib Unknown");
1611 #endif
1612 SendMessage(GetDlgItem(dlg, IDC_ZLIB_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1613
1614
1615 // TTSSH�_�C�A���O���\������SSH������������ (2004.10.30 yutaka)
1616 if (pvar->socket != INVALID_SOCKET) {
1617 if (SSHv1(pvar)) {
1618 SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1619 append_about_text(dlg, "Server ID: ", buf);
1620 SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1621 append_about_text(dlg, "Using protocol: ", buf);
1622 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1623 append_about_text(dlg, "Encryption: ", buf);
1624 CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1625 append_about_text(dlg, "Server keys: ", buf);
1626 AUTH_get_auth_info(pvar, buf, sizeof(buf));
1627 append_about_text(dlg, "Authentication: ", buf);
1628 SSH_get_compression_info(pvar, buf, sizeof(buf));
1629 append_about_text(dlg, "Compression: ", buf);
1630
1631 } else { // SSH2
1632 SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1633 append_about_text(dlg, "Server ID: ", buf);
1634
1635 append_about_text(dlg, "Client ID: ", pvar->client_version_string);
1636
1637 SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1638 append_about_text(dlg, "Using protocol: ", buf);
1639
1640 if (pvar->kex_type == KEX_DH_GRP1_SHA1) {
1641 strcpy(buf, KEX_DH1);
1642 } else if (pvar->kex_type == KEX_DH_GRP14_SHA1) {
1643 strcpy(buf, KEX_DH14);
1644 } else {
1645 strcpy(buf, KEX_DHGEX);
1646 }
1647 append_about_text(dlg, "KEX: ", buf);
1648
1649 if (pvar->hostkey_type == KEY_DSA) {
1650 strcpy(buf, "ssh-dss");
1651 } else {
1652 strcpy(buf, "ssh-rsa");
1653 }
1654 append_about_text(dlg, "Host Key: ", buf);
1655
1656 // add HMAC algorithm (2004.12.17 yutaka)
1657 buf[0] = '\0';
1658 if (pvar->ctos_hmac == HMAC_SHA1) {
1659 strcat(buf, "hmac-sha1");
1660 } else if (pvar->ctos_hmac == HMAC_MD5) {
1661 strcat(buf, "hmac-md5");
1662 }
1663 strcat(buf, " to server, ");
1664 if (pvar->stoc_hmac == HMAC_SHA1) {
1665 strcat(buf, "hmac-sha1");
1666 } else if (pvar->stoc_hmac == HMAC_MD5) {
1667 strcat(buf, "hmac-md5");
1668 }
1669 strcat(buf, " from server");
1670 append_about_text(dlg, "HMAC: ", buf);
1671
1672 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1673 append_about_text(dlg, "Encryption: ", buf);
1674 CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1675 append_about_text(dlg, "Server keys: ", buf);
1676 AUTH_get_auth_info(pvar, buf, sizeof(buf));
1677 append_about_text(dlg, "Authentication: ", buf);
1678
1679 SSH_get_compression_info(pvar, buf, sizeof(buf));
1680 if (pvar->ctos_compression == COMP_DELAYED) { // �x���p�P�b�g���k������ (2006.6.23 yutaka)
1681 append_about_text(dlg, "Delayed Compression: ", buf);
1682 } else {
1683 append_about_text(dlg, "Compression: ", buf);
1684 }
1685
1686 }
1687 }
1688 }
1689
1690 static BOOL CALLBACK TTXAboutDlg(HWND dlg, UINT msg, WPARAM wParam,
1691 LPARAM lParam)
1692 {
1693 switch (msg) {
1694 case WM_INITDIALOG:
1695 init_about_dlg((PTInstVar) lParam, dlg);
1696 return TRUE;
1697 case WM_COMMAND:
1698 switch (LOWORD(wParam)) {
1699 case IDOK:
1700 EndDialog(dlg, 1);
1701 return TRUE;
1702 case IDCANCEL: /* there isn't a cancel button, but other Windows
1703 UI things can send this message */
1704 EndDialog(dlg, 0);
1705 return TRUE;
1706 }
1707 break;
1708 }
1709
1710 return FALSE;
1711 }
1712
1713 static char FAR *get_cipher_name(int cipher)
1714 {
1715 switch (cipher) {
1716 case SSH_CIPHER_NONE:
1717 return "<ciphers below this line are disabled>";
1718 case SSH_CIPHER_RC4:
1719 return "RC4";
1720 case SSH_CIPHER_3DES:
1721 return "3DES";
1722 case SSH_CIPHER_DES:
1723 return "DES";
1724 case SSH_CIPHER_IDEA:
1725 return "IDEA";
1726 case SSH_CIPHER_TSS:
1727 return "TSS";
1728 case SSH_CIPHER_BLOWFISH:
1729 return "Blowfish";
1730
1731 // for SSH2(yutaka)
1732 case SSH_CIPHER_AES128:
1733 return "AES128(SSH2)";
1734 case SSH_CIPHER_3DES_CBC:
1735 return "3DES-CBC(SSH2)";
1736
1737 default:
1738 return NULL;
1739 }
1740 }
1741
1742 static void set_move_button_status(HWND dlg)
1743 {
1744 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1745 int curPos = (int) SendMessage(cipherControl, LB_GETCURSEL, 0, 0);
1746 int maxPos = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0) - 1;
1747
1748 EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERUP), curPos > 0
1749 && curPos <= maxPos);
1750 EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERDOWN), curPos >= 0
1751 && curPos < maxPos);
1752 }
1753
1754 static void init_setup_dlg(PTInstVar pvar, HWND dlg)
1755 {
1756 HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1757 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1758 int i;
1759 int ch;
1760
1761 SendMessage(compressionControl, TBM_SETRANGE, TRUE, MAKELONG(0, 9));
1762 SendMessage(compressionControl, TBM_SETPOS, TRUE,
1763 pvar->settings.CompressionLevel);
1764
1765 normalize_cipher_order(pvar->settings.CipherOrder);
1766
1767 for (i = 0; pvar->settings.CipherOrder[i] != 0; i++) {
1768 int cipher = pvar->settings.CipherOrder[i] - '0';
1769 char FAR *name = get_cipher_name(cipher);
1770
1771 if (name != NULL) {
1772 SendMessage(cipherControl, LB_ADDSTRING, 0, (LPARAM) name);
1773 }
1774 }
1775
1776 SendMessage(cipherControl, LB_SETCURSEL, 0, 0);
1777 set_move_button_status(dlg);
1778
1779 for (i = 0; (ch = pvar->settings.KnownHostsFiles[i]) != 0 && ch != ';';
1780 i++) {
1781 }
1782 if (ch != 0) {
1783 pvar->settings.KnownHostsFiles[i] = 0;
1784 SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1785 pvar->settings.KnownHostsFiles);
1786 pvar->settings.KnownHostsFiles[i] = ch;
1787 SetDlgItemText(dlg, IDC_READONLYFILENAME,
1788 pvar->settings.KnownHostsFiles + i + 1);
1789 } else {
1790 SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1791 pvar->settings.KnownHostsFiles);
1792 }
1793
1794 // SSH2 HeartBeat(keep-alive)������ (2005.2.22 yutaka)
1795 {
1796 char buf[10];
1797 _snprintf(buf, sizeof(buf), "%d", pvar->settings.ssh_heartbeat_overtime);
1798 SetDlgItemText(dlg, IDC_HEARTBEAT_EDIT, buf);
1799 }
1800
1801 }
1802
1803 void get_teraterm_dir_relative_name(char FAR * buf, int bufsize,
1804 char FAR * basename)
1805 {
1806 int filename_start = 0;
1807 int i;
1808 int ch;
1809
1810 if (basename[0] == '\\' || basename[0] == '/'
1811 || (basename[0] != 0 && basename[1] == ':')) {
1812 strncpy(buf, basename, bufsize);
1813 buf[bufsize - 1] = 0;
1814 return;
1815 }
1816
1817 GetModuleFileName(NULL, buf, bufsize);
1818 for (i = 0; (ch = buf[i]) != 0; i++) {
1819 if (ch == '\\' || ch == '/' || ch == ':') {
1820 filename_start = i + 1;
1821 }
1822 }
1823
1824 if (bufsize > filename_start) {
1825 strncpy(buf + filename_start, basename, bufsize - filename_start);
1826 }
1827 buf[bufsize - 1] = 0;
1828 }
1829
1830 int copy_teraterm_dir_relative_path(char FAR * dest, int destsize,
1831 char FAR * basename)
1832 {
1833 char buf[1024];
1834 int filename_start = 0;
1835 int i;
1836 int ch, ch2;
1837
1838 if (basename[0] != '\\' && basename[0] != '/'
1839 && (basename[0] == 0 || basename[1] != ':')) {
1840 strncpy(dest, basename, destsize);
1841 dest[destsize - 1] = 0;
1842 return strlen(dest);
1843 }
1844
1845 GetModuleFileName(NULL, buf, sizeof(buf));
1846 for (i = 0; (ch = buf[i]) != 0; i++) {
1847 if (ch == '\\' || ch == '/' || ch == ':') {
1848 filename_start = i + 1;
1849 }
1850 }
1851
1852 for (i = 0; i < filename_start; i++) {
1853 ch = toupper(buf[i]);
1854 ch2 = toupper(basename[i]);
1855
1856 if (ch == ch2
1857 || ((ch == '\\' || ch == '/')
1858 && (ch2 == '\\' || ch2 == '/'))) {
1859 } else {
1860 break;
1861 }
1862 }
1863
1864 if (i == filename_start) {
1865 strncpy(dest, basename + i, destsize);
1866 } else {
1867 strncpy(dest, basename, destsize);
1868 }
1869 dest[destsize - 1] = 0;
1870 return strlen(dest);
1871 }
1872
1873 static void complete_setup_dlg(PTInstVar pvar, HWND dlg)
1874 {
1875 char buf[4096];
1876 char buf2[1024];
1877 HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1878 HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1879 int i, j, buf2index, bufindex;
1880 int count = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0);
1881
1882 pvar->settings.CompressionLevel =
1883 (int) SendMessage(compressionControl, TBM_GETPOS, 0, 0);
1884
1885 buf2index = 0;
1886 for (i = 0; i < count; i++) {
1887 int len = SendMessage(cipherControl, LB_GETTEXTLEN, i, 0);
1888
1889 if (len > 0 && len < sizeof(buf)) { /* should always be true */
1890 buf[0] = 0;
1891 SendMessage(cipherControl, LB_GETTEXT, i, (LPARAM) buf);
1892 for (j = 0;
1893 j <= SSH_CIPHER_MAX
1894 && strcmp(buf, get_cipher_name(j)) != 0; j++) {
1895 }
1896 if (j <= SSH_CIPHER_MAX) {
1897 buf2[buf2index] = '0' + j;
1898 buf2index++;
1899 }
1900 }
1901 }
1902 buf2[buf2index] = 0;
1903 normalize_cipher_order(buf2);
1904 strcpy(pvar->settings.CipherOrder, buf2);
1905
1906 buf[0] = 0;
1907 GetDlgItemText(dlg, IDC_READWRITEFILENAME, buf, sizeof(buf));
1908 j = copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles,
1909 sizeof(pvar->settings.
1910 KnownHostsFiles), buf);
1911 buf[0] = 0;
1912 bufindex = 0;
1913 GetDlgItemText(dlg, IDC_READONLYFILENAME, buf, sizeof(buf));
1914 for (i = 0; buf[i] != 0; i++) {
1915 if (buf[i] == ';') {
1916 buf[i] = 0;
1917 if (j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1918 pvar->settings.KnownHostsFiles[j] = ';';
1919 j++;
1920 j += copy_teraterm_dir_relative_path(pvar->settings.
1921 KnownHostsFiles + j,
1922 sizeof(pvar->settings.
1923 KnownHostsFiles)
1924 - j, buf + bufindex);
1925 }
1926 bufindex = i + 1;
1927 }
1928 }
1929 if (bufindex < i && j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1930 pvar->settings.KnownHostsFiles[j] = ';';
1931 j++;
1932 copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles + j,
1933 sizeof(pvar->settings.
1934 KnownHostsFiles) - j,
1935 buf + bufindex);
1936 }
1937
1938 // get SSH HeartBeat(keep-alive)
1939 SendMessage(GetDlgItem(dlg, IDC_HEARTBEAT_EDIT), WM_GETTEXT, sizeof(buf), (LPARAM)buf);
1940 i = atoi(buf);
1941 if (i < 0)
1942 i = 60;
1943 pvar->settings.ssh_heartbeat_overtime = i;
1944
1945 }
1946
1947 static void move_cur_sel_delta(HWND listbox, int delta)
1948 {
1949 int curPos = (int) SendMessage(listbox, LB_GETCURSEL, 0, 0);
1950 int maxPos = (int) SendMessage(listbox, LB_GETCOUNT, 0, 0) - 1;
1951 int newPos = curPos + delta;
1952 char buf[1024];
1953
1954 if (curPos >= 0 && newPos >= 0 && newPos <= maxPos) {
1955 int len = SendMessage(listbox, LB_GETTEXTLEN, curPos, 0);
1956
1957 if (len > 0 && len < sizeof(buf)) { /* should always be true */
1958 buf[0] = 0;
1959 SendMessage(listbox, LB_GETTEXT, curPos, (LPARAM) buf);
1960 SendMessage(listbox, LB_DELETESTRING, curPos, 0);
1961 SendMessage(listbox, LB_INSERTSTRING, newPos,
1962 (LPARAM) (char FAR *) buf);
1963 SendMessage(listbox, LB_SETCURSEL, newPos, 0);
1964 }
1965 }
1966 }
1967
1968 static int get_keys_file_name(HWND parent, char FAR * buf, int bufsize,
1969 int readonly)
1970 {
1971 #ifdef TERATERM32
1972 OPENFILENAME params;
1973 char fullname_buf[2048] = "ssh_known_hosts";
1974
1975 params.lStructSize = sizeof(OPENFILENAME);
1976 params.hwndOwner = parent;
1977 params.lpstrFilter = NULL;
1978 params.lpstrCustomFilter = NULL;
1979 params.nFilterIndex = 0;
1980 buf[0] = 0;
1981 params.lpstrFile = fullname_buf;
1982 params.nMaxFile = sizeof(fullname_buf);
1983 params.lpstrFileTitle = NULL;
1984 params.lpstrInitialDir = NULL;
1985 params.lpstrTitle =
1986 readonly ? "Choose a read-only known-hosts file to add" :
1987 "Choose a read/write known-hosts file";
1988 params.Flags = (readonly ? OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST : 0)
1989 | OFN_HIDEREADONLY | (!readonly ? OFN_NOREADONLYRETURN : 0);
1990 params.lpstrDefExt = NULL;
1991
1992 if (GetOpenFileName(&params) != 0) {
1993 copy_teraterm_dir_relative_path(buf, bufsize, fullname_buf);
1994 return 1;
1995 } else {
1996 int err = CommDlgExtendedError();
1997
1998 if (err != 0) {
1999 char buf[1024];
2000
2001 _snprintf(buf, sizeof(buf),
2002 "Cannot show file dialog box: error %d", err);
2003 buf[sizeof(buf) - 1] = 0;
2004 MessageBox(parent, buf, "TTSSH Error",
2005 MB_OK | MB_ICONEXCLAMATION);
2006 }
2007
2008 return 0;
2009 }
2010 #else
2011 return 0;
2012 #endif
2013 }
2014
2015 static void choose_read_write_file(HWND dlg)
2016 {
2017 char buf[1024];
2018
2019 if (get_keys_file_name(dlg, buf, sizeof(buf), 0)) {
2020 SetDlgItemText(dlg, IDC_READWRITEFILENAME, buf);
2021 }
2022 }
2023
2024 static void choose_read_only_file(HWND dlg)
2025 {
2026 char buf[1024];
2027 char buf2[4096];
2028
2029 if (get_keys_file_name(dlg, buf, sizeof(buf), 1)) {
2030 buf2[0] = 0;
2031 GetDlgItemText(dlg, IDC_READONLYFILENAME, buf2, sizeof(buf2));
2032 if (buf2[0] != 0 && buf2[strlen(buf2) - 1] != ';') {
2033 strncat(buf2, ";", sizeof(buf2));
2034 }
2035 strncat(buf2, buf, sizeof(buf2));
2036 SetDlgItemText(dlg, IDC_READONLYFILENAME, buf2);
2037 }
2038 }
2039
2040 static BOOL CALLBACK TTXSetupDlg(HWND dlg, UINT msg, WPARAM wParam,
2041 LPARAM lParam)
2042 {
2043 switch (msg) {
2044 case WM_INITDIALOG:
2045 SetWindowLong(dlg, DWL_USER, lParam);
2046 init_setup_dlg((PTInstVar) lParam, dlg);
2047 return TRUE;
2048 case WM_COMMAND:
2049 switch (LOWORD(wParam)) {
2050 case IDOK:
2051 complete_setup_dlg((PTInstVar) GetWindowLong(dlg, DWL_USER),
2052 dlg);
2053 EndDialog(dlg, 1);
2054 return TRUE;
2055 case IDCANCEL: /* there isn't a cancel button, but other Windows
2056 UI things can send this message */
2057 EndDialog(dlg, 0);
2058 return TRUE;
2059 case IDC_SSHMOVECIPHERUP:
2060 move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), -1);
2061 set_move_button_status(dlg);
2062 SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
2063 return TRUE;
2064 case IDC_SSHMOVECIPHERDOWN:
2065 move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), 1);
2066 set_move_button_status(dlg);
2067 SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
2068 return TRUE;
2069 case IDC_SSHCIPHERPREFS:
2070 set_move_button_status(dlg);
2071 return TRUE;
2072 case IDC_CHOOSEREADWRITEFILE:
2073 choose_read_write_file(dlg);
2074 return TRUE;
2075 case IDC_CHOOSEREADONLYFILE:
2076 choose_read_only_file(dlg);
2077 return TRUE;
2078 }
2079 break;
2080 }
2081
2082 return FALSE;
2083 }
2084
2085
2086 //
2087 // SSH key generator dialog (2005.4.10 yutaka)
2088 //
2089
2090 typedef struct {
2091 RSA *rsa;
2092 DSA *dsa;
2093 } ssh_private_key_t;
2094
2095 static ssh_private_key_t private_key = {NULL, NULL};
2096
2097 typedef struct {
2098 RSA *rsa;
2099 DSA *dsa;
2100 } ssh_public_key_t;
2101
2102 static ssh_public_key_t public_key = {NULL, NULL};;
2103
2104 static void free_ssh_key(void)
2105 {
2106 // DSA_free(), RSA_free()��NULL���n�����������������B
2107 DSA_free(private_key.dsa);
2108 private_key.dsa = NULL;
2109 DSA_free(public_key.dsa);
2110 public_key.dsa = NULL;
2111
2112 RSA_free(private_key.rsa);
2113 private_key.rsa = NULL;
2114 RSA_free(public_key.rsa);
2115 public_key.rsa = NULL;
2116 }
2117
2118
2119 static BOOL generate_ssh_key(enum hostkey_type type)
2120 {
2121 int bits = 1024;
2122
2123 // if SSH key already is generated, should free the resource.
2124 free_ssh_key();
2125
2126 if (type == KEY_RSA1 || type == KEY_RSA) {
2127 RSA *priv = NULL;
2128 RSA *pub = NULL;
2129
2130 // private key
2131 priv = RSA_generate_key(bits, 35, NULL, NULL);
2132 if (priv == NULL)
2133 goto error;
2134 private_key.rsa = priv;
2135
2136 // public key
2137 pub = RSA_new();
2138 pub->n = BN_new();
2139 pub->e = BN_new();
2140 if (pub->n == NULL || pub->e == NULL) {
2141 RSA_free(pub);
2142 goto error;
2143 }
2144
2145 BN_copy(pub->n, priv->n);
2146 BN_copy(pub->e, priv->e);
2147 public_key.rsa = pub;
2148
2149 } else if (type == KEY_DSA) {
2150 DSA *priv = NULL;
2151 DSA *pub = NULL;
2152
2153 // private key
2154 priv = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
2155 if (priv == NULL)
2156 goto error;
2157 if (!DSA_generate_key(priv)) {
2158 // TODO: free 'priv'?
2159 goto error;
2160 }
2161 private_key.dsa = priv;
2162
2163 // public key
2164 pub = DSA_new();
2165 if (pub == NULL)
2166 goto error;
2167 pub->p = BN_new();
2168 pub->q = BN_new();
2169 pub->g = BN_new();
2170 pub->pub_key = BN_new();
2171 if (pub->p == NULL || pub->q == NULL || pub->g == NULL || pub->pub_key == NULL) {
2172 DSA_free(pub);
2173 goto error;
2174 }
2175
2176 BN_copy(pub->p, priv->p);
2177 BN_copy(pub->q, priv->q);
2178 BN_copy(pub->g, priv->g);
2179 BN_copy(pub->pub_key, priv->pub_key);
2180 public_key.dsa = pub;
2181
2182 } else {
2183 goto error;
2184 }
2185
2186 return TRUE;
2187
2188 error:
2189 free_ssh_key();
2190 return FALSE;
2191 }
2192
2193
2194 //
2195 // RC4
2196 //
2197
2198 /* Size of key to use */
2199 #define SEED_SIZE 20
2200
2201 /* Number of bytes to reseed after */
2202 #define REKEY_BYTES (1 << 24)
2203
2204 static int rc4_ready = 0;
2205 static RC4_KEY rc4;
2206
2207 static void seed_rng(void)
2208 {
2209 if (RAND_status() != 1)
2210 return;
2211 }
2212
2213 static void arc4random_stir(void)
2214 {
2215 unsigned char rand_buf[SEED_SIZE];
2216 int i;
2217
2218 memset(&rc4, 0, sizeof(rc4));
2219 if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0) {
2220 //fatal("Couldn't obtain random bytes (error %ld)",
2221 // ERR_get_error());
2222 }
2223 RC4_set_key(&rc4, sizeof(rand_buf), rand_buf);
2224
2225 /*
2226 * Discard early keystream, as per recommendations in:
2227 * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
2228 */
2229 for(i = 0; i <= 256; i += sizeof(rand_buf))
2230 RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf);
2231
2232 memset(rand_buf, 0, sizeof(rand_buf));
2233
2234 rc4_ready = REKEY_BYTES;
2235 }
2236
2237 static unsigned int arc4random(void)
2238 {
2239 unsigned int r = 0;
2240 static int first_time = 1;
2241
2242 if (rc4_ready <= 0) {
2243 if (first_time) {
2244 seed_rng();
2245 }
2246 first_time = 0;
2247 arc4random_stir();
2248 }
2249
2250 RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r);
2251
2252 rc4_ready -= sizeof(r);
2253
2254 return(r);
2255 }
2256
2257 //
2258 // SSH1 3DES
2259 //
2260 /*
2261 * This is used by SSH1:
2262 *
2263 * What kind of triple DES are these 2 routines?
2264 *
2265 * Why is there a redundant initialization vector?
2266 *
2267 * If only iv3 was used, then, this would till effect have been
2268 * outer-cbc. However, there is also a private iv1 == iv2 which
2269 * perhaps makes differential analysis easier. On the other hand, the
2270 * private iv1 probably makes the CRC-32 attack ineffective. This is a
2271 * result of that there is no longer any known iv1 to use when
2272 * choosing the X block.
2273 */
2274 struct ssh1_3des_ctx
2275 {
2276 EVP_CIPHER_CTX k1, k2, k3;
2277 };
2278
2279 static int ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, int enc)
2280 {
2281 struct ssh1_3des_ctx *c;
2282 u_char *k1, *k2, *k3;
2283
2284 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
2285 c = malloc(sizeof(*c));
2286 EVP_CIPHER_CTX_set_app_data(ctx, c);
2287 }
2288 if (key == NULL)
2289 return (1);
2290 if (enc == -1)
2291 enc = ctx->encrypt;
2292 k1 = k2 = k3 = (u_char *) key;
2293 k2 += 8;
2294 if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
2295 if (enc)
2296 k3 += 16;
2297 else
2298 k1 += 16;
2299 }
2300 EVP_CIPHER_CTX_init(&c->k1);
2301 EVP_CIPHER_CTX_init(&c->k2);
2302 EVP_CIPHER_CTX_init(&c->k3);
2303 if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
2304 EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
2305 EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
2306 memset(c, 0, sizeof(*c));
2307 free(c);
2308 EVP_CIPHER_CTX_set_app_data(ctx, NULL);
2309 return (0);
2310 }
2311 return (1);
2312 }
2313
2314 static int ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len)
2315 {
2316 struct ssh1_3des_ctx *c;
2317
2318 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
2319 //error("ssh1_3des_cbc: no context");
2320 return (0);
2321 }
2322 if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
2323 EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
2324 EVP_Cipher(&c->k3, dest, dest, len) == 0)
2325 return (0);
2326 return (1);
2327 }
2328
2329 static int ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
2330 {
2331 struct ssh1_3des_ctx *c;
2332
2333 if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
2334 EVP_CIPHER_CTX_cleanup(&c->k1);
2335 EVP_CIPHER_CTX_cleanup(&c->k2);
2336 EVP_CIPHER_CTX_cleanup(&c->k3);
2337 memset(c, 0, sizeof(*c));
2338 free(c);
2339 EVP_CIPHER_CTX_set_app_data(ctx, NULL);
2340 }
2341 return (1);
2342 }
2343
2344 void ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
2345 {
2346 struct ssh1_3des_ctx *c;
2347
2348 if (len != 24)
2349 //fatal("%s: bad 3des iv length: %d", __func__, len);
2350 ;
2351
2352 if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
2353 //fatal("%s: no 3des context", __func__);
2354 ;
2355
2356 if (doset) {
2357 //debug3("%s: Installed 3DES IV", __func__);
2358 memcpy(c->k1.iv, iv, 8);
2359 memcpy(c->k2.iv, iv + 8, 8);
2360 memcpy(c->k3.iv, iv + 16, 8);
2361 } else {
2362 //debug3("%s: Copying 3DES IV", __func__);
2363 memcpy(iv, c->k1.iv, 8);
2364 memcpy(iv + 8, c->k2.iv, 8);
2365 memcpy(iv + 16, c->k3.iv, 8);
2366 }
2367 }
2368
2369 const EVP_CIPHER *evp_ssh1_3des(void)
2370 {
2371 static EVP_CIPHER ssh1_3des;
2372
2373 memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
2374 ssh1_3des.nid = NID_undef;
2375 ssh1_3des.block_size = 8;
2376 ssh1_3des.iv_len = 0;
2377 ssh1_3des.key_len = 16;
2378 ssh1_3des.init = ssh1_3des_init;
2379 ssh1_3des.cleanup = ssh1_3des_cleanup;
2380 ssh1_3des.do_cipher = ssh1_3des_cbc;
2381 ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
2382 return (&ssh1_3des);
2383 }
2384
2385 static void ssh_make_comment(char *comment, int maxlen)
2386 {
2387 char user[UNLEN + 1], host[128];
2388 DWORD dwSize;
2389 WSADATA wsaData;
2390 int ret;
2391
2392 // get Windows logon user name
2393 dwSize = sizeof(user);
2394 if (GetUserName(user, &dwSize) == 0) {
2395 strcpy(user, "yutaka");
2396 }
2397
2398 // get local hostname (by WinSock)
2399 ret = WSAStartup(MAKEWORD(2,2), &wsaData);
2400 if (ret == 0) {
2401 if (gethostname(host, sizeof(host)) != 0) {
2402 ret = WSAGetLastError();
2403 }
2404 WSACleanup();
2405 }
2406 if (ret != 0) {
2407 strcpy(host, "sai");
2408 }
2409
2410 _snprintf(comment, maxlen, "%s@%s", user, host);
2411 }
2412
2413 // uuencode (rfc1521)
2414 int uuencode(unsigned char *src, int srclen, unsigned char *target, int targsize)
2415 {
2416 char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2417 char pad = '=';
2418 int datalength = 0;
2419 unsigned char input[3];
2420 unsigned char output[4];
2421 int i;
2422
2423 while (srclen > 2) {
2424 input[0] = *src++;
2425 input[1] = *src++;
2426 input[2] = *src++;
2427 srclen -= 3;
2428
2429 output[0] = input[0] >> 2;
2430 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
2431 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
2432 output[3] = input[2] & 0x3f;
2433 if (output[0] >= 64 ||
2434 output[1] >= 64 ||
2435 output[2] >= 64 ||
2436 output[3] >= 64)
2437 return -1;
2438
2439 if (datalength + 4 > targsize)
2440 return (-1);
2441 target[datalength++] = base64[output[0]];
2442 target[datalength++] = base64[output[1]];
2443 target[datalength++] = base64[output[2]];
2444 target[datalength++] = base64[output[3]];
2445 }
2446
2447 if (srclen != 0) {
2448 /* Get what's left. */
2449 input[0] = input[1] = input[2] = '\0';
2450 for (i = 0; i < srclen; i++)
2451 input[i] = *src++;
2452
2453 output[0] = input[0] >> 2;
2454 output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
2455 output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
2456 if (output[0] >= 64 ||
2457 output[1] >= 64 ||
2458 output[2] >= 64)
2459 return -1;
2460
2461 if (datalength + 4 > targsize)
2462 return (-1);
2463 target[datalength++] = base64[output[0]];
2464 target[datalength++] = base64[output[1]];
2465 if (srclen == 1)
2466 target[datalength++] = pad;
2467 else
2468 target[datalength++] = base64[output[2]];
2469 target[datalength++] = pad;
2470 }
2471 if (datalength >= targsize)
2472 return (-1);
2473 target[datalength] = '\0'; /* Returned value doesn't count \0. */
2474
2475 return (datalength); // success
2476 }
2477
2478 static BOOL CALLBACK TTXKeyGenerator(HWND dlg, UINT msg, WPARAM wParam,
2479 LPARAM lParam)
2480 {
2481 static enum hostkey_type key_type;
2482
2483 switch (msg) {
2484 case WM_INITDIALOG:
2485 {
2486 // default key type
2487 SendMessage(GetDlgItem(dlg, IDC_RSA_TYPE), BM_SETCHECK, BST_CHECKED, 0);
2488 key_type = KEY_RSA;
2489
2490 // passphrase edit box disabled(default)
2491 EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE);
2492 EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE);
2493
2494 // file saving dialog disabled(default)
2495 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE);
2496 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE);
2497
2498 }
2499 return TRUE;
2500
2501 case WM_COMMAND:
2502 switch (LOWORD(wParam)) {
2503 case IDOK: // key generate button pressed
2504 // passphrase edit box disabled(default)
2505 EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE);
2506 EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE);
2507
2508 // file saving dialog disabled(default)
2509 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE);
2510 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE);
2511
2512 if (generate_ssh_key(key_type)) {
2513 // passphrase edit box disabled(default)
2514 EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), TRUE);
2515 EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), TRUE);
2516
2517 // file saving dialog disabled(default)
2518 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), TRUE);
2519 EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), TRUE);
2520 }
2521 return TRUE;
2522
2523 case IDCANCEL:
2524 // don't forget to free SSH resource!
2525 free_ssh_key();
2526 EndDialog(dlg, 0); // dialog close
2527 return TRUE;
2528
2529 // if radio button pressed...
2530 case IDC_RSA1_TYPE | (BN_CLICKED << 16):
2531 key_type = KEY_RSA1;
2532 break;
2533
2534 case IDC_RSA_TYPE | (BN_CLICKED << 16):
2535 key_type = KEY_RSA;
2536 break;
2537
2538 case IDC_DSA_TYPE | (BN_CLICKED << 16):
2539 key_type = KEY_DSA;
2540 break;
2541
2542 // saving public key file
2543 case IDC_SAVE_PUBLIC_KEY:
2544 {
2545 int ret;
2546 OPENFILENAME ofn;
2547 char filename[MAX_PATH];
2548 FILE *fp;
2549 char comment[1024]; // comment string in private key
2550
2551 arc4random_stir();
2552
2553 // saving file dialog
2554 ZeroMemory(&ofn, sizeof(ofn));
2555 ofn.lStructSize = sizeof(ofn);
2556 ofn.hwndOwner = dlg;
2557 if (key_type == KEY_RSA1) {
2558 ofn.lpstrFilter = "SSH1 RSA key(identity.pub)\0identity.pub\0All Files(*.*)\0*.*\0\0";
2559 _snprintf(filename, sizeof(filename), "identity.pub");
2560 } else if (key_type == KEY_RSA) {
2561 ofn.lpstrFilter = "SSH2 RSA key(id_rsa.pub)\0id_rsa.pub\0All Files(*.*)\0*.*\0\0";
2562 _snprintf(filename, sizeof(filename), "id_rsa.pub");
2563 } else {
2564 ofn.lpstrFilter = "SSH2 DSA key(id_dsa.pub)\0id_dsa.pub\0All Files(*.*)\0*.*\0\0";
2565 _snprintf(filename, sizeof(filename), "id_dsa.pub");
2566 }
2567 ofn.lpstrFile = filename;
2568 ofn.nMaxFile = sizeof(filename);
2569 ofn.lpstrTitle = "Save public key as:";
2570 if (GetSaveFileName(&ofn) == 0) { // failure
2571 ret = CommDlgExtendedError();
2572 break;
2573 }
2574
2575 ssh_make_comment(comment, sizeof(comment));
2576
2577 // saving public key file
2578 fp = fopen(filename, "wb");
2579 if (fp == NULL) {
2580 MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2581 break;
2582 }
2583
2584 if (key_type == KEY_RSA1) { // SSH1 RSA
2585 RSA *rsa = public_key.rsa;
2586 int bits;
2587 char *buf;
2588
2589 bits = BN_num_bits(rsa->n);
2590 fprintf(fp, "%u", bits);
2591
2592 buf = BN_bn2dec(rsa->e);
2593 fprintf(fp, " %s", buf);
2594 OPENSSL_free(buf);
2595
2596 buf = BN_bn2dec(rsa->n);
2597 fprintf(fp, " %s", buf);
2598 OPENSSL_free(buf);
2599
2600 } else { // SSH2 RSA, DSA
2601 buffer_t *b;
2602 char *keyname;
2603 DSA *dsa = public_key.dsa;
2604 RSA *rsa = public_key.rsa;
2605 int len;
2606 char *blob;
2607 char *uuenc; // uuencode data
2608 int uulen;
2609
2610 b = buffer_init();
2611 if (b == NULL)
2612 goto public_error;
2613
2614 if (key_type == KEY_DSA) { // DSA
2615 keyname = "ssh-dss";
2616 buffer_put_string(b, keyname, strlen(keyname));
2617 buffer_put_bignum2(b, dsa->p);
2618 buffer_put_bignum2(b, dsa->q);
2619 buffer_put_bignum2(b, dsa->g);
2620 buffer_put_bignum2(b, dsa->pub_key);
2621
2622 } else { // RSA
2623 keyname = "ssh-rsa";
2624 buffer_put_string(b, keyname, strlen(keyname));
2625 buffer_put_bignum2(b, rsa->e);
2626 buffer_put_bignum2(b, rsa->n);
2627 }
2628
2629 blob = buffer_ptr(b);
2630 len = buffer_len(b);
2631 uuenc = malloc(len * 2);
2632 if (uuenc == NULL) {
2633 buffer_free(b);
2634 goto public_error;
2635 }
2636 uulen = uuencode(blob, len, uuenc, len * 2);
2637 if (uulen > 0) {
2638 fprintf(fp, "%s %s", keyname, uuenc);
2639 }
2640 free(uuenc);
2641 buffer_free(b);
2642 }
2643
2644 // writing a comment(+LF)
2645 fprintf(fp, " %s", comment);
2646 fputc(0x0a, fp);
2647
2648 public_error:
2649 fclose(fp);
2650
2651 }
2652 break;
2653
2654 // saving private key file
2655 case IDC_SAVE_PRIVATE_KEY:
2656 {
2657 char buf[1024], buf_conf[1024]; // passphrase
2658 int ret;
2659 OPENFILENAME ofn;
2660 char filename[MAX_PATH];
2661 char comment[1024]; // comment string in private key
2662
2663 // �p�X�t���[�Y���`�F�b�N���s���B�p�X�t���[�Y���������t�@�C�����t�����B
2664 SendMessage(GetDlgItem(dlg, IDC_KEY_EDIT), WM_GETTEXT, sizeof(buf), (LPARAM)buf);
2665 SendMessage(GetDlgItem(dlg, IDC_CONFIRM_EDIT), WM_GETTEXT, sizeof(buf_conf), (LPARAM)buf_conf);
2666
2667 // check matching
2668 if (strcmp(buf, buf_conf) != 0) {
2669 MessageBox(dlg, "Two passphrases don't match.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2670 break;
2671 }
2672
2673 // check empty-passphrase (this is warning level)
2674 if (buf[0] == '\0') {
2675 ret = MessageBox(dlg, "Are you sure that you want to use a empty passphrase?", "WARNING", MB_YESNO | MB_ICONWARNING);
2676 if (ret == IDNO)
2677 break;
2678 }
2679
2680 ssh_make_comment(comment, sizeof(comment));
2681
2682 // saving file dialog
2683 ZeroMemory(&ofn, sizeof(ofn));
2684 ofn.lStructSize = sizeof(ofn);
2685 ofn.hwndOwner = dlg;
2686 if (key_type == KEY_RSA1) {
2687 ofn.lpstrFilter = "SSH1 RSA key(identity)\0identity\0All Files(*.*)\0*.*\0\0";
2688 _snprintf(filename, sizeof(filename), "identity");
2689 } else if (key_type == KEY_RSA) {
2690 ofn.lpstrFilter = "SSH2 RSA key(id_rsa)\0id_rsa\0All Files(*.*)\0*.*\0\0";
2691 _snprintf(filename, sizeof(filename), "id_rsa");
2692 } else {
2693 ofn.lpstrFilter = "SSH2 DSA key(id_dsa)\0id_dsa\0All Files(*.*)\0*.*\0\0";
2694 _snprintf(filename, sizeof(filename), "id_dsa");
2695 }
2696 ofn.lpstrFile = filename;
2697 ofn.nMaxFile = sizeof(filename);
2698 ofn.lpstrTitle = "Save private key as:";
2699 if (GetSaveFileName(&ofn) == 0) { // failure
2700 ret = CommDlgExtendedError();
2701 break;
2702 }
2703
2704 // saving private key file
2705 if (key_type == KEY_RSA1) { // SSH1 RSA
2706 int cipher_num;
2707 buffer_t *b, *enc;
2708 unsigned int rnd;
2709 unsigned char tmp[128];
2710 RSA *rsa;
2711 int i, len;
2712 char authfile_id_string[] = "SSH PRIVATE KEY FILE FORMAT 1.1";
2713 MD5_CTX md;
2714 unsigned char digest[16];
2715 char *passphrase = buf;
2716 EVP_CIPHER_CTX cipher_ctx;
2717 FILE *fp;
2718 char wrapped[4096];
2719
2720 if (passphrase[0] == '\0') { // passphrase is empty
2721 cipher_num = SSH_CIPHER_NONE;
2722 } else {
2723 cipher_num = SSH_CIPHER_3DES; // 3DES-CBC
2724 }
2725
2726 b = buffer_init();
2727 if (b == NULL)
2728 break;
2729 enc = buffer_init();
2730 if (enc == NULL) {
2731 buffer_free(b);
2732 break;
2733 }
2734
2735 // set random value
2736 rnd = arc4random();
2737 tmp[0] = rnd & 0xff;
2738 tmp[1] = (rnd >> 8) & 0xff;
2739 tmp[2] = tmp[0];
2740 tmp[3] = tmp[1];
2741 buffer_append(b, tmp, 4);
2742
2743 // set private key
2744 rsa = private_key.rsa;
2745 buffer_put_bignum(b, rsa->d);
2746 buffer_put_bignum(b, rsa->iqmp);
2747 buffer_put_bignum(b, rsa->q);
2748 buffer_put_bignum(b, rsa->p);
2749
2750 // padding with 8byte align
2751 while (buffer_len(b) % 8) {
2752 buffer_put_char(b, 0);
2753 }
2754
2755 //
2756 // step(2)
2757 //
2758 // encrypted buffer
2759 /* First store keyfile id string. */
2760 for (i = 0 ; authfile_id_string[i] ; i++) {
2761 buffer_put_char(enc, authfile_id_string[i]);
2762 }
2763 buffer_put_char(enc, 0x0a); // LF
2764 buffer_put_char(enc, 0);
2765
2766 /* Store cipher type. */
2767 buffer_put_char(enc, cipher_num);
2768 buffer_put_int(enc, 0); // type is 'int'!! (For future extension)
2769
2770 /* Store public key. This will be in plain text. */
2771 buffer_put_int(enc, BN_num_bits(rsa->n));
2772 buffer_put_bignum(enc, rsa->n);
2773 buffer_put_bignum(enc, rsa->e);
2774 buffer_put_string(enc, comment, strlen(comment));
2775
2776 // setup the MD5ed passphrase to cipher encryption key
2777 MD5_Init(&md);
2778 MD5_Update(&md, (const unsigned char *)passphrase, strlen(passphrase));
2779 MD5_Final(digest, &md);
2780 if (cipher_num == SSH_CIPHER_NONE) {
2781 cipher_init_SSH2(&cipher_ctx, digest, 16, NULL, 0, CIPHER_ENCRYPT, EVP_enc_null);
2782 } else {
2783 cipher_init_SSH2(&cipher_ctx, digest, 16, NULL, 0, CIPHER_ENCRYPT, evp_ssh1_3des);
2784 }
2785 len = buffer_len(b);
2786 if (len % 8) { // fatal error
2787 goto error;
2788 }
2789
2790 // check buffer overflow
2791 if (buffer_overflow_verify(enc, len) && (sizeof(wrapped) < len)) {
2792 goto error;
2793 }
2794
2795 if (EVP_Cipher(&cipher_ctx, wrapped, buffer_ptr(b), len) == 0) {
2796 goto error;
2797 }
2798 if (EVP_CIPHER_CTX_cleanup(&cipher_ctx) == 0) {
2799 goto error;
2800 }
2801
2802 buffer_append(enc, wrapped, len);
2803
2804 // saving private key file (binary mode)
2805 fp = fopen(filename, "wb");
2806 if (fp == NULL) {
2807 MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2808 break;
2809 }
2810 fwrite(buffer_ptr(enc), buffer_len(enc), 1, fp);
2811
2812 fclose(fp);
2813
2814 error:;
2815 buffer_free(b);
2816 buffer_free(enc);
2817
2818 } else { // SSH2 RSA, DSA
2819 int len;
2820 FILE *fp;
2821 const EVP_CIPHER *cipher;
2822
2823 len = strlen(buf);
2824 // TODO: range check (len >= 4)
2825
2826 cipher = NULL;
2827 if (len > 0) {
2828 cipher = EVP_des_ede3_cbc();
2829 }
2830
2831 fp = fopen(filename, "w");
2832 if (fp == NULL) {
2833 MessageBox(dlg, "Can't open key file", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2834 break;
2835 }
2836
2837 if (key_type == KEY_RSA) { // RSA
2838 ret = PEM_write_RSAPrivateKey(fp, private_key.rsa, cipher, buf, len, NULL, NULL);
2839 } else { // DSA
2840 ret = PEM_write_DSAPrivateKey(fp, private_key.dsa, cipher, buf, len, NULL, NULL);
2841 }
2842 if (ret == 0) {
2843 MessageBox(dlg, "Can't write key file", "ERROR", MB_OK | MB_ICONEXCLAMATION);
2844 }
2845 fclose(fp);
2846 }
2847
2848
2849 }
2850 break;
2851
2852 }
2853 break;
2854 }
2855
2856 return FALSE;
2857 }
2858
2859
2860 static int PASCAL FAR TTXProcessCommand(HWND hWin, WORD cmd)
2861 {
2862 GET_VAR();
2863
2864 if (pvar->fatal_error) {
2865 return 0;
2866 }
2867
2868 switch (cmd) {
2869 case ID_SSHKEYGENMENU:
2870 if (DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHKEYGEN), hWin, TTXKeyGenerator,
2871 (LPARAM) pvar) == -1) {
2872 MessageBox(hWin, "Cannot create Key Generator window.",
2873 "TTSSH Error", MB_OK | MB_ICONEXCLAMATION);
2874 }
2875 return 1;
2876
2877 case ID_ABOUTMENU:
2878 if (DialogBoxParam
2879 (hInst, MAKEINTRESOURCE(IDD_ABOUTDIALOG), hWin, TTXAboutDlg,
2880 (LPARAM) pvar)
2881 == -1) {
2882 MessageBox(hWin, "Cannot create About box window.",
2883 "TTSSH Error", MB_OK | MB_ICONEXCLAMATION);
2884 }
2885 return 1;
2886 case ID_SSHAUTH:
2887 AUTH_do_cred_dialog(pvar);
2888 return 1;
2889 case ID_SSHSETUPMENU:
2890 if (DialogBoxParam
2891 (hInst, MAKEINTRESOURCE(IDD_SSHSETUP), hWin, TTXSetupDlg,
2892 (LPARAM) pvar)
2893 == -1) {
2894 MessageBox(hWin, "Cannot create TTSSH Setup window.",
2895 "TTSSH Error", MB_OK | MB_ICONEXCLAMATION);
2896 }
2897 return 1;
2898 case ID_SSHAUTHSETUPMENU:
2899 AUTH_do_default_cred_dialog(pvar);
2900 return 1;
2901 case ID_SSHFWDSETUPMENU:
2902 FWDUI_do_forwarding_dialog(pvar);
2903 return 1;
2904 case ID_SSHUNKNOWNHOST:
2905 HOSTS_do_unknown_host_dialog(hWin, pvar);
2906 return 1;
2907 case ID_SSHDIFFERENTHOST:
2908 HOSTS_do_different_host_dialog(hWin, pvar);
2909 return 1;
2910 case ID_SSHASYNCMESSAGEBOX:
2911 if (pvar->err_msg != NULL) {
2912 char FAR *msg = pvar->err_msg;
2913
2914 /* Could there be a buffer overrun bug anywhere in Win32
2915 MessageBox? Who knows? I'm paranoid. */
2916 if (strlen(msg) > 2048) {
2917 msg[2048] = 0;
2918 }
2919
2920 pvar->showing_err = TRUE;
2921 pvar->err_msg = NULL;
2922 #if 1
2923 // XXX: "SECURITY WARINIG" dialog�� ESC �L�[�������������A
2924 // �������A�v���P�[�V�����G���[�����������A���LAPI�������B(2004.12.16 yutaka)
2925 if (!SSHv1(pvar)) {
2926 MessageBox(NULL, msg, "TTSSH",
2927 MB_TASKMODAL | MB_ICONEXCLAMATION);
2928 }
2929 #else
2930 MessageBox(NULL, msg, "TTSSH",
2931 MB_TASKMODAL | MB_ICONEXCLAMATION);
2932 #endif
2933 free(msg);
2934 pvar->showing_err = FALSE;
2935
2936 if (pvar->err_msg != NULL) {
2937 PostMessage(hWin, WM_COMMAND, ID_SSHASYNCMESSAGEBOX, 0);
2938 } else {
2939 AUTH_notify_end_error(pvar);
2940 }
2941 }
2942 return 1;
2943 default:
2944 return 0;
2945 }
2946 }
2947
2948
2949 // ������TeraTerm Menu���R�[�h(ttpmenu.cpp)�������B
2950 // ������ @ ���u���������B@���g��@@�������B(2005.1.28 yutaka)
2951 static void replace_blank_to_mark(char *str, char *dst, int dst_len)
2952 {
2953 int i, len, n;
2954
2955 len = strlen(str);
2956 n = 0;
2957 for (i = 0 ; i < len ; i++) {
2958 if (str[i] == '@')
2959 n++;
2960 }
2961 if (dst_len < (len + 2*n))
2962 return;
2963
2964 for (i = 0 ; i < len ; i++) {
2965 if (str[i] == '@') {
2966 *dst++ = '@';
2967 *dst++ = '@';
2968
2969 } else if (str[i] == ' ') {
2970 *dst++ = '@';
2971
2972 } else {
2973 *dst++ = str[i];
2974
2975 }
2976 }
2977 *dst = '\0';
2978
2979 }
2980
2981 static void PASCAL FAR TTXSetCommandLine(PCHAR cmd, int cmdlen,
2982 PGetHNRec rec)
2983 {
2984 char tmpFile[MAX_PATH];
2985 char tmpPath[1024];
2986 char buf[1024];
2987 int i;
2988 GET_VAR();
2989
2990 GetTempPath(sizeof(tmpPath), tmpPath);
2991 GetTempFileName(tmpPath, "TTX", 0, tmpFile);
2992
2993 for (i = 0; cmd[i] != ' ' && cmd[i] != 0; i++) {
2994 }
2995
2996 if (i < cmdlen) {
2997 strncpy(buf, cmd + i, sizeof(buf));
2998 cmd[i] = 0;
2999
3000 write_ssh_options(pvar, tmpFile, &pvar->settings, FALSE);
3001
3002 strncat(cmd, " /ssh-consume=", cmdlen);
3003 strncat(cmd, tmpFile, cmdlen);
3004
3005 strncat(cmd, buf, cmdlen);
3006
3007 if (pvar->hostdlg_Enabled) {
3008 strncat(cmd, " /ssh", cmdlen);
3009
3010 // add option of SSH protcol version (2004.10.11 yutaka)
3011 if (pvar->settings.ssh_protocol_version == 2) {
3012 strncat(cmd, " /2", cmdlen);
3013 } else {
3014 strncat(cmd, " /1", cmdlen);
3015 }
3016
3017 }
3018
3019 // �Z�b�V�����������������A�������O�C���p�p�����[�^���t�����B(2005.4.8 yutaka)
3020 if (strstr(buf, "DUPLICATE")) {
3021 char mark[MAX_PATH];
3022 char tmp[MAX_PATH*2];
3023
3024 // �������O�C�������������L�t���O��0�������A�K�v���R�}���h���t�������B
3025 if (!pvar->hostdlg_Enabled) {
3026 _snprintf(tmp, sizeof(tmp), " /ssh /%d", pvar->settings.ssh_protocol_version);
3027 strncat(cmd, tmp, cmdlen);
3028 }
3029
3030 // �p�X���[�h���o�����������������A�R�}���h���C�����n���B(2006.8.3 yutaka)
3031 if (pvar->settings.remember_password &&
3032 pvar->auth_state.cur_cred.method == SSH_AUTH_PASSWORD) {
3033 replace_blank_to_mark(pvar->auth_state.cur_cred.password, mark, sizeof(mark));
3034 _snprintf(tmp, sizeof(tmp), " /auth=password /user=%s /passwd=%s", pvar->auth_state.user, mark);
3035 strncat(cmd, tmp, cmdlen);
3036
3037 } else if (pvar->settings.remember_password &&
3038 pvar->auth_state.cur_cred.method == SSH_AUTH_RSA) {
3039 replace_blank_to_mark(pvar->auth_state.cur_cred.password, mark, sizeof(mark));
3040 _snprintf(tmp, sizeof(tmp), " /auth=publickey /user=%s /passwd=%s", pvar->auth_state.user, mark);
3041 strncat(cmd, tmp, cmdlen);
3042
3043 replace_blank_to_mark(pvar->session_settings.DefaultRSAPrivateKeyFile, mark, sizeof(mark));
3044 _snprintf(tmp, sizeof(tmp), " /keyfile=%s", mark);
3045 strncat(cmd, tmp, cmdlen);
3046
3047 } else if (pvar->auth_state.cur_cred.method == SSH_AUTH_TIS) {
3048 // keyboard-interactive�F���������������������B
3049
3050 } else {
3051 // don't come here
3052
3053 }
3054
3055 }
3056
3057 }
3058 }
3059
3060 /* This function is called when Teraterm is quitting. You can use it to clean
3061 up.
3062
3063 This function is called for each extension, in reverse load order (see
3064 below).