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 2907 - (show annotations) (download) (as text)
Sat Sep 16 07:24:06 2006 UTC (17 years, 6 months ago) by maya
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 89577 byte(s)
/ssh1, /ssh2, /telnet オプションを追加した。

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