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 2897 - (show annotations) (download) (as text)
Wed Aug 9 15:13:17 2006 UTC (17 years, 8 months ago) by maya
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 87987 byte(s)
ttermpro.exe のアイコンハンドルを取得できない問題を修正した

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