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 2823 - (show annotations) (download) (as text)
Sun Jun 19 09:17:47 2005 UTC (18 years, 9 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 84214 byte(s)
SSH2 port-fowarding(local to remote)をサポートした。

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