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 2816 - (hide annotations) (download) (as text)
Sat Apr 23 17:26:57 2005 UTC (18 years, 11 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 83484 byte(s)
キー作成ダイアログの追加。

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