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 2850 - (show annotations) (download) (as text)
Sat Feb 18 07:37:02 2006 UTC (18 years, 1 month ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 85424 byte(s)
  ・コンパイラを Visual Studio 2005 Standard Edition に切り替えた。
  ・stricmp()を_stricmp()へ置換した
  ・strdup()を_strdup()へ置換した

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