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 2873 - (show annotations) (download) (as text)
Fri Jun 23 13:57:24 2006 UTC (17 years, 9 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 86352 byte(s)
TTSSH 2.28にて遅延パケット圧縮をサポートした。

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