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