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 2868 - (show annotations) (download) (as text)
Sun Jun 11 14:26:30 2006 UTC (17 years, 10 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 85997 byte(s)
SSH Port Forward の編集画面で、TeraTermが未接続状態の場合、ポート番号不正を即座にメッセージボックスが表示されないバグを修正した。

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