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 2896 - (show annotations) (download) (as text)
Wed Aug 9 09:13:49 2006 UTC (17 years, 8 months ago) by maya
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 87685 byte(s)
タイトルバーのアイコンに小さいアイコンが使用されていなかったのを修正した

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