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 2846 - (show annotations) (download) (as text)
Fri Oct 21 13:36:47 2005 UTC (18 years, 5 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 85041 byte(s)
接続ダイアログに History チェックボックスを追加した。
2.18へアップデート。

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