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 2908 - (show annotations) (download) (as text)
Mon Sep 18 05:08:04 2006 UTC (17 years, 6 months ago) by maya
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 89979 byte(s)
コマンドラインパラメータ '/ask4passwd' を追加した。

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