Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /branches/ssh_chacha20poly1305/ttssh2/ttxssh/ttxssh.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2821 - (hide annotations) (download) (as text)
Sun May 15 09:14:04 2005 UTC (18 years, 11 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 84137 byte(s)
zlib versionの位置調整。

1 yutakakn 2728 /*
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 yutakakn 2748 #include "ssh.h"
39 yutakakn 2728
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 yutakakn 2816 #include <Lmcons.h>
59    
60     // include OpenSSL header file
61 yutakakn 2782 #include <openssl/opensslv.h>
62 yutakakn 2816 #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 yutakakn 2782
70 yutakakn 2820 // include ZLib header file
71     #include <zlib.h>
72    
73 yutakakn 2816 #include "buffer.h"
74     #include "cipher.h"
75    
76 yutakakn 2728 #define MATCH_STR(s, o) _strnicmp((s), (o), NUM_ELEM(o) - 1)
77    
78     /* This extension implements SSH, so we choose a load order in the
79     "protocols" range. */
80     #define ORDER 2500
81    
82     #ifdef TERATERM32
83     static HICON SecureIcon = NULL;
84     #endif
85    
86     static TInstVar FAR *pvar;
87    
88     #ifdef TERATERM32
89     /* WIN32 allows multiple instances of a DLL */
90     static TInstVar InstVar;
91     #define GET_VAR()
92     #else
93     /* WIN16 does not allow multiple instances of a DLL */
94    
95     /* maximum number of Tera Term instances */
96     #define MAXNUMINST 32
97     /* list of task handles for Tera Term instances */
98     static HANDLE FAR TaskList[MAXNUMINST];
99     /* variable sets for instances */
100     static TInstVar FAR *FAR InstVar[MAXNUMINST];
101    
102     /* Here's how the TS settings work.
103     Whenever the TS settings are read or written to the INI file, then
104     the shared memory containing those settings is updated.
105     When Teraterm starts, the shared memory is read to initialize the TS
106     settings. */
107    
108     /* TS settings shared across instances */
109     static TS_SSH ts_SSH_settings;
110    
111    
112     extern void SSH2_update_cipher_myproposal(PTInstVar pvar);
113    
114    
115     static BOOL NewVar()
116     {
117     int i = 0;
118     HANDLE Task = GetCurrentTask();
119    
120     if (TaskList[0] == NULL)
121    
122     if (Task == NULL)
123     return FALSE;
124     while ((i < MAXNUMINST) && (TaskList[i] != NULL))
125     i++;
126     if (i >= MAXNUMINST)
127     return FALSE;
128     pvar = (TInstVar FAR *) malloc(sizeof(TInstVar));
129     InstVar[i] = pvar;
130     TaskList[i] = Task;
131     return TRUE;
132     }
133    
134     void DelVar()
135     {
136     int i = 0;
137     HANDLE Task = GetCurrentTask();
138    
139     if (Task == NULL)
140     return;
141     while ((i < MAXNUMINST) && (TaskList[i] != Task))
142     i++;
143     if (i >= MAXNUMINST)
144     return;
145     free(TaskList[i]);
146     TaskList[i] = NULL;
147     }
148    
149     BOOL GetVar()
150     {
151     int i = 0;
152     HANDLE Task = GetCurrentTask();
153    
154     if (Task == NULL)
155     return FALSE;
156     while ((i < MAXNUMINST) && (TaskList[i] != Task))
157     i++;
158     if (i >= MAXNUMINST)
159     return FALSE;
160     pvar = InstVar[i];
161     return TRUE;
162     }
163    
164     #define GET_VAR() if (!GetVar()) return
165     #endif
166    
167     /*
168     This code makes lots of assumptions about the order in which Teraterm
169     does things, and how. A key assumption is that the Notification window
170     passed into WSAAsyncSelect is the main terminal window. We also assume
171     that the socket used in the first WSAconnect is the main session socket.
172     */
173    
174     static void init_TTSSH(PTInstVar pvar)
175     {
176     pvar->socket = INVALID_SOCKET;
177     pvar->OldLargeIcon = NULL;
178     pvar->OldSmallIcon = NULL;
179     pvar->NotificationWindow = NULL;
180     pvar->hostdlg_activated = FALSE;
181     pvar->socket = INVALID_SOCKET;
182     pvar->NotificationWindow = NULL;
183     pvar->protocol_major = 0;
184     pvar->protocol_minor = 0;
185    
186     PKT_init(pvar);
187     SSH_init(pvar);
188     CRYPT_init(pvar);
189     AUTH_init(pvar);
190     HOSTS_init(pvar);
191     FWD_init(pvar);
192     FWDUI_init(pvar);
193 yutakakn 2748
194     ssh_heartbeat_lock_initialize();
195 yutakakn 2728 }
196    
197     static void uninit_TTSSH(PTInstVar pvar)
198     {
199 yutakakn 2766 halt_ssh_heartbeat_thread(pvar);
200    
201 yutakakn 2809 ssh2_channel_free();
202    
203 yutakakn 2728 SSH_end(pvar);
204     PKT_end(pvar);
205     AUTH_end(pvar);
206     CRYPT_end(pvar);
207     HOSTS_end(pvar);
208     FWD_end(pvar);
209     FWDUI_end(pvar);
210    
211     if (pvar->OldLargeIcon != NULL) {
212     PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_BIG,
213     (LPARAM) pvar->OldLargeIcon);
214     pvar->OldLargeIcon = NULL;
215     }
216     if (pvar->OldSmallIcon != NULL) {
217     PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_SMALL,
218     (LPARAM) pvar->OldSmallIcon);
219     pvar->OldSmallIcon = NULL;
220     }
221 yutakakn 2766
222     ssh_heartbeat_lock_finalize();
223 yutakakn 2728 }
224    
225     static void PASCAL FAR TTXInit(PTTSet ts, PComVar cv)
226     {
227     #ifndef TERATERM32
228     if (!NewVar())
229     return; /* should be called first */
230     pvar->ts_SSH = &ts_SSH_settings;
231     #endif
232     pvar->settings = *pvar->ts_SSH;
233     pvar->ts = ts;
234     pvar->cv = cv;
235     pvar->fatal_error = FALSE;
236     pvar->showing_err = FALSE;
237     pvar->err_msg = NULL;
238    
239     init_TTSSH(pvar);
240     }
241    
242     static void normalize_cipher_order(char FAR * buf)
243     {
244     char ciphers_listed[SSH_CIPHER_MAX + 1];
245     char ciphers_allowed[SSH_CIPHER_MAX + 1];
246     int i, j;
247    
248     /* SSH_CIPHER_NONE means that all ciphers below that one are disabled.
249     We *never* allow no encryption. */
250     #if 0
251     static char default_ciphers[] = {
252     SSH_CIPHER_3DES,
253     SSH_CIPHER_NONE,
254     SSH_CIPHER_DES, SSH_CIPHER_BLOWFISH
255     };
256     #else
257     // for SSH2(yutaka)
258     static char default_ciphers[] = {
259     SSH_CIPHER_AES128,
260     SSH_CIPHER_3DES_CBC,
261     SSH_CIPHER_3DES,
262     SSH_CIPHER_NONE,
263     SSH_CIPHER_DES, SSH_CIPHER_BLOWFISH
264     };
265     #endif
266    
267     memset(ciphers_listed, 0, sizeof(ciphers_listed));
268    
269     memset(ciphers_allowed, 0, sizeof(ciphers_allowed));
270     for (i = 0; i < NUM_ELEM(default_ciphers); i++) {
271     ciphers_allowed[default_ciphers[i]] = 1;
272     }
273    
274     for (i = 0; buf[i] != 0; i++) {
275     int cipher_num = buf[i] - '0';
276    
277     if (cipher_num < 0 || cipher_num > SSH_CIPHER_MAX
278     || !ciphers_allowed[cipher_num]
279     || ciphers_listed[cipher_num]) {
280     memmove(buf + i, buf + i + 1, strlen(buf + i + 1) + 1);
281     i--;
282     } else {
283     ciphers_listed[cipher_num] = 1;
284     }
285     }
286    
287     for (j = 0; j < NUM_ELEM(default_ciphers); j++) {
288     int cipher_num = default_ciphers[j];
289    
290     if (!ciphers_listed[cipher_num]) {
291     buf[i] = cipher_num + '0';
292     i++;
293     }
294     }
295    
296     buf[i] = 0;
297     }
298    
299     /* Remove local settings from the shared memory block. */
300     static void clear_local_settings(PTInstVar pvar)
301     {
302     pvar->ts_SSH->TryDefaultAuth = FALSE;
303     }
304    
305     static BOOL read_BOOL_option(PCHAR fileName, char FAR * keyName, BOOL def)
306     {
307     char buf[1024];
308    
309     buf[0] = 0;
310     GetPrivateProfileString("TTSSH", keyName, "", buf, sizeof(buf),
311     fileName);
312     if (buf[0] == 0) {
313     return def;
314     } else {
315     return atoi(buf) != 0 ||
316     stricmp(buf, "yes") == 0 || stricmp(buf, "y") == 0;
317     }
318     }
319    
320     static void read_string_option(PCHAR fileName, char FAR * keyName,
321     char FAR * def, char FAR * buf, int bufSize)
322     {
323    
324     buf[0] = 0;
325     GetPrivateProfileString("TTSSH", keyName, def, buf, bufSize, fileName);
326     }
327    
328     static void read_ssh_options(PTInstVar pvar, PCHAR fileName)
329     {
330     extern void SSH2_update_cipher_myproposal(PTInstVar pvar);
331     char buf[1024];
332     TS_SSH FAR *settings = pvar->ts_SSH;
333    
334     #define READ_STD_STRING_OPTION(name) \
335     read_string_option(fileName, #name, "", settings->name, sizeof(settings->name))
336    
337     settings->Enabled = read_BOOL_option(fileName, "Enabled", FALSE);
338    
339     buf[0] = 0;
340     GetPrivateProfileString("TTSSH", "Compression", "", buf, sizeof(buf),
341     fileName);
342     settings->CompressionLevel = atoi(buf);
343     if (settings->CompressionLevel < 0 || settings->CompressionLevel > 9) {
344     settings->CompressionLevel = 0;
345     }
346    
347     READ_STD_STRING_OPTION(DefaultUserName);
348     READ_STD_STRING_OPTION(DefaultForwarding);
349     READ_STD_STRING_OPTION(DefaultRhostsLocalUserName);
350     READ_STD_STRING_OPTION(DefaultRhostsHostPrivateKeyFile);
351     READ_STD_STRING_OPTION(DefaultRSAPrivateKeyFile);
352    
353     READ_STD_STRING_OPTION(CipherOrder);
354     normalize_cipher_order(settings->CipherOrder);
355     SSH2_update_cipher_myproposal(pvar); // yutaka
356    
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 yutakakn 2800 && settings->DefaultAuthMethod != SSH_AUTH_TIS // add (2005.3.12 yutaka)
368 yutakakn 2728 && 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 yutakakn 2738 // default is SSH2 (2004.11.30 yutaka)
394     settings->ssh_protocol_version = GetPrivateProfileInt("TTSSH", "ProtocolVersion", 2, fileName);
395 yutakakn 2728
396 yutakakn 2748 // SSH heartbeat time(second) (2004.12.11 yutaka)
397     settings->ssh_heartbeat_overtime = GetPrivateProfileInt("TTSSH", "HeartBeat", 60, fileName);
398    
399 yutakakn 2782 // SSH2 keyboard-interactive (2005.1.23 yutaka)
400 yutakakn 2799 // �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 yutakakn 2782
404 yutakakn 2728 clear_local_settings(pvar);
405     }
406    
407     static void write_ssh_options(PTInstVar pvar, PCHAR fileName,
408     TS_SSH FAR * settings)
409     {
410     char buf[1024];
411    
412     WritePrivateProfileString("TTSSH", "Enabled",
413     settings->Enabled ? "1" : "0", fileName);
414    
415     _itoa(settings->CompressionLevel, buf, 10);
416     WritePrivateProfileString("TTSSH", "Compression", buf, fileName);
417    
418     WritePrivateProfileString("TTSSH", "DefaultUserName",
419     settings->DefaultUserName, fileName);
420    
421     WritePrivateProfileString("TTSSH", "DefaultForwarding",
422     settings->DefaultForwarding, fileName);
423    
424     WritePrivateProfileString("TTSSH", "CipherOrder",
425     settings->CipherOrder, fileName);
426    
427     WritePrivateProfileString("TTSSH", "KnownHostsFiles",
428     settings->KnownHostsFiles, fileName);
429    
430     WritePrivateProfileString("TTSSH", "DefaultRhostsLocalUserName",
431     settings->DefaultRhostsLocalUserName,
432     fileName);
433    
434     WritePrivateProfileString("TTSSH", "DefaultRhostsHostPrivateKeyFile",
435     settings->DefaultRhostsHostPrivateKeyFile,
436     fileName);
437    
438     WritePrivateProfileString("TTSSH", "DefaultRSAPrivateKeyFile",
439     settings->DefaultRSAPrivateKeyFile,
440     fileName);
441    
442     _itoa(settings->DefaultAuthMethod, buf, 10);
443     WritePrivateProfileString("TTSSH", "DefaultAuthMethod", buf, fileName);
444    
445     _itoa(settings->LogLevel, buf, 10);
446     WritePrivateProfileString("TTSSH", "LogLevel", buf, fileName);
447    
448     _itoa(settings->WriteBufferSize, buf, 10);
449     WritePrivateProfileString("TTSSH", "WriteBufferSize", buf, fileName);
450    
451     WritePrivateProfileString("TTSSH", "LocalForwardingIdentityCheck",
452     settings->
453     LocalForwardingIdentityCheck ? "1" : "0",
454     fileName);
455    
456     // SSH protocol version (2004.10.11 yutaka)
457     WritePrivateProfileString("TTSSH", "ProtocolVersion",
458     settings->ssh_protocol_version==2 ? "2" : "1",
459     fileName);
460    
461 yutakakn 2748 // SSH heartbeat time(second) (2004.12.11 yutaka)
462     _snprintf(buf, sizeof(buf), "%d", settings->ssh_heartbeat_overtime);
463     WritePrivateProfileString("TTSSH", "HeartBeat", buf, fileName);
464    
465 yutakakn 2782 // SSH2 keyboard-interactive (2005.1.23 yutaka)
466     WritePrivateProfileString("TTSSH", "KeyboardInteractive",
467     settings->ssh2_keyboard_interactive ? "1" : "0",
468     fileName);
469    
470 yutakakn 2728 }
471    
472 yutakakn 2748
473 yutakakn 2728 /* find free port in all protocol family */
474     static unsigned short find_local_port(PTInstVar pvar)
475     {
476     int tries;
477     #ifdef INET6
478     SOCKET connecter;
479     struct addrinfo hints;
480     struct addrinfo FAR *res;
481     struct addrinfo FAR *res0;
482     unsigned short port;
483     char pname[NI_MAXHOST];
484     #endif /* INET6 */
485    
486     if (pvar->session_settings.DefaultAuthMethod != SSH_AUTH_RHOSTS) {
487     return 0;
488     }
489    
490     /* The random numbers here are only used to try to get fresh
491     ports across runs (dangling ports can cause bind errors
492     if we're unlucky). They do not need to be (and are not)
493     cryptographically strong.
494     */
495     srand((unsigned) GetTickCount());
496    
497     #ifdef INET6
498     for (tries = 20; tries > 0; tries--) {
499     memset(&hints, 0, sizeof(hints));
500     hints.ai_family = pvar->ts->ProtocolFamily;
501     hints.ai_flags = AI_PASSIVE;
502     hints.ai_socktype = SOCK_STREAM;
503     port = (unsigned) rand() % 512 + 512;
504     _snprintf(pname, sizeof(pname), "%d", (int) port);
505     if (getaddrinfo(NULL, pname, &hints, &res0)) {
506     return 0;
507     /* NOT REACHED */
508     }
509    
510     for (res = res0; res; res = res->ai_next) {
511     if (res->ai_family == AF_INET || res->ai_family == AF_INET6)
512     continue;
513    
514     connecter =
515     socket(res->ai_family, res->ai_socktype, res->ai_protocol);
516     if (connecter == INVALID_SOCKET) {
517     freeaddrinfo(res0);
518     return 0;
519     }
520    
521     if (bind(connecter, res->ai_addr, res->ai_addrlen) !=
522     SOCKET_ERROR) {
523     return port;
524     freeaddrinfo(res0);
525     closesocket(connecter);
526     } else if (WSAGetLastError() != WSAEADDRINUSE) {
527     closesocket(connecter);
528     freeaddrinfo(res0);
529     return 0;
530     }
531    
532     closesocket(connecter);
533     }
534     freeaddrinfo(res0);
535     }
536    
537     return 0;
538     #else
539     for (tries = 20; tries > 0; tries--) {
540     SOCKET connecter = socket(AF_INET, SOCK_STREAM, 0);
541     struct sockaddr_in connecter_addr;
542    
543     connecter_addr.sin_family = AF_INET;
544     connecter_addr.sin_port = (unsigned) rand() % 512 + 512;
545     connecter_addr.sin_addr.s_addr = htonl(INADDR_ANY);
546    
547     if (connecter == INVALID_SOCKET) {
548     return 0;
549     }
550    
551     if (bind
552     (connecter, (struct sockaddr FAR *) &connecter_addr,
553     sizeof(connecter_addr)) != SOCKET_ERROR) {
554     closesocket(connecter);
555     return connecter_addr.sin_port;
556     } else if (WSAGetLastError() != WSAEADDRINUSE) {
557     closesocket(connecter);
558     return 0;
559     }
560    
561     closesocket(connecter);
562     }
563    
564     return 0;
565     #endif /* INET6 */
566     }
567    
568     static int PASCAL FAR TTXconnect(SOCKET s,
569     const struct sockaddr FAR * name,
570     int namelen)
571     {
572     GET_VAR();
573    
574     #ifdef INET6
575     if (pvar->socket == INVALID_SOCKET) {
576     struct sockaddr_storage ss;
577     int len;
578    
579     pvar->socket = s;
580    
581     memset(&ss, 0, sizeof(ss));
582     switch (pvar->ts->ProtocolFamily) {
583     case AF_INET:
584     len = sizeof(struct sockaddr_in);
585     ((struct sockaddr_in FAR *) &ss)->sin_family = AF_INET;
586     ((struct sockaddr_in FAR *) &ss)->sin_addr.s_addr = INADDR_ANY;
587     ((struct sockaddr_in FAR *) &ss)->sin_port =
588     htons(find_local_port(pvar));
589     break;
590     case AF_INET6:
591     len = sizeof(struct sockaddr_in6);
592     ((struct sockaddr_in6 FAR *) &ss)->sin6_family = AF_INET6;
593     #if 0 /* symbol "in6addr_any" is not included in wsock32.lib */
594     /* if wsock32.lib will be linked, we can't refer "in6addr_any" */
595     ((struct sockaddr_in6 FAR *) &ss)->sin6_addr = in6addr_any;
596     #eles
597     memset(&((struct sockaddr_in6 FAR *) &ss)->sin6_addr, 0,
598     sizeof(struct in_addr6));
599     #endif /* 0 */
600     ((struct sockaddr_in6 FAR *) &ss)->sin6_port =
601     htons(find_local_port(pvar));
602     break;
603     default:
604     /* NOT REACHED */
605     break;
606     }
607    
608     bind(s, (struct sockaddr FAR *) &ss, len);
609     }
610     #else
611     if (pvar->socket == INVALID_SOCKET) {
612     struct sockaddr_in addr;
613    
614     pvar->socket = s;
615    
616     addr.sin_family = AF_INET;
617     addr.sin_port = htons(find_local_port(pvar));
618     addr.sin_addr.s_addr = INADDR_ANY;
619     memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
620    
621     bind(s, (struct sockaddr FAR *) &addr, sizeof(addr));
622     }
623     #endif /* INET6 */
624    
625     return (pvar->Pconnect) (s, name, namelen);
626     }
627    
628     static int PASCAL FAR TTXWSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
629     long lEvent)
630     {
631     GET_VAR();
632    
633     if (s == pvar->socket) {
634     pvar->notification_events = lEvent;
635     pvar->notification_msg = wMsg;
636    
637     if (pvar->NotificationWindow == NULL) {
638     pvar->NotificationWindow = hWnd;
639     AUTH_advance_to_next_cred(pvar);
640     }
641     }
642    
643     return (pvar->PWSAAsyncSelect) (s, hWnd, wMsg, lEvent);
644     }
645    
646     static int PASCAL FAR TTXrecv(SOCKET s, char FAR * buf, int len, int flags)
647     {
648     GET_VAR();
649    
650     if (s == pvar->socket) {
651 yutakakn 2748 int ret;
652    
653     ssh_heartbeat_lock();
654     ret = PKT_recv(pvar, buf, len);
655     ssh_heartbeat_unlock();
656     return (ret);
657    
658 yutakakn 2728 } else {
659     return (pvar->Precv) (s, buf, len, flags);
660     }
661     }
662    
663     static int PASCAL FAR TTXsend(SOCKET s, char const FAR * buf, int len,
664     int flags)
665     {
666     GET_VAR();
667    
668     if (s == pvar->socket) {
669 yutakakn 2748 ssh_heartbeat_lock();
670 yutakakn 2728 SSH_send(pvar, buf, len);
671 yutakakn 2748 ssh_heartbeat_unlock();
672 yutakakn 2728 return len;
673     } else {
674     return (pvar->Psend) (s, buf, len, flags);
675     }
676     }
677    
678     void notify_established_secure_connection(PTInstVar pvar)
679     {
680     #ifdef TERATERM32
681     if (SecureIcon == NULL) {
682     SecureIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_SECURETT));
683     }
684    
685     if (SecureIcon != NULL) {
686     pvar->OldSmallIcon =
687     (HICON) SendMessage(pvar->NotificationWindow, WM_GETICON,
688     ICON_SMALL, 0);
689     pvar->OldLargeIcon =
690     (HICON) SendMessage(pvar->NotificationWindow, WM_GETICON,
691     ICON_BIG, 0);
692     PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_BIG,
693     (LPARAM) SecureIcon);
694     PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_SMALL,
695     (LPARAM) SecureIcon);
696     }
697     #endif
698    
699     notify_verbose_message(pvar, "Entering secure mode",
700     LOG_LEVEL_VERBOSE);
701     }
702    
703     void notify_closed_connection(PTInstVar pvar)
704     {
705 yutakakn 2766 SSH_notify_disconnecting(pvar, NULL);
706     AUTH_notify_disconnecting(pvar);
707     HOSTS_notify_disconnecting(pvar);
708    
709 yutakakn 2728 PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
710     pvar->socket, MAKELPARAM(FD_CLOSE, 0));
711    
712     }
713    
714     static void add_err_msg(PTInstVar pvar, char FAR * msg)
715     {
716     if (pvar->err_msg != NULL) {
717     char FAR *buf =
718     (char FAR *) malloc(strlen(pvar->err_msg) + 3 + strlen(msg));
719    
720     strcpy(buf, pvar->err_msg);
721     strcat(buf, "\n\n");
722     strcat(buf, msg);
723     free(pvar->err_msg);
724     pvar->err_msg = buf;
725     } else {
726     pvar->err_msg = _strdup(msg);
727     }
728     }
729    
730     void notify_nonfatal_error(PTInstVar pvar, char FAR * msg)
731     {
732     if (!pvar->showing_err) {
733     PostMessage(pvar->NotificationWindow, WM_COMMAND,
734     ID_SSHASYNCMESSAGEBOX, 0);
735     }
736     if (msg[0] != 0) {
737     notify_verbose_message(pvar, msg, LOG_LEVEL_ERROR);
738     add_err_msg(pvar, msg);
739     }
740     }
741    
742     void notify_fatal_error(PTInstVar pvar, char FAR * msg)
743     {
744     if (msg[0] != 0) {
745     notify_verbose_message(pvar, msg, LOG_LEVEL_FATAL);
746     add_err_msg(pvar, msg);
747     }
748    
749     if (!pvar->fatal_error) {
750     pvar->fatal_error = TRUE;
751    
752     SSH_notify_disconnecting(pvar, msg);
753     AUTH_notify_disconnecting(pvar);
754     HOSTS_notify_disconnecting(pvar);
755    
756     PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
757     pvar->socket, MAKELPARAM(FD_CLOSE,
758     (pvar->PWSAGetLastError) ()));
759     }
760     }
761    
762     void notify_verbose_message(PTInstVar pvar, char FAR * msg, int level)
763     {
764     if (level <= pvar->session_settings.LogLevel) {
765     char buf[1024];
766     int file;
767    
768     get_teraterm_dir_relative_name(buf, NUM_ELEM(buf), "TTSSH.LOG");
769     file = _open(buf, _O_RDWR | _O_APPEND | _O_CREAT | _O_TEXT,
770     _S_IREAD | _S_IWRITE);
771    
772     if (file >= 0) {
773     _write(file, msg, strlen(msg));
774     _write(file, "\n", 1);
775     _close(file);
776     }
777     }
778     }
779    
780     static void PASCAL FAR TTXOpenTCP(TTXSockHooks FAR * hooks)
781     {
782     GET_VAR();
783    
784     if (pvar->settings.Enabled) {
785 yutakakn 2805 char buf[1024] = "\n---------------------------------------------------------------------\nInitiating SSH session at ";
786 yutakakn 2728 struct tm FAR *newtime;
787     time_t long_time;
788    
789     pvar->session_settings = pvar->settings;
790    
791     time(&long_time);
792     newtime = localtime(&long_time);
793     strcat(buf, asctime(newtime));
794     buf[strlen(buf) - 1] = 0;
795     notify_verbose_message(pvar, buf, LOG_LEVEL_VERBOSE);
796    
797     FWDUI_load_settings(pvar);
798    
799     pvar->cv->TelAutoDetect = FALSE;
800     /* This next line should not be needed because Teraterm's
801     CommLib should find ts->Telnet == 0 ... but we'll do this
802     just to be on the safe side. */
803     pvar->cv->TelFlag = FALSE;
804    
805     pvar->Precv = *hooks->Precv;
806     pvar->Psend = *hooks->Psend;
807     pvar->PWSAAsyncSelect = *hooks->PWSAAsyncSelect;
808     pvar->Pconnect = *hooks->Pconnect;
809     pvar->PWSAGetLastError = *hooks->PWSAGetLastError;
810    
811     *hooks->Precv = TTXrecv;
812     *hooks->Psend = TTXsend;
813     *hooks->PWSAAsyncSelect = TTXWSAAsyncSelect;
814     *hooks->Pconnect = TTXconnect;
815    
816     SSH_open(pvar);
817     HOSTS_open(pvar);
818     FWDUI_open(pvar);
819     }
820     }
821    
822     static void PASCAL FAR TTXCloseTCP(TTXSockHooks FAR * hooks)
823     {
824     GET_VAR();
825    
826     if (pvar->session_settings.Enabled) {
827     pvar->socket = INVALID_SOCKET;
828    
829     notify_verbose_message(pvar, "Terminating SSH session...",
830     LOG_LEVEL_VERBOSE);
831    
832     *hooks->Precv = pvar->Precv;
833     *hooks->Psend = pvar->Psend;
834     *hooks->PWSAAsyncSelect = pvar->PWSAAsyncSelect;
835     *hooks->Pconnect = pvar->Pconnect;
836     }
837    
838     uninit_TTSSH(pvar);
839     init_TTSSH(pvar);
840     }
841    
842     static void enable_dlg_items(HWND dlg, int from, int to, BOOL enabled)
843     {
844     for (; from <= to; from++) {
845     EnableWindow(GetDlgItem(dlg, from), enabled);
846     }
847     }
848    
849     static BOOL CALLBACK TTXHostDlg(HWND dlg, UINT msg, WPARAM wParam,
850     LPARAM lParam)
851     {
852     static char *ssh_version[] = {"SSH1", "SSH2", NULL};
853     PGetHNRec GetHNRec;
854     char EntName[7];
855     char TempHost[HostNameMaxLength + 1];
856     WORD i, j, w;
857     BOOL Ok;
858    
859     GET_VAR();
860    
861     switch (msg) {
862     case WM_INITDIALOG:
863     GetHNRec = (PGetHNRec) lParam;
864     SetWindowLong(dlg, DWL_USER, lParam);
865    
866     if (GetHNRec->PortType == IdFile)
867     GetHNRec->PortType = IdTCPIP;
868     CheckRadioButton(dlg, IDC_HOSTTCPIP, IDC_HOSTSERIAL,
869     IDC_HOSTTCPIP + GetHNRec->PortType - 1);
870    
871     strcpy(EntName, "Host");
872    
873     i = 1;
874     do {
875     sprintf(&EntName[4], "%d", i);
876     GetPrivateProfileString("Hosts", EntName, "",
877     TempHost, sizeof(TempHost),
878     GetHNRec->SetupFN);
879     if (strlen(TempHost) > 0)
880     SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_ADDSTRING,
881     0, (LPARAM) TempHost);
882     i++;
883     } while ((i <= 99) && (strlen(TempHost) > 0));
884    
885     SendDlgItemMessage(dlg, IDC_HOSTNAME, EM_LIMITTEXT,
886     HostNameMaxLength - 1, 0);
887    
888     SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_SETCURSEL, 0, 0);
889    
890     CheckRadioButton(dlg, IDC_HOSTTELNET, IDC_HOSTOTHER,
891     pvar->settings.Enabled ? IDC_HOSTSSH : GetHNRec->
892     Telnet ? IDC_HOSTTELNET : IDC_HOSTOTHER);
893     SendDlgItemMessage(dlg, IDC_HOSTTCPPORT, EM_LIMITTEXT, 5, 0);
894     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TCPPort, FALSE);
895     #ifdef INET6
896     for (i = 0; ProtocolFamilyList[i]; ++i) {
897     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_ADDSTRING,
898     0, (LPARAM) ProtocolFamilyList[i]);
899     }
900     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, EM_LIMITTEXT,
901     ProtocolFamilyMaxLength - 1, 0);
902     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_SETCURSEL, 0, 0);
903     #endif /* INET6 */
904    
905     /////// SSH version
906     for (i = 0; ssh_version[i]; ++i) {
907     SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_ADDSTRING,
908     0, (LPARAM) ssh_version[i]);
909     }
910     SendDlgItemMessage(dlg, IDC_SSH_VERSION, EM_LIMITTEXT,
911     NUM_ELEM(ssh_version) - 1, 0);
912    
913 yutakakn 2734 if (pvar->settings.ssh_protocol_version == 1) {
914     SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 0, 0); // SSH1
915     } else {
916 yutakakn 2728 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 1, 0); // SSH2
917     }
918    
919     if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
920     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE); // enabled
921     } else {
922     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
923     }
924     /////// SSH version
925    
926    
927     j = 0;
928     w = 1;
929     strcpy(EntName, "COM");
930     for (i = 1; i <= GetHNRec->MaxComPort; i++) {
931     sprintf(&EntName[3], "%d", i);
932     SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_ADDSTRING,
933     0, (LPARAM) EntName);
934     j++;
935     if (GetHNRec->ComPort == i)
936     w = j;
937     }
938     if (j > 0)
939     SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_SETCURSEL, w - 1, 0);
940     else /* All com ports are already used */
941     GetHNRec->PortType = IdTCPIP;
942    
943 yutakakn 2803 if (GetHNRec->PortType == IdTCPIP) {
944 yutakakn 2728 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
945 yutakakn 2803
946     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
947     enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, TRUE);
948     }
949 yutakakn 2728 #ifdef INET6
950     else {
951     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
952     FALSE);
953     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
954     IDC_HOSTTCPPROTOCOL, FALSE);
955 yutakakn 2803
956     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
957     enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, FALSE); // disabled (2004.11.23 yutaka)
958 yutakakn 2728 }
959     #else
960     else
961     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
962     FALSE);
963     #endif /* INET6 */
964    
965     // Host dialog���t�H�[�J�X�������� (2004.10.2 yutaka)
966 yutakakn 2803 if (GetHNRec->PortType == IdTCPIP) {
967     HWND hwnd = GetDlgItem(dlg, IDC_HOSTNAME);
968     SetFocus(hwnd);
969     } else {
970     HWND hwnd = GetDlgItem(dlg, IDC_HOSTCOM);
971     SetFocus(hwnd);
972 yutakakn 2728 }
973    
974 yutakakn 2734 // SetFocus()���t�H�[�J�X���������������AFALSE�������K�v�������B
975     // TRUE���������ATABSTOP�������������������R���g���[�����I�������B
976     // (2004.11.23 yutaka)
977     return FALSE;
978     //return TRUE;
979 yutakakn 2728
980     case WM_COMMAND:
981     switch (LOWORD(wParam)) {
982     case IDOK:
983     GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
984     if (GetHNRec != NULL) {
985     if (IsDlgButtonChecked(dlg, IDC_HOSTTCPIP)) {
986     #ifdef INET6
987     char afstr[BUFSIZ];
988     #endif /* INET6 */
989     i = GetDlgItemInt(dlg, IDC_HOSTTCPPORT, &Ok, FALSE);
990     if (Ok) {
991     GetHNRec->TCPPort = i;
992     } else {
993     MessageBox(dlg, "Teraterm",
994     "The TCP port must be a number.",
995     MB_OK | MB_ICONEXCLAMATION);
996     return TRUE;
997     }
998     #ifdef INET6
999     #define getaf(str) \
1000     ((strcmp((str), "IPv6") == 0) ? AF_INET6 : \
1001     ((strcmp((str), "IPv4") == 0) ? AF_INET : AF_UNSPEC))
1002     memset(afstr, 0, sizeof(afstr));
1003     GetDlgItemText(dlg, IDC_HOSTTCPPROTOCOL, afstr,
1004     sizeof(afstr));
1005     GetHNRec->ProtocolFamily = getaf(afstr);
1006     #endif /* INET6 */
1007     GetHNRec->PortType = IdTCPIP;
1008     GetDlgItemText(dlg, IDC_HOSTNAME, GetHNRec->HostName,
1009     HostNameMaxLength);
1010     GetHNRec->Telnet = FALSE;
1011     pvar->hostdlg_activated = TRUE;
1012     pvar->hostdlg_Enabled = FALSE;
1013     if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1014     GetHNRec->Telnet = TRUE;
1015     } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1016     pvar->hostdlg_Enabled = TRUE;
1017    
1018     // check SSH protocol version
1019     memset(afstr, 0, sizeof(afstr));
1020     GetDlgItemText(dlg, IDC_SSH_VERSION, afstr, sizeof(afstr));
1021     if (stricmp(afstr, "SSH1") == 0) {
1022     pvar->settings.ssh_protocol_version = 1;
1023     } else {
1024     pvar->settings.ssh_protocol_version = 2;
1025     }
1026     }
1027     } else {
1028     GetHNRec->PortType = IdSerial;
1029     GetHNRec->HostName[0] = 0;
1030     memset(EntName, 0, sizeof(EntName));
1031     GetDlgItemText(dlg, IDC_HOSTCOM, EntName,
1032     sizeof(EntName) - 1);
1033     GetHNRec->ComPort = (BYTE) (EntName[3]) - 0x30;
1034     if (strlen(EntName) > 4)
1035     GetHNRec->ComPort =
1036     GetHNRec->ComPort * 10 + (BYTE) (EntName[4]) -
1037     0x30;
1038     }
1039     }
1040     EndDialog(dlg, 1);
1041     return TRUE;
1042    
1043     case IDCANCEL:
1044     EndDialog(dlg, 0);
1045     return TRUE;
1046    
1047     case IDC_HOSTTCPIP:
1048     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1049     TRUE);
1050     #ifdef INET6
1051     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1052     IDC_HOSTTCPPROTOCOL, TRUE);
1053     #endif /* INET6 */
1054     enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
1055    
1056 yutakakn 2734 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, TRUE); // disabled (2004.11.23 yutaka)
1057 yutakakn 2728 if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1058     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
1059     } else {
1060     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1061     }
1062    
1063     return TRUE;
1064    
1065     case IDC_HOSTSERIAL:
1066     enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, TRUE);
1067     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1068     FALSE);
1069     #ifdef INET6
1070     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1071     IDC_HOSTTCPPROTOCOL, FALSE);
1072     #endif /* INET6 */
1073     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1074 yutakakn 2734 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, FALSE); // disabled (2004.11.23 yutaka)
1075 yutakakn 2728
1076     return TRUE;
1077    
1078     case IDC_HOSTSSH:
1079     enable_dlg_items(dlg, IDC_SSH_VERSION,
1080     IDC_SSH_VERSION, TRUE);
1081     goto hostssh_enabled;
1082    
1083     case IDC_HOSTTELNET:
1084     case IDC_HOSTOTHER:
1085     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1086     hostssh_enabled:
1087    
1088     GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
1089    
1090     if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1091     if (GetHNRec != NULL)
1092     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TelPort,
1093     FALSE);
1094     } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1095     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, 22, FALSE);
1096     }
1097     return TRUE;
1098    
1099     case IDC_HOSTHELP:
1100     PostMessage(GetParent(dlg), WM_USER_DLGHELP2, 0, 0);
1101     }
1102     }
1103     return FALSE;
1104     }
1105    
1106     static BOOL FAR PASCAL TTXGetHostName(HWND parent, PGetHNRec rec)
1107     {
1108     return (BOOL) DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_HOSTDLG),
1109     parent, TTXHostDlg, (LONG) rec);
1110     }
1111    
1112     static void PASCAL FAR TTXGetUIHooks(TTXUIHooks FAR * hooks)
1113     {
1114     GET_VAR();
1115    
1116     *hooks->GetHostName = TTXGetHostName;
1117     }
1118    
1119     static void FAR PASCAL TTXReadINIFile(PCHAR fileName, PTTSet ts)
1120     {
1121     GET_VAR();
1122    
1123     (pvar->ReadIniFile) (fileName, ts);
1124     read_ssh_options(pvar, fileName);
1125     pvar->settings = *pvar->ts_SSH;
1126     notify_verbose_message(pvar, "Reading INI file", LOG_LEVEL_VERBOSE);
1127     FWDUI_load_settings(pvar);
1128     }
1129    
1130     static void FAR PASCAL TTXWriteINIFile(PCHAR fileName, PTTSet ts)
1131     {
1132     GET_VAR();
1133    
1134     (pvar->WriteIniFile) (fileName, ts);
1135     *pvar->ts_SSH = pvar->settings;
1136     clear_local_settings(pvar);
1137     notify_verbose_message(pvar, "Writing INI file", LOG_LEVEL_VERBOSE);
1138     write_ssh_options(pvar, fileName, pvar->ts_SSH);
1139     }
1140    
1141     static void read_ssh_options_from_user_file(PTInstVar pvar,
1142     char FAR * user_file_name)
1143     {
1144     if (user_file_name[0] == '.') {
1145     read_ssh_options(pvar, user_file_name);
1146     } else {
1147     char buf[1024];
1148    
1149     get_teraterm_dir_relative_name(buf, sizeof(buf), user_file_name);
1150     read_ssh_options(pvar, buf);
1151     }
1152    
1153     pvar->settings = *pvar->ts_SSH;
1154     FWDUI_load_settings(pvar);
1155     }
1156    
1157 yutakakn 2784
1158     // @���u�����N���u�������B (2005.1.26 yutaka)
1159     static void replace_to_blank(char *src, char *dst, int dst_len)
1160     {
1161     int len, i;
1162    
1163     len = strlen(src);
1164     if (dst_len < len) // buffer overflow check
1165     return;
1166    
1167     for (i = 0 ; i < len ; i++) {
1168     if (src[i] == '@') { // @ ���o��������
1169     if (i < len - 1 && src[i + 1] == '@') { // �������� @ �����A�b�g�}�[�N���F������
1170     *dst++ = '@';
1171     i++;
1172     } else {
1173     *dst++ = ' '; // �������u��������
1174     }
1175     } else {
1176     *dst++ = src[i];
1177     }
1178     }
1179     *dst = '\0';
1180     }
1181    
1182 yutakakn 2728 /* returns 1 if the option text must be deleted */
1183     static int parse_option(PTInstVar pvar, char FAR * option)
1184     {
1185     if ((option[0] == '-' || option[0] == '/')) {
1186     if (MATCH_STR(option + 1, "ssh") == 0) {
1187     if (option[4] == 0) {
1188     pvar->settings.Enabled = 1;
1189     } else if (MATCH_STR(option + 4, "-L") == 0
1190     || MATCH_STR(option + 4, "-R") == 0
1191     || stricmp(option + 4, "-X") == 0) {
1192     if (pvar->settings.DefaultForwarding[0] == 0) {
1193     strcpy(pvar->settings.DefaultForwarding, option + 5);
1194     } else {
1195     strcat(pvar->settings.DefaultForwarding, ";");
1196     strcat(pvar->settings.DefaultForwarding, option + 5);
1197     }
1198     } else if (MATCH_STR(option + 4, "-f=") == 0) {
1199     read_ssh_options_from_user_file(pvar, option + 7);
1200     } else if (MATCH_STR(option + 4, "-v") == 0) {
1201     pvar->settings.LogLevel = LOG_LEVEL_VERBOSE;
1202     } else if (stricmp(option + 4, "-autologin") == 0
1203     || stricmp(option + 4, "-autologon") == 0) {
1204     pvar->settings.TryDefaultAuth = TRUE;
1205 yutakakn 2739
1206 yutakakn 2728 } else if (MATCH_STR(option + 4, "-consume=") == 0) {
1207     read_ssh_options_from_user_file(pvar, option + 13);
1208     DeleteFile(option + 13);
1209     } else {
1210     char buf[1024];
1211    
1212     _snprintf(buf, sizeof(buf),
1213     "Unrecognized command-line option: %s", option);
1214     buf[sizeof(buf) - 1] = 0;
1215    
1216     MessageBox(NULL, buf, "TTSSH", MB_OK | MB_ICONEXCLAMATION);
1217     }
1218    
1219     return 1;
1220     } else if (MATCH_STR(option + 1, "t=") == 0) {
1221     if (strcmp(option + 3, "2") == 0) {
1222     pvar->settings.Enabled = 1;
1223     return 1;
1224     } else {
1225     pvar->settings.Enabled = 0;
1226     }
1227     } else if (MATCH_STR(option + 1, "f=") == 0) {
1228     read_ssh_options_from_user_file(pvar, option + 3);
1229    
1230     // /1 ������ /2 �I�v�V�������V�K���� (2004.10.3 yutaka)
1231     } else if (MATCH_STR(option + 1, "1") == 0) {
1232     // command line: /ssh /1 is SSH1 only
1233     pvar->settings.ssh_protocol_version = 1;
1234    
1235     } else if (MATCH_STR(option + 1, "2") == 0) {
1236     // command line: /ssh /2 is SSH2 & SSH1
1237     pvar->settings.ssh_protocol_version = 2;
1238    
1239     } else if (MATCH_STR(option + 1, "nossh") == 0) {
1240     // '/nossh' �I�v�V�����������B
1241     // TERATERM.INI ��SSH���L�������������������A������Cygterm���N��������������
1242     // �����������������B(2004.10.11 yutaka)
1243     pvar->settings.Enabled = 0;
1244    
1245 yutakakn 2739 } else if (MATCH_STR(option + 1, "auth") == 0) {
1246 yutakakn 2784 // SSH2�������O�C���I�v�V����������
1247 yutakakn 2739 //
1248 yutakakn 2784 // SYNOPSIS: /ssh /auth=passowrd /user=���[�U�� /passwd=�p�X���[�h
1249     // /ssh /auth=publickey /user=���[�U�� /passwd=�p�X���[�h /keyfile=�p�X
1250     // EXAMPLE: /ssh /auth=password /user=nike /passwd=a@bc
1251     // /ssh /auth=publickey /user=foo /passwd=bar /keyfile=d:\tmp\id_rsa
1252     // NOTICE: �p�X���[�h���p�X�������������������A�u�����N���������� @ ���g�������B
1253 yutakakn 2739 //
1254 yutakakn 2784 // (2004.11.30 yutaka)
1255     // (2005.1.26 yutaka) ���������B���J���F���T�|�[�g�B
1256     //
1257 yutakakn 2739 pvar->ssh2_autologin = 1; // for SSH2 (2004.11.30 yutaka)
1258    
1259 yutakakn 2784 if (MATCH_STR(option + 5, "=password") == 0) { // �p�X���[�h/keyboard-interactive�F��
1260     //pvar->auth_state.cur_cred.method = SSH_AUTH_PASSWORD;
1261     pvar->ssh2_authmethod = SSH_AUTH_PASSWORD;
1262 yutakakn 2739
1263 yutakakn 2784 } else if (MATCH_STR(option + 5, "=publickey") == 0) { // ���J���F��
1264     //pvar->auth_state.cur_cred.method = SSH_AUTH_RSA;
1265     pvar->ssh2_authmethod = SSH_AUTH_RSA;
1266    
1267 yutakakn 2739 } else {
1268     // TODO:
1269    
1270     }
1271    
1272     } else if (MATCH_STR(option + 1, "user=") == 0) {
1273 yutakakn 2784 replace_to_blank(option + 6, pvar->ssh2_username, sizeof(pvar->ssh2_username));
1274     //_snprintf(pvar->ssh2_username, sizeof(pvar->ssh2_username), "%s", option + 6);
1275 yutakakn 2739
1276     } else if (MATCH_STR(option + 1, "passwd=") == 0) {
1277 yutakakn 2784 replace_to_blank(option + 8, pvar->ssh2_password, sizeof(pvar->ssh2_password));
1278     //_snprintf(pvar->ssh2_password, sizeof(pvar->ssh2_password), "%s", option + 8);
1279 yutakakn 2739
1280 yutakakn 2784 } else if (MATCH_STR(option + 1, "keyfile=") == 0) {
1281     replace_to_blank(option + 9, pvar->ssh2_keyfile, sizeof(pvar->ssh2_keyfile));
1282    
1283 yutakakn 2728 }
1284    
1285     }
1286    
1287     return 0;
1288     }
1289    
1290     static void FAR PASCAL TTXParseParam(PCHAR param, PTTSet ts,
1291     PCHAR DDETopic)
1292     {
1293     int i;
1294     BOOL inParam = FALSE;
1295     BOOL inQuotes = FALSE;
1296     PCHAR option = NULL;
1297     GET_VAR();
1298    
1299     if (pvar->hostdlg_activated) {
1300     pvar->settings.Enabled = pvar->hostdlg_Enabled;
1301     }
1302    
1303     for (i = 0; param[i] != 0; i++) {
1304     if (inQuotes ? param[i] ==
1305     '"' : (param[i] == ' ' || param[i] == '\t')) {
1306     if (option != NULL) {
1307     char ch = param[i];
1308    
1309     param[i] = 0;
1310     if (parse_option
1311     (pvar, *option == '"' ? option + 1 : option)) {
1312     memset(option, ' ', i + 1 - (option - param));
1313     } else {
1314     param[i] = ch;
1315     }
1316     option = NULL;
1317     }
1318     inParam = FALSE;
1319     inQuotes = FALSE;
1320     } else if (!inParam) {
1321     if (param[i] == '"') {
1322     inQuotes = TRUE;
1323     inParam = TRUE;
1324     option = param + i;
1325     } else if (param[i] != ' ' && param[i] != '\t') {
1326     inParam = TRUE;
1327     option = param + i;
1328     }
1329     }
1330     }
1331    
1332     if (option != NULL) {
1333     if (parse_option(pvar, option)) {
1334     memset(option, ' ', i - (option - param));
1335     }
1336     }
1337    
1338     FWDUI_load_settings(pvar);
1339    
1340     (pvar->ParseParam) (param, ts, DDETopic);
1341    
1342     }
1343    
1344     static void PASCAL FAR TTXGetSetupHooks(TTXSetupHooks FAR * hooks)
1345     {
1346     GET_VAR();
1347    
1348     pvar->ReadIniFile = *hooks->ReadIniFile;
1349     pvar->WriteIniFile = *hooks->WriteIniFile;
1350     pvar->ParseParam = *hooks->ParseParam;
1351    
1352     *hooks->ReadIniFile = TTXReadINIFile;
1353     *hooks->WriteIniFile = TTXWriteINIFile;
1354     *hooks->ParseParam = TTXParseParam;
1355     }
1356    
1357     static void PASCAL FAR TTXSetWinSize(int rows, int cols)
1358     {
1359     GET_VAR();
1360    
1361     SSH_notify_win_size(pvar, cols, rows);
1362     }
1363    
1364     static void insertMenuBeforeItem(HMENU menu, WORD beforeItemID, WORD flags,
1365     WORD newItemID, char FAR * text)
1366     {
1367     int i, j;
1368    
1369     for (i = GetMenuItemCount(menu) - 1; i >= 0; i--) {
1370     HMENU submenu = GetSubMenu(menu, i);
1371    
1372     for (j = GetMenuItemCount(submenu) - 1; j >= 0; j--) {
1373     if (GetMenuItemID(submenu, j) == beforeItemID) {
1374     InsertMenu(submenu, j, MF_BYPOSITION | flags, newItemID,
1375     text);
1376     return;
1377     }
1378     }
1379     }
1380     }
1381    
1382     static void PASCAL FAR TTXModifyMenu(HMENU menu)
1383     {
1384     GET_VAR();
1385    
1386     /* inserts before ID_HELP_ABOUT */
1387     insertMenuBeforeItem(menu, 50990, MF_ENABLED, ID_ABOUTMENU,
1388     "About &TTSSH...");
1389    
1390     /* inserts before ID_SETUP_TCPIP */
1391     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHSETUPMENU,
1392     "SS&H...");
1393     /* inserts before ID_SETUP_TCPIP */
1394     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHAUTHSETUPMENU,
1395     "SSH &Authentication...");
1396     /* inserts before ID_SETUP_TCPIP */
1397     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHFWDSETUPMENU,
1398     "SSH F&orwarding...");
1399 yutakakn 2816
1400     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHKEYGENMENU,
1401     "SSH KeyGenerator...");
1402 yutakakn 2728 }
1403    
1404     static void append_about_text(HWND dlg, char FAR * prefix, char FAR * msg)
1405     {
1406     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1407     (LPARAM) prefix);
1408     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0, (LPARAM) msg);
1409     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1410     (LPARAM) (char FAR *) "\r\n");
1411     }
1412    
1413 yutakakn 2792 // ���s�t�@�C�������o�[�W�������������� (2005.2.28 yutaka)
1414 yutakakn 2793 void get_file_version(char *exefile, int *major, int *minor, int *release, int *build)
1415 yutakakn 2792 {
1416     typedef struct {
1417     WORD wLanguage;
1418     WORD wCodePage;
1419     } LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
1420     LPLANGANDCODEPAGE lplgcode;
1421     UINT unLen;
1422     DWORD size;
1423     char *buf = NULL;
1424     BOOL ret;
1425     int i;
1426     char fmt[80];
1427     char *pbuf;
1428    
1429     size = GetFileVersionInfoSize(exefile, NULL);
1430     if (size == 0) {
1431     goto error;
1432     }
1433     buf = malloc(size);
1434     ZeroMemory(buf, size);
1435    
1436     if (GetFileVersionInfo(exefile, 0, size, buf) == FALSE) {
1437     goto error;
1438     }
1439    
1440     ret = VerQueryValue(buf,
1441     "\\VarFileInfo\\Translation",
1442     (LPVOID *)&lplgcode, &unLen);
1443     if (ret == FALSE)
1444     goto error;
1445    
1446     for (i = 0 ; i < (int)(unLen / sizeof(LANGANDCODEPAGE)) ; i++) {
1447     _snprintf(fmt, sizeof(fmt), "\\StringFileInfo\\%04x%04x\\FileVersion",
1448     lplgcode[i].wLanguage, lplgcode[i].wCodePage);
1449     VerQueryValue(buf, fmt, &pbuf, &unLen);
1450     if (unLen > 0) { // get success
1451     int n, a, b, c, d;
1452    
1453     n = sscanf(pbuf, "%d, %d, %d, %d", &a, &b, &c, &d);
1454     if (n == 4) { // convert success
1455     *major = a;
1456     *minor = b;
1457     *release = c;
1458     *build = d;
1459     break;
1460     }
1461     }
1462     }
1463    
1464     free(buf);
1465     return;
1466    
1467     error:
1468     free(buf);
1469     *major = *minor = *release = *build = 0;
1470     }
1471    
1472 yutakakn 2728 static void init_about_dlg(PTInstVar pvar, HWND dlg)
1473     {
1474     char buf[1024];
1475 yutakakn 2792 int a, b, c, d;
1476 yutakakn 2728
1477 yutakakn 2792 // TTSSH���o�[�W�������������� (2005.2.28 yutaka)
1478     get_file_version("ttxssh.dll", &a, &b, &c, &d);
1479     _snprintf(buf, sizeof(buf), "TTSSH\r\nTeraterm Secure Shell extension, %d.%d", a, b);
1480     SendMessage(GetDlgItem(dlg, IDC_TTSSH_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1481    
1482 yutakakn 2782 // OpenSSL���o�[�W�������������� (2005.1.24 yutaka)
1483 yutakakn 2820 // ���������� (2005.5.11 yutaka)
1484     #ifdef OPENSSL_VERSION_TEXT
1485 yutakakn 2782 SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)OPENSSL_VERSION_TEXT);
1486 yutakakn 2820 #else
1487     SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)"Unknown");
1488     #endif
1489 yutakakn 2782
1490 yutakakn 2820 // zlib���o�[�W�������������� (2005.5.11 yutaka)
1491     #ifdef ZLIB_VERSION
1492 yutakakn 2821 _snprintf(buf, sizeof(buf), "ZLib: %s", ZLIB_VERSION);
1493 yutakakn 2820 #else
1494 yutakakn 2821 _snprintf(buf, sizeof(buf), "ZLib: Unknown");
1495 yutakakn 2820 #endif
1496     SendMessage(GetDlgItem(dlg, IDC_ZLIB_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1497    
1498    
1499 yutakakn 2728 // TTSSH�_�C�A���O���\������SSH������������ (2004.10.30 yutaka)
1500     if (pvar->socket != INVALID_SOCKET) {
1501     if (SSHv1(pvar)) {
1502     SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1503     append_about_text(dlg, "Server ID: ", buf);
1504     SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1505     append_about_text(dlg, "Using protocol: ", buf);
1506     CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1507     append_about_text(dlg, "Encryption: ", buf);
1508     CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1509     append_about_text(dlg, "Server keys: ", buf);
1510     AUTH_get_auth_info(pvar, buf, sizeof(buf));
1511     append_about_text(dlg, "Authentication: ", buf);
1512     SSH_get_compression_info(pvar, buf, sizeof(buf));
1513     append_about_text(dlg, "Compression: ", buf);
1514    
1515     } else { // SSH2
1516     SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1517     append_about_text(dlg, "Server ID: ", buf);
1518    
1519     append_about_text(dlg, "Client ID: ", pvar->client_version_string);
1520    
1521     SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1522     append_about_text(dlg, "Using protocol: ", buf);
1523    
1524     if (pvar->kex_type == KEX_DH_GRP1_SHA1) {
1525     strcpy(buf, KEX_DH1);
1526     } else if (pvar->kex_type == KEX_DH_GRP14_SHA1) {
1527     strcpy(buf, KEX_DH14);
1528     } else {
1529     strcpy(buf, KEX_DHGEX);
1530     }
1531     append_about_text(dlg, "KEX: ", buf);
1532    
1533     if (pvar->hostkey_type == KEY_DSA) {
1534     strcpy(buf, "ssh-dss");
1535     } else {
1536     strcpy(buf, "ssh-rsa");
1537     }
1538     append_about_text(dlg, "Host Key: ", buf);
1539    
1540 yutakakn 2758 // add HMAC algorithm (2004.12.17 yutaka)
1541     buf[0] = '\0';
1542     if (pvar->ctos_hmac == HMAC_SHA1) {
1543     strcat(buf, "hmac-sha1");
1544     } else if (pvar->ctos_hmac == HMAC_MD5) {
1545     strcat(buf, "hmac-md5");
1546     }
1547     strcat(buf, " to server, ");
1548     if (pvar->stoc_hmac == HMAC_SHA1) {
1549     strcat(buf, "hmac-sha1");
1550     } else if (pvar->stoc_hmac == HMAC_MD5) {
1551     strcat(buf, "hmac-md5");
1552     }
1553     strcat(buf, " from server");
1554     append_about_text(dlg, "HMAC: ", buf);
1555    
1556 yutakakn 2728 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1557     append_about_text(dlg, "Encryption: ", buf);
1558     CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1559     append_about_text(dlg, "Server keys: ", buf);
1560     AUTH_get_auth_info(pvar, buf, sizeof(buf));
1561     append_about_text(dlg, "Authentication: ", buf);
1562     SSH_get_compression_info(pvar, buf, sizeof(buf));
1563     append_about_text(dlg, "Compression: ", buf);
1564    
1565     }
1566     }
1567     }
1568    
1569     static BOOL CALLBACK TTXAboutDlg(HWND dlg, UINT msg, WPARAM wParam,
1570     LPARAM lParam)
1571     {
1572     switch (msg) {
1573     case WM_INITDIALOG:
1574     init_about_dlg((PTInstVar) lParam, dlg);
1575     return TRUE;
1576     case WM_COMMAND:
1577     switch (LOWORD(wParam)) {
1578     case IDOK:
1579     EndDialog(dlg, 1);
1580     return TRUE;
1581     case IDCANCEL: /* there isn't a cancel button, but other Windows
1582     UI things can send this message */
1583     EndDialog(dlg, 0);
1584     return TRUE;
1585     }
1586     break;
1587     }
1588    
1589     return FALSE;
1590     }
1591    
1592     static char FAR *get_cipher_name(int cipher)
1593     {
1594     switch (cipher) {
1595     case SSH_CIPHER_NONE:
1596     return "<ciphers below this line are disabled>";
1597     case SSH_CIPHER_RC4:
1598     return "RC4";
1599     case SSH_CIPHER_3DES:
1600     return "3DES";
1601     case SSH_CIPHER_DES:
1602     return "DES";
1603     case SSH_CIPHER_IDEA:
1604     return "IDEA";
1605     case SSH_CIPHER_TSS:
1606     return "TSS";
1607     case SSH_CIPHER_BLOWFISH:
1608     return "Blowfish";
1609    
1610     // for SSH2(yutaka)
1611     case SSH_CIPHER_AES128:
1612     return "AES128(SSH2)";
1613     case SSH_CIPHER_3DES_CBC:
1614     return "3DES-CBC(SSH2)";
1615    
1616     default:
1617     return NULL;
1618     }
1619     }
1620    
1621     static void set_move_button_status(HWND dlg)
1622     {
1623     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1624     int curPos = (int) SendMessage(cipherControl, LB_GETCURSEL, 0, 0);
1625     int maxPos = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0) - 1;
1626    
1627     EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERUP), curPos > 0
1628     && curPos <= maxPos);
1629     EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERDOWN), curPos >= 0
1630     && curPos < maxPos);
1631     }
1632    
1633     static void init_setup_dlg(PTInstVar pvar, HWND dlg)
1634     {
1635     HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1636     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1637     int i;
1638     int ch;
1639    
1640     SendMessage(compressionControl, TBM_SETRANGE, TRUE, MAKELONG(0, 9));
1641     SendMessage(compressionControl, TBM_SETPOS, TRUE,
1642     pvar->settings.CompressionLevel);
1643    
1644     normalize_cipher_order(pvar->settings.CipherOrder);
1645     SSH2_update_cipher_myproposal(pvar); // yutaka
1646    
1647     for (i = 0; pvar->settings.CipherOrder[i] != 0; i++) {
1648     int cipher = pvar->settings.CipherOrder[i] - '0';
1649     char FAR *name = get_cipher_name(cipher);
1650    
1651     if (name != NULL) {
1652     SendMessage(cipherControl, LB_ADDSTRING, 0, (LPARAM) name);
1653     }
1654     }
1655    
1656     SendMessage(cipherControl, LB_SETCURSEL, 0, 0);
1657     set_move_button_status(dlg);
1658    
1659     for (i = 0; (ch = pvar->settings.KnownHostsFiles[i]) != 0 && ch != ';';
1660     i++) {
1661     }
1662     if (ch != 0) {
1663     pvar->settings.KnownHostsFiles[i] = 0;
1664     SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1665     pvar->settings.KnownHostsFiles);
1666     pvar->settings.KnownHostsFiles[i] = ch;
1667     SetDlgItemText(dlg, IDC_READONLYFILENAME,
1668     pvar->settings.KnownHostsFiles + i + 1);
1669     } else {
1670     SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1671     pvar->settings.KnownHostsFiles);
1672     }
1673 yutakakn 2789
1674     // SSH2 HeartBeat(keep-alive)������ (2005.2.22 yutaka)
1675     {
1676     char buf[10];
1677     _snprintf(buf, sizeof(buf), "%d", pvar->settings.ssh_heartbeat_overtime);
1678     SetDlgItemText(dlg, IDC_HEARTBEAT_EDIT, buf);
1679     }
1680    
1681 yutakakn 2728 }
1682    
1683     void get_teraterm_dir_relative_name(char FAR * buf, int bufsize,
1684     char FAR * basename)
1685     {
1686     int filename_start = 0;
1687     int i;
1688     int ch;
1689    
1690     if (basename[0] == '\\' || basename[0] == '/'
1691     || (basename[0] != 0 && basename[1] == ':')) {
1692     strncpy(buf, basename, bufsize);
1693     buf[bufsize - 1] = 0;
1694     return;
1695     }
1696    
1697     GetModuleFileName(NULL, buf, bufsize);
1698     for (i = 0; (ch = buf[i]) != 0; i++) {
1699     if (ch == '\\' || ch == '/' || ch == ':') {
1700     filename_start = i + 1;
1701     }
1702     }
1703    
1704     if (bufsize > filename_start) {
1705     strncpy(buf + filename_start, basename, bufsize - filename_start);
1706     }
1707     buf[bufsize - 1] = 0;
1708     }
1709    
1710     int copy_teraterm_dir_relative_path(char FAR * dest, int destsize,
1711     char FAR * basename)
1712     {
1713     char buf[1024];
1714     int filename_start = 0;
1715     int i;
1716     int ch, ch2;
1717    
1718     if (basename[0] != '\\' && basename[0] != '/'
1719     && (basename[0] == 0 || basename[1] != ':')) {
1720     strncpy(dest, basename, destsize);
1721     dest[destsize - 1] = 0;
1722     return strlen(dest);
1723     }
1724    
1725     GetModuleFileName(NULL, buf, sizeof(buf));
1726     for (i = 0; (ch = buf[i]) != 0; i++) {
1727     if (ch == '\\' || ch == '/' || ch == ':') {
1728     filename_start = i + 1;
1729     }
1730     }
1731    
1732     for (i = 0; i < filename_start; i++) {
1733     ch = toupper(buf[i]);
1734     ch2 = toupper(basename[i]);
1735    
1736     if (ch == ch2
1737     || ((ch == '\\' || ch == '/')
1738     && (ch2 == '\\' || ch2 == '/'))) {
1739     } else {
1740     break;
1741     }
1742     }
1743    
1744     if (i == filename_start) {
1745     strncpy(dest, basename + i, destsize);
1746     } else {
1747     strncpy(dest, basename, destsize);
1748     }
1749     dest[destsize - 1] = 0;
1750     return strlen(dest);
1751     }
1752    
1753     static void complete_setup_dlg(PTInstVar pvar, HWND dlg)
1754     {
1755     char buf[4096];
1756     char buf2[1024];
1757     HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1758     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1759     int i, j, buf2index, bufindex;
1760     int count = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0);
1761    
1762     pvar->settings.CompressionLevel =
1763     (int) SendMessage(compressionControl, TBM_GETPOS, 0, 0);
1764    
1765     buf2index = 0;
1766     for (i = 0; i < count; i++) {
1767     int len = SendMessage(cipherControl, LB_GETTEXTLEN, i, 0);
1768    
1769     if (len > 0 && len < sizeof(buf)) { /* should always be true */
1770     buf[0] = 0;
1771     SendMessage(cipherControl, LB_GETTEXT, i, (LPARAM) buf);
1772     for (j = 0;
1773     j <= SSH_CIPHER_MAX
1774     && strcmp(buf, get_cipher_name(j)) != 0; j++) {
1775     }
1776     if (j <= SSH_CIPHER_MAX) {
1777     buf2[buf2index] = '0' + j;
1778     buf2index++;
1779     }
1780     }
1781     }
1782     buf2[buf2index] = 0;
1783     normalize_cipher_order(buf2);
1784     strcpy(pvar->settings.CipherOrder, buf2);
1785     SSH2_update_cipher_myproposal(pvar); // yutaka
1786    
1787     buf[0] = 0;
1788     GetDlgItemText(dlg, IDC_READWRITEFILENAME, buf, sizeof(buf));
1789     j = copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles,
1790     sizeof(pvar->settings.
1791     KnownHostsFiles), buf);
1792     buf[0] = 0;
1793     bufindex = 0;
1794     GetDlgItemText(dlg, IDC_READONLYFILENAME, buf, sizeof(buf));
1795     for (i = 0; buf[i] != 0; i++) {
1796     if (buf[i] == ';') {
1797     buf[i] = 0;
1798     if (j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1799     pvar->settings.KnownHostsFiles[j] = ';';
1800     j++;
1801     j += copy_teraterm_dir_relative_path(pvar->settings.
1802     KnownHostsFiles + j,
1803     sizeof(pvar->settings.
1804     KnownHostsFiles)
1805     - j, buf + bufindex);
1806     }
1807     bufindex = i + 1;
1808     }
1809     }
1810     if (bufindex < i && j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1811     pvar->settings.KnownHostsFiles[j] = ';';
1812     j++;
1813     copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles + j,
1814     sizeof(pvar->settings.
1815     KnownHostsFiles) - j,
1816     buf + bufindex);
1817     }
1818 yutakakn 2789
1819     // get SSH HeartBeat(keep-alive)
1820     SendMessage(GetDlgItem(dlg, IDC_HEARTBEAT_EDIT), WM_GETTEXT, sizeof(buf), (LPARAM)buf);
1821     i = atoi(buf);
1822     if (i < 0)
1823     i = 60;
1824     pvar->settings.ssh_heartbeat_overtime = i;
1825    
1826 yutakakn 2728 }
1827    
1828     static void move_cur_sel_delta(HWND listbox, int delta)
1829     {
1830     int curPos = (int) SendMessage(listbox, LB_GETCURSEL, 0, 0);
1831     int maxPos = (int) SendMessage(listbox, LB_GETCOUNT, 0, 0) - 1;
1832     int newPos = curPos + delta;
1833     char buf[1024];
1834    
1835     if (curPos >= 0 && newPos >= 0 && newPos <= maxPos) {
1836     int len = SendMessage(listbox, LB_GETTEXTLEN, curPos, 0);
1837    
1838     if (len > 0 && len < sizeof(buf)) { /* should always be true */
1839     buf[0] = 0;
1840     SendMessage(listbox, LB_GETTEXT, curPos, (LPARAM) buf);
1841     SendMessage(listbox, LB_DELETESTRING, curPos, 0);
1842     SendMessage(listbox, LB_INSERTSTRING, newPos,
1843     (LPARAM) (char FAR *) buf);
1844     SendMessage(listbox, LB_SETCURSEL, newPos, 0);
1845     }
1846     }
1847     }
1848    
1849     static int get_keys_file_name(HWND parent, char FAR * buf, int bufsize,
1850     int readonly)
1851     {
1852     #ifdef TERATERM32
1853     OPENFILENAME params;
1854     char fullname_buf[2048] = "ssh_known_hosts";
1855    
1856     params.lStructSize = sizeof(OPENFILENAME);
1857     params.hwndOwner = parent;
1858     params.lpstrFilter = NULL;
1859     params.lpstrCustomFilter = NULL;
1860     params.nFilterIndex = 0;
1861     buf[0] = 0;
1862     params.lpstrFile = fullname_buf;
1863     params.nMaxFile = sizeof(fullname_buf);
1864     params.lpstrFileTitle = NULL;
1865     params.lpstrInitialDir = NULL;
1866     params.lpstrTitle =
1867     readonly ? "Choose a read-only known-hosts file to add" :
1868     "Choose a read/write known-hosts file";
1869     params.Flags = (readonly ? OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST : 0)
1870     | OFN_HIDEREADONLY | (!readonly ? OFN_NOREADONLYRETURN : 0);
1871     params.lpstrDefExt = NULL;
1872    
1873     if (GetOpenFileName(&params) != 0) {
1874     copy_teraterm_dir_relative_path(buf, bufsize, fullname_buf);
1875     return 1;
1876     } else {
1877     int err = CommDlgExtendedError();
1878    
1879     if (err != 0) {
1880     char buf[1024];
1881    
1882     _snprintf(buf, sizeof(buf),
1883     "Cannot show file dialog box: error %d", err);
1884     buf[sizeof(buf) - 1] = 0;
1885     MessageBox(parent, buf, "TTSSH Error",
1886     MB_OK | MB_ICONEXCLAMATION);
1887     }
1888    
1889     return 0;
1890     }
1891     #else
1892     return 0;
1893     #endif
1894     }
1895    
1896     static void choose_read_write_file(HWND dlg)
1897     {
1898     char buf[1024];
1899    
1900     if (get_keys_file_name(dlg, buf, sizeof(buf), 0)) {
1901     SetDlgItemText(dlg, IDC_READWRITEFILENAME, buf);
1902     }
1903     }
1904    
1905     static void choose_read_only_file(HWND dlg)
1906     {
1907     char buf[1024];
1908     char buf2[4096];
1909    
1910     if (get_keys_file_name(dlg, buf, sizeof(buf), 1)) {
1911     buf2[0] = 0;
1912     GetDlgItemText(dlg, IDC_READONLYFILENAME, buf2, sizeof(buf2));
1913     if (buf2[0] != 0 && buf2[strlen(buf2) - 1] != ';') {
1914     strncat(buf2, ";", sizeof(buf2));
1915     }
1916     strncat(buf2, buf, sizeof(buf2));
1917     SetDlgItemText(dlg, IDC_READONLYFILENAME, buf2);
1918     }
1919     }
1920    
1921     static BOOL CALLBACK TTXSetupDlg(HWND dlg, UINT msg, WPARAM wParam,
1922     LPARAM lParam)
1923     {
1924     switch (msg) {
1925     case WM_INITDIALOG:
1926     SetWindowLong(dlg, DWL_USER, lParam);
1927     init_setup_dlg((PTInstVar) lParam, dlg);
1928     return TRUE;
1929     case WM_COMMAND:
1930     switch (LOWORD(wParam)) {
1931     case IDOK:
1932     complete_setup_dlg((PTInstVar) GetWindowLong(dlg, DWL_USER),
1933     dlg);
1934     EndDialog(dlg, 1);
1935     return TRUE;
1936     case IDCANCEL: /* there isn't a cancel button, but other Windows
1937     UI things can send this message */
1938     EndDialog(dlg, 0);
1939     return TRUE;
1940     case IDC_SSHMOVECIPHERUP:
1941     move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), -1);
1942     set_move_button_status(dlg);
1943     SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
1944     return TRUE;
1945     case IDC_SSHMOVECIPHERDOWN:
1946     move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), 1);
1947     set_move_button_status(dlg);
1948     SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
1949     return TRUE;
1950     case IDC_SSHCIPHERPREFS:
1951     set_move_button_status(dlg);
1952     return TRUE;
1953     case IDC_CHOOSEREADWRITEFILE:
1954     choose_read_write_file(dlg);
1955     return TRUE;
1956     case IDC_CHOOSEREADONLYFILE:
1957     choose_read_only_file(dlg);
1958     return TRUE;
1959     }
1960     break;
1961     }
1962    
1963     return FALSE;
1964     }
1965    
1966 yutakakn 2816
1967     //
1968     // SSH key generator dialog (2005.4.10 yutaka)
1969     //
1970    
1971     typedef struct {
1972     RSA *rsa;
1973     DSA *dsa;
1974     } ssh_private_key_t;
1975    
1976     static ssh_private_key_t private_key = {NULL, NULL};
1977    
1978     typedef struct {
1979     RSA *rsa;
1980     DSA *dsa;
1981     } ssh_public_key_t;
1982    
1983     static ssh_public_key_t public_key = {NULL, NULL};;
1984    
1985     static void free_ssh_key(void)
1986     {
1987     // DSA_free(), RSA_free()��NULL���n�����������������B
1988     DSA_free(private_key.dsa);
1989     private_key.dsa = NULL;
1990     DSA_free(public_key.dsa);
1991     public_key.dsa = NULL;
1992    
1993     RSA_free(private_key.rsa);
1994     private_key.rsa = NULL;
1995     RSA_free(public_key.rsa);
1996     public_key.rsa = NULL;
1997     }
1998    
1999    
2000     static BOOL generate_ssh_key(enum hostkey_type type)
2001     {
2002     int bits = 1024;
2003    
2004     // if SSH key already is generated, should free the resource.
2005     free_ssh_key();
2006    
2007     if (type == KEY_RSA1 || type == KEY_RSA) {
2008     RSA *priv = NULL;
2009     RSA *pub = NULL;
2010    
2011     // private key
2012     priv = RSA_generate_key(bits, 35, NULL, NULL);
2013     if (priv == NULL)
2014     goto error;
2015     private_key.rsa = priv;
2016    
2017     // public key
2018     pub = RSA_new();
2019     pub->n = BN_new();
2020     pub->e = BN_new();
2021     if (pub->n == NULL || pub->e == NULL) {
2022     RSA_free(pub);
2023     goto error;
2024     }
2025    
2026     BN_copy(pub->n, priv->n);
2027     BN_copy(pub->e, priv->e);
2028     public_key.rsa = pub;
2029    
2030     } else if (type == KEY_DSA) {
2031     DSA *priv = NULL;
2032     DSA *pub = NULL;
2033    
2034     // private key
2035     priv = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
2036     if (priv == NULL)
2037     goto error;
2038     if (!DSA_generate_key(priv)) {
2039     // TODO: free 'priv'?
2040     goto error;
2041     }
2042     private_key.dsa = priv;
2043    
2044     // public key
2045     pub = DSA_new();
2046     if (pub == NULL)
2047     goto error;
2048     pub->p = BN_new();
2049     pub->q = BN_new();
2050     pub->g = BN_new();
2051     pub->pub_key = BN_new();
2052     if (pub->p == NULL || pub->q == NULL || pub->g == NULL || pub->pub_key == NULL) {
2053     DSA_free(pub);
2054     goto error;
2055     }
2056    
2057     BN_copy(pub->p, priv->p);
2058     BN_copy(pub->q, priv->q);
2059     BN_copy(pub->g, priv->g);
2060     BN_copy(pub->pub_key, priv->pub_key);
2061     public_key.dsa = pub;
2062    
2063     } else {
2064     goto error;
2065     }
2066    
2067     return TRUE;
2068    
2069     error:
2070     free_ssh_key();
2071     return FALSE;
2072     }
2073    
2074    
2075     //
2076     // RC4
2077     //
2078    
2079     /* Size of key to use */
2080     #define SEED_SIZE 20
2081    
2082     /* Number of bytes to reseed after */
2083     #define REKEY_BYTES (1 << 24)
2084    
2085     static int rc4_ready = 0;
2086     static RC4_KEY rc4;
2087    
2088     static void seed_rng(void)
2089     {
2090     if (RAND_status() != 1)
2091     return;
2092     }
2093    
2094     static void arc4random_stir(void)
2095     {
2096     unsigned char rand_buf[SEED_SIZE];
2097     int i;
2098    
2099     memset(&rc4, 0, sizeof(rc4));
2100     if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0) {
2101     //fatal("Couldn't obtain random bytes (error %ld)",
2102     // ERR_get_error());
2103     }
2104     RC4_set_key(&rc4, sizeof(rand_buf), rand_buf);
2105    
2106     /*
2107     * Discard early keystream, as per recommendations in:
2108     * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
2109     */
2110     for(i = 0; i <= 256; i += sizeof(rand_buf))
2111     RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf);
2112    
2113     memset(rand_buf, 0, sizeof(rand_buf));
2114    
2115     rc4_ready = REKEY_BYTES;
2116     }
2117    
2118     static unsigned int arc4random(void)
2119     {
2120     unsigned int r = 0;
2121     static int first_time = 1;
2122    
2123     if (rc4_ready <= 0) {
2124     if (first_time) {
2125     seed_rng();
2126     }
2127     first_time = 0;
2128     arc4random_stir();
2129     }
2130    
2131     RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r);
2132    
2133     rc4_ready -= sizeof(r);
2134    
2135     return(r);
2136     }
2137    
2138     //
2139     // SSH1 3DES
2140     //
2141     /*
2142     * This is used by SSH1:
2143     *
2144     * What kind of triple DES are these 2 routines?
2145     *
2146     * Why is there a redundant initialization vector?
2147     *
2148     * If only iv3 was used, then, this would till effect have been
2149     * outer-cbc. However, there is also a private iv1 == iv2 which
2150     * perhaps makes differential analysis easier. On the other hand, the
2151     * private iv1 probably makes the CRC-32 attack ineffective. This is a
2152     * result of that there is no longer any known iv1 to use when
2153     * choosing the X block.
2154     */
2155     struct ssh1_3des_ctx
2156     {
2157     EVP_CIPHER_CTX k1, k2, k3;
2158     };
2159    
2160     static int ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, int enc)
2161     {
2162     struct ssh1_3des_ctx *c;
2163     u_char *k1, *k2, *k3;
2164    
2165     if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
2166     c = malloc(sizeof(*c));
2167     EVP_CIPHER_CTX_set_app_data(ctx, c);
2168     }
2169     if (key == NULL)
2170     return (1);
2171     if (enc == -1)
2172     enc = ctx->encrypt;
2173     k1 = k2 = k3 = (u_char *) key;
2174     k2 += 8;
2175     if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
2176     if (enc)
2177     k3 += 16;
2178     else
2179     k1 += 16;
2180     }
2181     EVP_CIPHER_CTX_init(&c->k1);
2182     EVP_CIPHER_CTX_init(&c->k2);
2183     EVP_CIPHER_CTX_init(&c->k3);
2184     if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
2185     EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
2186     EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
2187     memset(c, 0, sizeof(*c));
2188     free(c);
2189     EVP_CIPHER_CTX_set_app_data(ctx, NULL);
2190     return (0);
2191     }
2192     return (1);
2193     }
2194    
2195     static int ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len)
2196     {
2197     struct ssh1_3des_ctx *c;
2198    
2199     if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
2200     //error("ssh1_3des_cbc: no context");
2201     return (0);
2202     }
2203     if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
2204     EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
2205     EVP_Cipher(&c->k3, dest, dest, len) == 0)
2206     return (0);
2207     return (1);
2208     }
2209    
2210     static int ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
2211     {
2212     struct ssh1_3des_ctx *c;
2213    
2214     if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
2215     EVP_CIPHER_CTX_cleanup(&c->k1);
2216     EVP_CIPHER_CTX_cleanup(&c->k2);
2217     EVP_CIPHER_CTX_cleanup(&c->k3);
2218     memset(c, 0, sizeof(*c));
2219     free(c);
2220     EVP_CIPHER_CTX_set_app_data(ctx, NULL);
2221     }
2222     return (1);
2223     }
2224    
2225     void ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
2226     {
2227     struct ssh1_3des_ctx *c;
2228    
2229     if (len != 24)
2230     //fatal("%s: bad 3des iv length: %d", __func__, len);
2231     ;
2232    
2233     if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
2234     //fatal("%s: no 3des context", __func__);
2235     ;
2236    
2237     if (doset) {
2238     //debug3("%s: Installed 3DES IV", __func__);
2239     memcpy(c->k1.iv, iv, 8);
2240     memcpy(c->k2.iv, iv + 8, 8);
2241     memcpy(c->k3.iv, iv + 16, 8);
2242     } else {
2243     //debug3("%s: Copying 3DES IV", __func__);
2244     memcpy(iv, c->k1.iv, 8);
2245     memcpy(iv + 8, c->k2.iv, 8);
2246     memcpy(iv + 16, c->k3.iv, 8);
2247     }
2248     }
2249    
2250     const EVP_CIPHER *evp_ssh1_3des(void)
2251     {
2252     static EVP_CIPHER ssh1_3des;
2253    
2254     memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
2255     ssh1_3des.nid = NID_undef;
2256     ssh1_3des.block_size = 8;
2257     ssh1_3des.iv_len = 0;
2258     ssh1_3des.key_len = 16;
2259     ssh1_3des.init = ssh1_3des_init;
2260     ssh1_3des.cleanup = ssh1_3des_cleanup;
2261     ssh1_3des.do_cipher = ssh1_3des_cbc;
2262     ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
2263     return (&ssh1_3des);
2264     }
2265    
2266     static void ssh_make_comment(char *comment, int maxlen)
2267     {
2268     char user[UNLEN + 1], host[128];
2269     DWORD dwSize;
2270     WSADATA wsaData;
2271     int ret;
2272    
2273     // get Windows logon user name
2274     dwSize = sizeof(user);
2275     if (GetUserName(user, &dwSize) == 0) {
2276     strcpy(user, "yutaka");
2277     }
2278    
2279     // get local hostname (by WinSock)
2280     ret = WSAStartup(MAKEWORD(2,2), &wsaData);
2281     if (ret == 0) {
2282     if (gethostname(host, sizeof(host)) != 0) {
2283     ret = WSAGetLastError();
2284     }
2285     WSACleanup();
2286     }
2287     if (ret != 0) {
2288     strcpy(host, "sai");
2289     }
2290    
2291     _snprintf(comment, maxlen, "%s@%s", user, host);
2292     }
2293    
2294     // uuencode (rfc1521)
2295     static int uuencode(unsigned char *src, int srclen, unsigned char *target, int targsize)
2296     {
2297     char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2298     char pad = '=';
2299     int datalength = 0;
2300     unsigned char input[3];
2301     unsigned char output[4];
2302     int i;
2303    
2304     while (srclen > 2) {
2305     input[0] = *src++;
2306     input[1] = *src++;
2307     input[2] = *src++;
2308     srclen -= 3;
2309    
2310     output[0] = input[0] >> 2;
2311     output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
2312     output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
2313     output[3] = input[2] & 0x3f;
2314     if (output[0] >= 64 ||
2315     output[1] >= 64 ||
2316     output[2] >= 64 ||
2317     output[3] >= 64)
2318     return -1;
2319    
2320     if (datalength + 4 > targsize)
2321     return (-1);
2322     target[datalength++] = base64[output[0]];
2323     target[datalength++] = base64[output[1]];
2324     target[datalength++] = base64[output[2]];
2325     target[datalength++] = base64[output[3]];
2326     }
2327    
2328     if (srclen != 0) {
2329     /* Get what's left. */
2330     input[0] = input[1] = input[2] = '\0';
2331     for (i = 0; i < srclen; i++)
2332     input[i] = *src++;
2333    
2334     output[0] = input[0] >> 2;
2335     output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
2336     output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
2337     if (output[0] >= 64 ||
2338     output[1] >= 64 ||
2339     output[2] >= 64)
2340     return -1;
2341    
2342     if (datalength + 4 > targsize)
2343     return (-1);
2344     target[datalength++] = base64[output[0]];
2345     target[datalength++] = base64[output[1]];
2346     if (srclen == 1)
2347     target[datalength++] = pad;
2348     else
2349     target[datalength++] = base64[output[2]];
2350     target[datalength++] = pad;
2351     }
2352     if (datalength >= targsize)
2353     return (-1);
2354     target[datalength] = '\0'; /* Returned value doesn't count \0. */
2355    
2356     return (datalength); // success
2357     }
2358    
2359     static BOOL CALLBACK TTXKeyGenerator(HWND dlg, UINT msg, WPARAM wParam,
2360     LPARAM lParam)
2361     {
2362     static enum hostkey_type key_type;
2363    
2364     switch (msg) {
2365     case WM_INITDIALOG:
2366     {
2367     // default key type
2368     SendMessage(GetDlgItem(dlg, IDC_RSA_TYPE), BM_SETCHECK, BST_CHECKED, 0);
2369     key_type = KEY_RSA;
2370    
2371     // passphrase edit box disabled(default)
2372     EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE);
2373     EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE);
2374    
2375     // file saving dialog disabled(default)
2376     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE);
2377     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE);
2378    
2379     }
2380     return TRUE;
2381    
2382     case WM_COMMAND:
2383     switch (LOWORD(wParam)) {
2384     case IDOK: // key generate button pressed
2385     // passphrase edit box disabled(default)
2386     EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE);
2387     EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE);
2388    
2389     // file saving dialog disabled(default)
2390     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE);
2391     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE);
2392    
2393     if (generate_ssh_key(key_type)) {
2394     // passphrase edit box disabled(default)
2395     EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), TRUE);
2396     EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), TRUE);
2397    
2398     // file saving dialog disabled(default)
2399     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), TRUE);
2400     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), TRUE);
2401     }
2402     return TRUE;
2403    
2404     case IDCANCEL:
2405     // don't forget to free SSH resource!
2406     free_ssh_key();
2407     EndDialog(dlg, 0); // dialog close
2408     return TRUE;
2409    
2410     // if radio button pressed...
2411     case IDC_RSA1_TYPE | (BN_CLICKED << 16):
2412     key_type = KEY_RSA1;
2413     break;
2414    
2415     case IDC_RSA_TYPE | (BN_CLICKED << 16):
2416     key_type = KEY_RSA;
2417     break;
2418    
2419     case IDC_DSA_TYPE | (BN_CLICKED << 16):
2420     key_type = KEY_DSA;
2421     break;
2422    
2423     // saving public key file
2424     case IDC_SAVE_PUBLIC_KEY:
2425     {
2426     int ret;
2427     OPENFILENAME ofn;
2428     char filename[MAX_PATH];
2429     FILE *fp;
2430     char comment[1024]; // comment string in private key
2431    
2432     arc4random_stir();
2433    
2434     // saving file dialog
2435     ZeroMemory(&ofn, sizeof(ofn));
2436     ofn.lStructSize = sizeof(ofn);
2437     ofn.hwndOwner = dlg;
2438     if (key_type == KEY_RSA1) {
2439     ofn.lpstrFilter = "SSH1 RSA key(identity.pub)\0identity.pub\0All Files(*.*)\0*.*\0\0";
2440     _snprintf(filename, sizeof(filename), "identity.pub"