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 2891 - (show annotations) (download) (as text)
Sat Aug 5 03:47:49 2006 UTC (17 years, 8 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 87174 byte(s)
パスワードをメモリ上に覚えておくかどうかの設定は teraterm.ini に反映させるようにした。

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