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 2831 - (hide annotations) (download) (as text)
Sat Jul 9 05:16:06 2005 UTC (18 years, 9 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 84346 byte(s)
OpenSSL 0.9.8でビルドできるようにした。

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