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