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 2868 - (hide annotations) (download) (as text)
Sun Jun 11 14:26:30 2006 UTC (17 years, 10 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 85997 byte(s)
SSH Port Forward の編集画面で、TeraTermが未接続状態の場合、ポート番号不正を即座にメッセージボックスが表示されないバグを修正した。

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 yutakakn 2850 _stricmp(buf, "yes") == 0 || _stricmp(buf, "y") == 0;
318 yutakakn 2728 }
319     }
320    
321     static void read_string_option(PCHAR fileName, char FAR * keyName,
322     char FAR * def, char FAR * buf, int bufSize)
323     {
324    
325     buf[0] = 0;
326     GetPrivateProfileString("TTSSH", keyName, def, buf, bufSize, fileName);
327     }
328    
329     static void read_ssh_options(PTInstVar pvar, PCHAR fileName)
330     {
331     char buf[1024];
332     TS_SSH FAR *settings = pvar->ts_SSH;
333    
334     #define READ_STD_STRING_OPTION(name) \
335     read_string_option(fileName, #name, "", settings->name, sizeof(settings->name))
336    
337     settings->Enabled = read_BOOL_option(fileName, "Enabled", FALSE);
338    
339     buf[0] = 0;
340     GetPrivateProfileString("TTSSH", "Compression", "", buf, sizeof(buf),
341     fileName);
342     settings->CompressionLevel = atoi(buf);
343     if (settings->CompressionLevel < 0 || settings->CompressionLevel > 9) {
344     settings->CompressionLevel = 0;
345     }
346    
347     READ_STD_STRING_OPTION(DefaultUserName);
348     READ_STD_STRING_OPTION(DefaultForwarding);
349     READ_STD_STRING_OPTION(DefaultRhostsLocalUserName);
350     READ_STD_STRING_OPTION(DefaultRhostsHostPrivateKeyFile);
351     READ_STD_STRING_OPTION(DefaultRSAPrivateKeyFile);
352    
353     READ_STD_STRING_OPTION(CipherOrder);
354     normalize_cipher_order(settings->CipherOrder);
355     SSH2_update_cipher_myproposal(pvar); // yutaka
356 yutakakn 2833 SSH2_update_compression_myproposal(pvar); // SSH2 packet compression (2005.7.9 yutaka)
357 yutakakn 2728
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 yutakakn 2868 // �������������������m���E�B���h�E�����������A�f�X�N�g�b�v���I�[�i�[������
735     // ���b�Z�[�W�{�b�N�X���o���������B(2006.6.11 yutaka)
736     if (pvar->NotificationWindow == NULL) {
737     MessageBox(NULL, msg, "Tera Term: not fatal error", MB_OK|MB_ICONINFORMATION);
738     msg[0] = '\0';
739    
740     } else {
741     PostMessage(pvar->NotificationWindow, WM_COMMAND,
742     ID_SSHASYNCMESSAGEBOX, 0);
743     }
744 yutakakn 2728 }
745     if (msg[0] != 0) {
746     notify_verbose_message(pvar, msg, LOG_LEVEL_ERROR);
747     add_err_msg(pvar, msg);
748     }
749     }
750    
751     void notify_fatal_error(PTInstVar pvar, char FAR * msg)
752     {
753     if (msg[0] != 0) {
754     notify_verbose_message(pvar, msg, LOG_LEVEL_FATAL);
755     add_err_msg(pvar, msg);
756     }
757    
758     if (!pvar->fatal_error) {
759     pvar->fatal_error = TRUE;
760    
761     SSH_notify_disconnecting(pvar, msg);
762     AUTH_notify_disconnecting(pvar);
763     HOSTS_notify_disconnecting(pvar);
764    
765     PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
766     pvar->socket, MAKELPARAM(FD_CLOSE,
767     (pvar->PWSAGetLastError) ()));
768     }
769     }
770    
771     void notify_verbose_message(PTInstVar pvar, char FAR * msg, int level)
772     {
773     if (level <= pvar->session_settings.LogLevel) {
774     char buf[1024];
775     int file;
776    
777     get_teraterm_dir_relative_name(buf, NUM_ELEM(buf), "TTSSH.LOG");
778     file = _open(buf, _O_RDWR | _O_APPEND | _O_CREAT | _O_TEXT,
779     _S_IREAD | _S_IWRITE);
780    
781     if (file >= 0) {
782     _write(file, msg, strlen(msg));
783     _write(file, "\n", 1);
784     _close(file);
785     }
786     }
787     }
788    
789     static void PASCAL FAR TTXOpenTCP(TTXSockHooks FAR * hooks)
790     {
791     GET_VAR();
792    
793     if (pvar->settings.Enabled) {
794 yutakakn 2805 char buf[1024] = "\n---------------------------------------------------------------------\nInitiating SSH session at ";
795 yutakakn 2728 struct tm FAR *newtime;
796     time_t long_time;
797    
798     pvar->session_settings = pvar->settings;
799    
800     time(&long_time);
801     newtime = localtime(&long_time);
802     strcat(buf, asctime(newtime));
803     buf[strlen(buf) - 1] = 0;
804     notify_verbose_message(pvar, buf, LOG_LEVEL_VERBOSE);
805    
806     FWDUI_load_settings(pvar);
807    
808     pvar->cv->TelAutoDetect = FALSE;
809     /* This next line should not be needed because Teraterm's
810     CommLib should find ts->Telnet == 0 ... but we'll do this
811     just to be on the safe side. */
812     pvar->cv->TelFlag = FALSE;
813    
814     pvar->Precv = *hooks->Precv;
815     pvar->Psend = *hooks->Psend;
816     pvar->PWSAAsyncSelect = *hooks->PWSAAsyncSelect;
817     pvar->Pconnect = *hooks->Pconnect;
818     pvar->PWSAGetLastError = *hooks->PWSAGetLastError;
819    
820     *hooks->Precv = TTXrecv;
821     *hooks->Psend = TTXsend;
822     *hooks->PWSAAsyncSelect = TTXWSAAsyncSelect;
823     *hooks->Pconnect = TTXconnect;
824    
825     SSH_open(pvar);
826     HOSTS_open(pvar);
827     FWDUI_open(pvar);
828     }
829     }
830    
831     static void PASCAL FAR TTXCloseTCP(TTXSockHooks FAR * hooks)
832     {
833     GET_VAR();
834    
835     if (pvar->session_settings.Enabled) {
836     pvar->socket = INVALID_SOCKET;
837    
838     notify_verbose_message(pvar, "Terminating SSH session...",
839     LOG_LEVEL_VERBOSE);
840    
841     *hooks->Precv = pvar->Precv;
842     *hooks->Psend = pvar->Psend;
843     *hooks->PWSAAsyncSelect = pvar->PWSAAsyncSelect;
844     *hooks->Pconnect = pvar->Pconnect;
845     }
846    
847     uninit_TTSSH(pvar);
848     init_TTSSH(pvar);
849     }
850    
851     static void enable_dlg_items(HWND dlg, int from, int to, BOOL enabled)
852     {
853     for (; from <= to; from++) {
854     EnableWindow(GetDlgItem(dlg, from), enabled);
855     }
856     }
857    
858     static BOOL CALLBACK TTXHostDlg(HWND dlg, UINT msg, WPARAM wParam,
859     LPARAM lParam)
860     {
861     static char *ssh_version[] = {"SSH1", "SSH2", NULL};
862     PGetHNRec GetHNRec;
863     char EntName[7];
864     char TempHost[HostNameMaxLength + 1];
865     WORD i, j, w;
866     BOOL Ok;
867    
868     GET_VAR();
869    
870     switch (msg) {
871     case WM_INITDIALOG:
872     GetHNRec = (PGetHNRec) lParam;
873     SetWindowLong(dlg, DWL_USER, lParam);
874    
875 yutakakn 2846 // �z�X�g�q�X�g�����`�F�b�N�{�b�N�X������ (2005.10.21 yutaka)
876     if (pvar->ts->HistoryList > 0) {
877     SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_SETCHECK, BST_CHECKED, 0);
878     } else {
879     SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_SETCHECK, BST_UNCHECKED, 0);
880     }
881    
882 yutakakn 2728 if (GetHNRec->PortType == IdFile)
883     GetHNRec->PortType = IdTCPIP;
884     CheckRadioButton(dlg, IDC_HOSTTCPIP, IDC_HOSTSERIAL,
885     IDC_HOSTTCPIP + GetHNRec->PortType - 1);
886    
887     strcpy(EntName, "Host");
888    
889     i = 1;
890     do {
891     sprintf(&EntName[4], "%d", i);
892     GetPrivateProfileString("Hosts", EntName, "",
893     TempHost, sizeof(TempHost),
894     GetHNRec->SetupFN);
895     if (strlen(TempHost) > 0)
896     SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_ADDSTRING,
897     0, (LPARAM) TempHost);
898     i++;
899     } while ((i <= 99) && (strlen(TempHost) > 0));
900    
901     SendDlgItemMessage(dlg, IDC_HOSTNAME, EM_LIMITTEXT,
902     HostNameMaxLength - 1, 0);
903    
904     SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_SETCURSEL, 0, 0);
905    
906     CheckRadioButton(dlg, IDC_HOSTTELNET, IDC_HOSTOTHER,
907     pvar->settings.Enabled ? IDC_HOSTSSH : GetHNRec->
908     Telnet ? IDC_HOSTTELNET : IDC_HOSTOTHER);
909     SendDlgItemMessage(dlg, IDC_HOSTTCPPORT, EM_LIMITTEXT, 5, 0);
910     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TCPPort, FALSE);
911     #ifdef INET6
912     for (i = 0; ProtocolFamilyList[i]; ++i) {
913     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_ADDSTRING,
914     0, (LPARAM) ProtocolFamilyList[i]);
915     }
916     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, EM_LIMITTEXT,
917     ProtocolFamilyMaxLength - 1, 0);
918     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_SETCURSEL, 0, 0);
919     #endif /* INET6 */
920    
921     /////// SSH version
922     for (i = 0; ssh_version[i]; ++i) {
923     SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_ADDSTRING,
924     0, (LPARAM) ssh_version[i]);
925     }
926     SendDlgItemMessage(dlg, IDC_SSH_VERSION, EM_LIMITTEXT,
927     NUM_ELEM(ssh_version) - 1, 0);
928    
929 yutakakn 2734 if (pvar->settings.ssh_protocol_version == 1) {
930     SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 0, 0); // SSH1
931     } else {
932 yutakakn 2728 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 1, 0); // SSH2
933     }
934    
935     if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
936     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE); // enabled
937     } else {
938     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
939     }
940     /////// SSH version
941    
942    
943     j = 0;
944     w = 1;
945     strcpy(EntName, "COM");
946     for (i = 1; i <= GetHNRec->MaxComPort; i++) {
947     sprintf(&EntName[3], "%d", i);
948     SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_ADDSTRING,
949     0, (LPARAM) EntName);
950     j++;
951     if (GetHNRec->ComPort == i)
952     w = j;
953     }
954     if (j > 0)
955     SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_SETCURSEL, w - 1, 0);
956     else /* All com ports are already used */
957     GetHNRec->PortType = IdTCPIP;
958    
959 yutakakn 2803 if (GetHNRec->PortType == IdTCPIP) {
960 yutakakn 2728 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
961 yutakakn 2803
962     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
963     enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, TRUE);
964     }
965 yutakakn 2728 #ifdef INET6
966     else {
967     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
968     FALSE);
969     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
970     IDC_HOSTTCPPROTOCOL, FALSE);
971 yutakakn 2803
972     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
973     enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, FALSE); // disabled (2004.11.23 yutaka)
974 yutakakn 2728 }
975     #else
976     else
977     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
978     FALSE);
979     #endif /* INET6 */
980    
981     // Host dialog���t�H�[�J�X�������� (2004.10.2 yutaka)
982 yutakakn 2803 if (GetHNRec->PortType == IdTCPIP) {
983     HWND hwnd = GetDlgItem(dlg, IDC_HOSTNAME);
984     SetFocus(hwnd);
985     } else {
986     HWND hwnd = GetDlgItem(dlg, IDC_HOSTCOM);
987     SetFocus(hwnd);
988 yutakakn 2728 }
989    
990 yutakakn 2734 // SetFocus()���t�H�[�J�X���������������AFALSE�������K�v�������B
991     // TRUE���������ATABSTOP�������������������R���g���[�����I�������B
992     // (2004.11.23 yutaka)
993     return FALSE;
994     //return TRUE;
995 yutakakn 2728
996     case WM_COMMAND:
997     switch (LOWORD(wParam)) {
998     case IDOK:
999     GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
1000     if (GetHNRec != NULL) {
1001     if (IsDlgButtonChecked(dlg, IDC_HOSTTCPIP)) {
1002     #ifdef INET6
1003     char afstr[BUFSIZ];
1004     #endif /* INET6 */
1005     i = GetDlgItemInt(dlg, IDC_HOSTTCPPORT, &Ok, FALSE);
1006     if (Ok) {
1007     GetHNRec->TCPPort = i;
1008     } else {
1009     MessageBox(dlg, "Teraterm",
1010     "The TCP port must be a number.",
1011     MB_OK | MB_ICONEXCLAMATION);
1012     return TRUE;
1013     }
1014     #ifdef INET6
1015     #define getaf(str) \
1016     ((strcmp((str), "IPv6") == 0) ? AF_INET6 : \
1017     ((strcmp((str), "IPv4") == 0) ? AF_INET : AF_UNSPEC))
1018     memset(afstr, 0, sizeof(afstr));
1019     GetDlgItemText(dlg, IDC_HOSTTCPPROTOCOL, afstr,
1020     sizeof(afstr));
1021     GetHNRec->ProtocolFamily = getaf(afstr);
1022     #endif /* INET6 */
1023     GetHNRec->PortType = IdTCPIP;
1024     GetDlgItemText(dlg, IDC_HOSTNAME, GetHNRec->HostName,
1025     HostNameMaxLength);
1026     GetHNRec->Telnet = FALSE;
1027     pvar->hostdlg_activated = TRUE;
1028     pvar->hostdlg_Enabled = FALSE;
1029     if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1030     GetHNRec->Telnet = TRUE;
1031     } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1032     pvar->hostdlg_Enabled = TRUE;
1033    
1034     // check SSH protocol version
1035     memset(afstr, 0, sizeof(afstr));
1036     GetDlgItemText(dlg, IDC_SSH_VERSION, afstr, sizeof(afstr));
1037 yutakakn 2850 if (_stricmp(afstr, "SSH1") == 0) {
1038 yutakakn 2728 pvar->settings.ssh_protocol_version = 1;
1039     } else {
1040     pvar->settings.ssh_protocol_version = 2;
1041     }
1042     }
1043 yutakakn 2846
1044     // host history check button
1045     if (SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_GETCHECK, 0, 0) == BST_CHECKED) {
1046     pvar->ts->HistoryList = 1;
1047     } else {
1048     pvar->ts->HistoryList = 0;
1049     }
1050    
1051 yutakakn 2728 } else {
1052     GetHNRec->PortType = IdSerial;
1053     GetHNRec->HostName[0] = 0;
1054     memset(EntName, 0, sizeof(EntName));
1055     GetDlgItemText(dlg, IDC_HOSTCOM, EntName,
1056     sizeof(EntName) - 1);
1057     GetHNRec->ComPort = (BYTE) (EntName[3]) - 0x30;
1058     if (strlen(EntName) > 4)
1059     GetHNRec->ComPort =
1060     GetHNRec->ComPort * 10 + (BYTE) (EntName[4]) -
1061     0x30;
1062     }
1063     }
1064     EndDialog(dlg, 1);
1065     return TRUE;
1066    
1067     case IDCANCEL:
1068     EndDialog(dlg, 0);
1069     return TRUE;
1070    
1071     case IDC_HOSTTCPIP:
1072     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1073     TRUE);
1074     #ifdef INET6
1075     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1076     IDC_HOSTTCPPROTOCOL, TRUE);
1077     #endif /* INET6 */
1078     enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
1079    
1080 yutakakn 2734 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, TRUE); // disabled (2004.11.23 yutaka)
1081 yutakakn 2728 if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1082     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
1083     } else {
1084     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1085     }
1086    
1087 yutakakn 2847 enable_dlg_items(dlg, IDC_HISTORY, IDC_HISTORY, TRUE); // disabled
1088    
1089 yutakakn 2728 return TRUE;
1090    
1091     case IDC_HOSTSERIAL:
1092     enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, TRUE);
1093     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1094     FALSE);
1095     #ifdef INET6
1096     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1097     IDC_HOSTTCPPROTOCOL, FALSE);
1098     #endif /* INET6 */
1099     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1100 yutakakn 2734 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, FALSE); // disabled (2004.11.23 yutaka)
1101 yutakakn 2728
1102 yutakakn 2847 enable_dlg_items(dlg, IDC_HISTORY, IDC_HISTORY, FALSE); // disabled
1103    
1104 yutakakn 2728 return TRUE;
1105    
1106     case IDC_HOSTSSH:
1107     enable_dlg_items(dlg, IDC_SSH_VERSION,
1108     IDC_SSH_VERSION, TRUE);
1109     goto hostssh_enabled;
1110    
1111     case IDC_HOSTTELNET:
1112     case IDC_HOSTOTHER:
1113     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1114     hostssh_enabled:
1115    
1116     GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
1117    
1118     if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1119     if (GetHNRec != NULL)
1120     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TelPort,
1121     FALSE);
1122     } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1123     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, 22, FALSE);
1124     }
1125     return TRUE;
1126    
1127     case IDC_HOSTHELP:
1128     PostMessage(GetParent(dlg), WM_USER_DLGHELP2, 0, 0);
1129     }
1130     }
1131     return FALSE;
1132     }
1133    
1134     static BOOL FAR PASCAL TTXGetHostName(HWND parent, PGetHNRec rec)
1135     {
1136     return (BOOL) DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_HOSTDLG),
1137     parent, TTXHostDlg, (LONG) rec);
1138     }
1139    
1140     static void PASCAL FAR TTXGetUIHooks(TTXUIHooks FAR * hooks)
1141     {
1142     GET_VAR();
1143    
1144     *hooks->GetHostName = TTXGetHostName;
1145     }
1146    
1147     static void FAR PASCAL TTXReadINIFile(PCHAR fileName, PTTSet ts)
1148     {
1149     GET_VAR();
1150    
1151     (pvar->ReadIniFile) (fileName, ts);
1152     read_ssh_options(pvar, fileName);
1153     pvar->settings = *pvar->ts_SSH;
1154     notify_verbose_message(pvar, "Reading INI file", LOG_LEVEL_VERBOSE);
1155     FWDUI_load_settings(pvar);
1156     }
1157    
1158     static void FAR PASCAL TTXWriteINIFile(PCHAR fileName, PTTSet ts)
1159     {
1160     GET_VAR();
1161    
1162     (pvar->WriteIniFile) (fileName, ts);
1163     *pvar->ts_SSH = pvar->settings;
1164     clear_local_settings(pvar);
1165     notify_verbose_message(pvar, "Writing INI file", LOG_LEVEL_VERBOSE);
1166     write_ssh_options(pvar, fileName, pvar->ts_SSH);
1167     }
1168    
1169     static void read_ssh_options_from_user_file(PTInstVar pvar,
1170     char FAR * user_file_name)
1171     {
1172     if (user_file_name[0] == '.') {
1173     read_ssh_options(pvar, user_file_name);
1174     } else {
1175     char buf[1024];
1176    
1177     get_teraterm_dir_relative_name(buf, sizeof(buf), user_file_name);
1178     read_ssh_options(pvar, buf);
1179     }
1180    
1181     pvar->settings = *pvar->ts_SSH;
1182     FWDUI_load_settings(pvar);
1183     }
1184    
1185 yutakakn 2784
1186     // @���u�����N���u�������B (2005.1.26 yutaka)
1187     static void replace_to_blank(char *src, char *dst, int dst_len)
1188     {
1189     int len, i;
1190    
1191     len = strlen(src);
1192     if (dst_len < len) // buffer overflow check
1193     return;
1194    
1195     for (i = 0 ; i < len ; i++) {
1196     if (src[i] == '@') { // @ ���o��������
1197     if (i < len - 1 && src[i + 1] == '@') { // �������� @ �����A�b�g�}�[�N���F������
1198     *dst++ = '@';
1199     i++;
1200     } else {
1201     *dst++ = ' '; // �������u��������
1202     }
1203     } else {
1204     *dst++ = src[i];
1205     }
1206     }
1207     *dst = '\0';
1208     }
1209    
1210 yutakakn 2728 /* returns 1 if the option text must be deleted */
1211     static int parse_option(PTInstVar pvar, char FAR * option)
1212     {
1213     if ((option[0] == '-' || option[0] == '/')) {
1214     if (MATCH_STR(option + 1, "ssh") == 0) {
1215     if (option[4] == 0) {
1216     pvar->settings.Enabled = 1;
1217     } else if (MATCH_STR(option + 4, "-L") == 0
1218     || MATCH_STR(option + 4, "-R") == 0
1219 yutakakn 2850 || _stricmp(option + 4, "-X") == 0) {
1220 yutakakn 2728 if (pvar->settings.DefaultForwarding[0] == 0) {
1221     strcpy(pvar->settings.DefaultForwarding, option + 5);
1222     } else {
1223     strcat(pvar->settings.DefaultForwarding, ";");
1224     strcat(pvar->settings.DefaultForwarding, option + 5);
1225     }
1226     } else if (MATCH_STR(option + 4, "-f=") == 0) {
1227     read_ssh_options_from_user_file(pvar, option + 7);
1228     } else if (MATCH_STR(option + 4, "-v") == 0) {
1229     pvar->settings.LogLevel = LOG_LEVEL_VERBOSE;
1230 yutakakn 2850 } else if (_stricmp(option + 4, "-autologin") == 0
1231     || _stricmp(option + 4, "-autologon") == 0) {
1232 yutakakn 2728 pvar->settings.TryDefaultAuth = TRUE;
1233 yutakakn 2739
1234 yutakakn 2728 } else if (MATCH_STR(option + 4, "-consume=") == 0) {
1235     read_ssh_options_from_user_file(pvar, option + 13);
1236     DeleteFile(option + 13);
1237     } else {
1238     char buf[1024];
1239    
1240     _snprintf(buf, sizeof(buf),
1241     "Unrecognized command-line option: %s", option);
1242     buf[sizeof(buf) - 1] = 0;
1243    
1244     MessageBox(NULL, buf, "TTSSH", MB_OK | MB_ICONEXCLAMATION);
1245     }
1246    
1247     return 1;
1248     } else if (MATCH_STR(option + 1, "t=") == 0) {
1249     if (strcmp(option + 3, "2") == 0) {
1250     pvar->settings.Enabled = 1;
1251     return 1;
1252     } else {
1253     pvar->settings.Enabled = 0;
1254     }
1255     } else if (MATCH_STR(option + 1, "f=") == 0) {
1256     read_ssh_options_from_user_file(pvar, option + 3);
1257    
1258     // /1 ������ /2 �I�v�V�������V�K���� (2004.10.3 yutaka)
1259     } else if (MATCH_STR(option + 1, "1") == 0) {
1260     // command line: /ssh /1 is SSH1 only
1261     pvar->settings.ssh_protocol_version = 1;
1262    
1263     } else if (MATCH_STR(option + 1, "2") == 0) {
1264     // command line: /ssh /2 is SSH2 & SSH1
1265     pvar->settings.ssh_protocol_version = 2;
1266    
1267     } else if (MATCH_STR(option + 1, "nossh") == 0) {
1268     // '/nossh' �I�v�V�����������B
1269     // TERATERM.INI ��SSH���L�������������������A������Cygterm���N��������������
1270     // �����������������B(2004.10.11 yutaka)
1271     pvar->settings.Enabled = 0;
1272    
1273 yutakakn 2739 } else if (MATCH_STR(option + 1, "auth") == 0) {
1274 yutakakn 2784 // SSH2�������O�C���I�v�V����������
1275 yutakakn 2739 //
1276 yutakakn 2784 // SYNOPSIS: /ssh /auth=passowrd /user=���[�U�� /passwd=�p�X���[�h
1277     // /ssh /auth=publickey /user=���[�U�� /passwd=�p�X���[�h /keyfile=�p�X
1278     // EXAMPLE: /ssh /auth=password /user=nike /passwd=a@bc
1279     // /ssh /auth=publickey /user=foo /passwd=bar /keyfile=d:\tmp\id_rsa
1280     // NOTICE: �p�X���[�h���p�X�������������������A�u�����N���������� @ ���g�������B
1281 yutakakn 2739 //
1282 yutakakn 2784 // (2004.11.30 yutaka)
1283     // (2005.1.26 yutaka) ���������B���J���F���T�|�[�g�B
1284     //
1285 yutakakn 2739 pvar->ssh2_autologin = 1; // for SSH2 (2004.11.30 yutaka)
1286    
1287 yutakakn 2784 if (MATCH_STR(option + 5, "=password") == 0) { // �p�X���[�h/keyboard-interactive�F��
1288     //pvar->auth_state.cur_cred.method = SSH_AUTH_PASSWORD;
1289     pvar->ssh2_authmethod = SSH_AUTH_PASSWORD;
1290 yutakakn 2739
1291 yutakakn 2784 } else if (MATCH_STR(option + 5, "=publickey") == 0) { // ���J���F��
1292     //pvar->auth_state.cur_cred.method = SSH_AUTH_RSA;
1293     pvar->ssh2_authmethod = SSH_AUTH_RSA;
1294    
1295 yutakakn 2739 } else {
1296     // TODO:
1297    
1298     }
1299    
1300     } else if (MATCH_STR(option + 1, "user=") == 0) {
1301 yutakakn 2784 replace_to_blank(option + 6, pvar->ssh2_username, sizeof(pvar->ssh2_username));
1302     //_snprintf(pvar->ssh2_username, sizeof(pvar->ssh2_username), "%s", option + 6);
1303 yutakakn 2739
1304     } else if (MATCH_STR(option + 1, "passwd=") == 0) {
1305 yutakakn 2784 replace_to_blank(option + 8, pvar->ssh2_password, sizeof(pvar->ssh2_password));
1306     //_snprintf(pvar->ssh2_password, sizeof(pvar->ssh2_password), "%s", option + 8);
1307 yutakakn 2739
1308 yutakakn 2784 } else if (MATCH_STR(option + 1, "keyfile=") == 0) {
1309     replace_to_blank(option + 9, pvar->ssh2_keyfile, sizeof(pvar->ssh2_keyfile));
1310    
1311 yutakakn 2728 }
1312    
1313     }
1314    
1315     return 0;
1316     }
1317    
1318     static void FAR PASCAL TTXParseParam(PCHAR param, PTTSet ts,
1319     PCHAR DDETopic)
1320     {
1321     int i;
1322     BOOL inParam = FALSE;
1323     BOOL inQuotes = FALSE;
1324     PCHAR option = NULL;
1325     GET_VAR();
1326    
1327     if (pvar->hostdlg_activated) {
1328     pvar->settings.Enabled = pvar->hostdlg_Enabled;
1329     }
1330    
1331     for (i = 0; param[i] != 0; i++) {
1332     if (inQuotes ? param[i] ==
1333     '"' : (param[i] == ' ' || param[i] == '\t')) {
1334     if (option != NULL) {
1335     char ch = param[i];
1336    
1337     param[i] = 0;
1338     if (parse_option
1339     (pvar, *option == '"' ? option + 1 : option)) {
1340     memset(option, ' ', i + 1 - (option - param));
1341     } else {
1342     param[i] = ch;
1343     }
1344     option = NULL;
1345     }
1346     inParam = FALSE;
1347     inQuotes = FALSE;
1348     } else if (!inParam) {
1349     if (param[i] == '"') {
1350     inQuotes = TRUE;
1351     inParam = TRUE;
1352     option = param + i;
1353     } else if (param[i] != ' ' && param[i] != '\t') {
1354     inParam = TRUE;
1355     option = param + i;
1356     }
1357     }
1358     }
1359    
1360     if (option != NULL) {
1361     if (parse_option(pvar, option)) {
1362     memset(option, ' ', i - (option - param));
1363     }
1364     }
1365    
1366     FWDUI_load_settings(pvar);
1367    
1368     (pvar->ParseParam) (param, ts, DDETopic);
1369    
1370     }
1371    
1372     static void PASCAL FAR TTXGetSetupHooks(TTXSetupHooks FAR * hooks)
1373     {
1374     GET_VAR();
1375    
1376     pvar->ReadIniFile = *hooks->ReadIniFile;
1377     pvar->WriteIniFile = *hooks->WriteIniFile;
1378     pvar->ParseParam = *hooks->ParseParam;
1379    
1380     *hooks->ReadIniFile = TTXReadINIFile;
1381     *hooks->WriteIniFile = TTXWriteINIFile;
1382     *hooks->ParseParam = TTXParseParam;
1383     }
1384    
1385     static void PASCAL FAR TTXSetWinSize(int rows, int cols)
1386     {
1387     GET_VAR();
1388    
1389     SSH_notify_win_size(pvar, cols, rows);
1390     }
1391    
1392     static void insertMenuBeforeItem(HMENU menu, WORD beforeItemID, WORD flags,
1393     WORD newItemID, char FAR * text)
1394     {
1395     int i, j;
1396    
1397     for (i = GetMenuItemCount(menu) - 1; i >= 0; i--) {
1398     HMENU submenu = GetSubMenu(menu, i);
1399    
1400     for (j = GetMenuItemCount(submenu) - 1; j >= 0; j--) {
1401     if (GetMenuItemID(submenu, j) == beforeItemID) {
1402     InsertMenu(submenu, j, MF_BYPOSITION | flags, newItemID,
1403     text);
1404     return;
1405     }
1406     }
1407     }
1408     }
1409    
1410     static void PASCAL FAR TTXModifyMenu(HMENU menu)
1411     {
1412     GET_VAR();
1413    
1414     /* inserts before ID_HELP_ABOUT */
1415     insertMenuBeforeItem(menu, 50990, MF_ENABLED, ID_ABOUTMENU,
1416     "About &TTSSH...");
1417    
1418     /* inserts before ID_SETUP_TCPIP */
1419     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHSETUPMENU,
1420     "SS&H...");
1421     /* inserts before ID_SETUP_TCPIP */
1422     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHAUTHSETUPMENU,
1423     "SSH &Authentication...");
1424     /* inserts before ID_SETUP_TCPIP */
1425     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHFWDSETUPMENU,
1426     "SSH F&orwarding...");
1427 yutakakn 2816
1428     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHKEYGENMENU,
1429     "SSH KeyGenerator...");
1430 yutakakn 2728 }
1431    
1432     static void append_about_text(HWND dlg, char FAR * prefix, char FAR * msg)
1433     {
1434     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1435     (LPARAM) prefix);
1436     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0, (LPARAM) msg);
1437     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1438     (LPARAM) (char FAR *) "\r\n");
1439     }
1440    
1441 yutakakn 2792 // ���s�t�@�C�������o�[�W�������������� (2005.2.28 yutaka)
1442 yutakakn 2793 void get_file_version(char *exefile, int *major, int *minor, int *release, int *build)
1443 yutakakn 2792 {
1444     typedef struct {
1445     WORD wLanguage;
1446     WORD wCodePage;
1447     } LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
1448     LPLANGANDCODEPAGE lplgcode;
1449     UINT unLen;
1450     DWORD size;
1451     char *buf = NULL;
1452     BOOL ret;
1453     int i;
1454     char fmt[80];
1455     char *pbuf;
1456    
1457     size = GetFileVersionInfoSize(exefile, NULL);
1458     if (size == 0) {
1459     goto error;
1460     }
1461     buf = malloc(size);
1462     ZeroMemory(buf, size);
1463    
1464     if (GetFileVersionInfo(exefile, 0, size, buf) == FALSE) {
1465     goto error;
1466     }
1467    
1468     ret = VerQueryValue(buf,
1469     "\\VarFileInfo\\Translation",
1470     (LPVOID *)&lplgcode, &unLen);
1471     if (ret == FALSE)
1472     goto error;
1473    
1474     for (i = 0 ; i < (int)(unLen / sizeof(LANGANDCODEPAGE)) ; i++) {
1475     _snprintf(fmt, sizeof(fmt), "\\StringFileInfo\\%04x%04x\\FileVersion",
1476     lplgcode[i].wLanguage, lplgcode[i].wCodePage);
1477     VerQueryValue(buf, fmt, &pbuf, &unLen);
1478     if (unLen > 0) { // get success
1479     int n, a, b, c, d;
1480    
1481     n = sscanf(pbuf, "%d, %d, %d, %d", &a, &b, &c, &d);
1482     if (n == 4) { // convert success
1483     *major = a;
1484     *minor = b;
1485     *release = c;
1486     *build = d;
1487     break;
1488     }
1489     }
1490     }
1491    
1492     free(buf);
1493     return;
1494    
1495     error:
1496     free(buf);
1497     *major = *minor = *release = *build = 0;
1498     }
1499    
1500 yutakakn 2728 static void init_about_dlg(PTInstVar pvar, HWND dlg)
1501     {
1502     char buf[1024];
1503 yutakakn 2792 int a, b, c, d;
1504 yutakakn 2728
1505 yutakakn 2792 // TTSSH���o�[�W�������������� (2005.2.28 yutaka)
1506     get_file_version("ttxssh.dll", &a, &b, &c, &d);
1507     _snprintf(buf, sizeof(buf), "TTSSH\r\nTeraterm Secure Shell extension, %d.%d", a, b);
1508     SendMessage(GetDlgItem(dlg, IDC_TTSSH_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1509    
1510 yutakakn 2782 // OpenSSL���o�[�W�������������� (2005.1.24 yutaka)
1511 yutakakn 2820 // ���������� (2005.5.11 yutaka)
1512     #ifdef OPENSSL_VERSION_TEXT
1513 yutakakn 2782 SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)OPENSSL_VERSION_TEXT);
1514 yutakakn 2820 #else
1515     SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)"Unknown");
1516     #endif
1517 yutakakn 2782
1518 yutakakn 2820 // zlib���o�[�W�������������� (2005.5.11 yutaka)
1519     #ifdef ZLIB_VERSION
1520 yutakakn 2823 _snprintf(buf, sizeof(buf), "ZLib %s", ZLIB_VERSION);
1521 yutakakn 2820 #else
1522 yutakakn 2823 _snprintf(buf, sizeof(buf), "ZLib Unknown");
1523 yutakakn 2820 #endif
1524     SendMessage(GetDlgItem(dlg, IDC_ZLIB_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1525    
1526    
1527 yutakakn 2728 // TTSSH�_�C�A���O���\������SSH������������ (2004.10.30 yutaka)
1528     if (pvar->socket != INVALID_SOCKET) {
1529     if (SSHv1(pvar)) {
1530     SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1531     append_about_text(dlg, "Server ID: ", buf);
1532     SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1533     append_about_text(dlg, "Using protocol: ", buf);
1534     CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1535     append_about_text(dlg, "Encryption: ", buf);
1536     CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1537     append_about_text(dlg, "Server keys: ", buf);
1538     AUTH_get_auth_info(pvar, buf, sizeof(buf));
1539     append_about_text(dlg, "Authentication: ", buf);
1540     SSH_get_compression_info(pvar, buf, sizeof(buf));
1541     append_about_text(dlg, "Compression: ", buf);
1542    
1543     } else { // SSH2
1544     SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1545     append_about_text(dlg, "Server ID: ", buf);
1546    
1547     append_about_text(dlg, "Client ID: ", pvar->client_version_string);
1548    
1549     SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1550     append_about_text(dlg, "Using protocol: ", buf);
1551    
1552     if (pvar->kex_type == KEX_DH_GRP1_SHA1) {
1553     strcpy(buf, KEX_DH1);
1554     } else if (pvar->kex_type == KEX_DH_GRP14_SHA1) {
1555     strcpy(buf, KEX_DH14);
1556     } else {
1557     strcpy(buf, KEX_DHGEX);
1558     }
1559     append_about_text(dlg, "KEX: ", buf);
1560    
1561     if (pvar->hostkey_type == KEY_DSA) {
1562     strcpy(buf, "ssh-dss");
1563     } else {
1564     strcpy(buf, "ssh-rsa");
1565     }
1566     append_about_text(dlg, "Host Key: ", buf);
1567    
1568 yutakakn 2758 // add HMAC algorithm (2004.12.17 yutaka)
1569     buf[0] = '\0';
1570     if (pvar->ctos_hmac == HMAC_SHA1) {
1571     strcat(buf, "hmac-sha1");
1572     } else if (pvar->ctos_hmac == HMAC_MD5) {
1573     strcat(buf, "hmac-md5");
1574     }
1575     strcat(buf, " to server, ");
1576     if (pvar->stoc_hmac == HMAC_SHA1) {
1577     strcat(buf, "hmac-sha1");
1578     } else if (pvar->stoc_hmac == HMAC_MD5) {
1579     strcat(buf, "hmac-md5");
1580     }
1581     strcat(buf, " from server");
1582     append_about_text(dlg, "HMAC: ", buf);
1583    
1584 yutakakn 2728 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1585     append_about_text(dlg, "Encryption: ", buf);
1586     CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1587     append_about_text(dlg, "Server keys: ", buf);
1588     AUTH_get_auth_info(pvar, buf, sizeof(buf));
1589     append_about_text(dlg, "Authentication: ", buf);
1590     SSH_get_compression_info(pvar, buf, sizeof(buf));
1591     append_about_text(dlg, "Compression: ", buf);
1592    
1593     }
1594     }
1595     }
1596    
1597     static BOOL CALLBACK TTXAboutDlg(HWND dlg, UINT msg, WPARAM wParam,
1598     LPARAM lParam)
1599     {
1600     switch (msg) {
1601     case WM_INITDIALOG:
1602     init_about_dlg((PTInstVar) lParam, dlg);
1603     return TRUE;
1604     case WM_COMMAND:
1605     switch (LOWORD(wParam)) {
1606     case IDOK:
1607     EndDialog(dlg, 1);
1608     return TRUE;
1609     case IDCANCEL: /* there isn't a cancel button, but other Windows
1610     UI things can send this message */
1611     EndDialog(dlg, 0);
1612     return TRUE;
1613     }
1614     break;
1615     }
1616    
1617     return FALSE;
1618     }
1619    
1620     static char FAR *get_cipher_name(int cipher)
1621     {
1622     switch (cipher) {
1623     case SSH_CIPHER_NONE:
1624     return "<ciphers below this line are disabled>";
1625     case SSH_CIPHER_RC4:
1626     return "RC4";
1627     case SSH_CIPHER_3DES:
1628     return "3DES";
1629     case SSH_CIPHER_DES:
1630     return "DES";
1631     case SSH_CIPHER_IDEA:
1632     return "IDEA";
1633     case SSH_CIPHER_TSS:
1634     return "TSS";
1635     case SSH_CIPHER_BLOWFISH:
1636     return "Blowfish";
1637    
1638     // for SSH2(yutaka)
1639     case SSH_CIPHER_AES128:
1640     return "AES128(SSH2)";
1641     case SSH_CIPHER_3DES_CBC:
1642     return "3DES-CBC(SSH2)";
1643    
1644     default:
1645     return NULL;
1646     }
1647     }
1648    
1649     static void set_move_button_status(HWND dlg)
1650     {
1651     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1652     int curPos = (int) SendMessage(cipherControl, LB_GETCURSEL, 0, 0);
1653     int maxPos = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0) - 1;
1654    
1655     EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERUP), curPos > 0
1656     && curPos <= maxPos);
1657     EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERDOWN), curPos >= 0
1658     && curPos < maxPos);
1659     }
1660    
1661     static void init_setup_dlg(PTInstVar pvar, HWND dlg)
1662     {
1663     HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1664     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1665     int i;
1666     int ch;
1667    
1668     SendMessage(compressionControl, TBM_SETRANGE, TRUE, MAKELONG(0, 9));
1669     SendMessage(compressionControl, TBM_SETPOS, TRUE,
1670     pvar->settings.CompressionLevel);
1671    
1672     normalize_cipher_order(pvar->settings.CipherOrder);
1673     SSH2_update_cipher_myproposal(pvar); // yutaka
1674    
1675     for (i = 0; pvar->settings.CipherOrder[i] != 0; i++) {
1676     int cipher = pvar->settings.CipherOrder[i] - '0';
1677     char FAR *name = get_cipher_name(cipher);
1678    
1679     if (name != NULL) {
1680     SendMessage(cipherControl, LB_ADDSTRING, 0, (LPARAM) name);
1681     }
1682     }
1683    
1684     SendMessage(cipherControl, LB_SETCURSEL, 0, 0);
1685     set_move_button_status(dlg);
1686    
1687     for (i = 0; (ch = pvar->settings.KnownHostsFiles[i]) != 0 && ch != ';';
1688     i++) {
1689     }
1690     if (ch != 0) {
1691     pvar->settings.KnownHostsFiles[i] = 0;
1692     SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1693     pvar->settings.KnownHostsFiles);
1694     pvar->settings.KnownHostsFiles[i] = ch;
1695     SetDlgItemText(dlg, IDC_READONLYFILENAME,
1696     pvar->settings.KnownHostsFiles + i + 1);
1697     } else {
1698     SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1699     pvar->settings.KnownHostsFiles);
1700     }
1701 yutakakn 2789
1702     // SSH2 HeartBeat(keep-alive)������ (2005.2.22 yutaka)
1703     {
1704     char buf[10];
1705     _snprintf(buf, sizeof(buf), "%d", pvar->settings.ssh_heartbeat_overtime);
1706     SetDlgItemText(dlg, IDC_HEARTBEAT_EDIT, buf);
1707     }
1708    
1709 yutakakn 2728 }
1710    
1711     void get_teraterm_dir_relative_name(char FAR * buf, int bufsize,
1712     char FAR * basename)
1713     {
1714     int filename_start = 0;
1715     int i;
1716     int ch;
1717    
1718     if (basename[0] == '\\' || basename[0] == '/'
1719     || (basename[0] != 0 && basename[1] == ':')) {
1720     strncpy(buf, basename, bufsize);
1721     buf[bufsize - 1] = 0;
1722     return;
1723     }
1724    
1725     GetModuleFileName(NULL, buf, bufsize);
1726     for (i = 0; (ch = buf[i]) != 0; i++) {
1727     if (ch == '\\' || ch == '/' || ch == ':') {
1728     filename_start = i + 1;
1729     }
1730     }
1731    
1732     if (bufsize > filename_start) {
1733     strncpy(buf + filename_start, basename, bufsize - filename_start);
1734     }
1735     buf[bufsize - 1] = 0;
1736     }
1737    
1738     int copy_teraterm_dir_relative_path(char FAR * dest, int destsize,
1739     char FAR * basename)
1740     {
1741     char buf[1024];
1742     int filename_start = 0;
1743     int i;
1744     int ch, ch2;
1745    
1746     if (basename[0] != '\\' && basename[0] != '/'
1747     && (basename[0] == 0 || basename[1] != ':')) {
1748     strncpy(dest, basename, destsize);
1749     dest[destsize - 1] = 0;
1750     return strlen(dest);
1751     }
1752    
1753     GetModuleFileName(NULL, buf, sizeof(buf));
1754     for (i = 0; (ch = buf[i]) != 0; i++) {
1755     if (ch == '\\' || ch == '/' || ch == ':') {
1756     filename_start = i + 1;
1757     }
1758     }
1759    
1760     for (i = 0; i < filename_start; i++) {
1761     ch = toupper(buf[i]);
1762     ch2 = toupper(basename[i]);
1763    
1764     if (ch == ch2
1765     || ((ch == '\\' || ch == '/')
1766     && (ch2 == '\\' || ch2 == '/'))) {
1767     } else {
1768     break;
1769     }
1770     }
1771    
1772     if (i == filename_start) {
1773     strncpy(dest, basename + i, destsize);
1774     } else {
1775     strncpy(dest, basename, destsize);
1776     }
1777     dest[destsize - 1] = 0;
1778     return strlen(dest);
1779     }
1780    
1781     static void complete_setup_dlg(PTInstVar pvar, HWND dlg)
1782     {
1783     char buf[4096];
1784     char buf2[1024];
1785     HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1786     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1787     int i, j, buf2index, bufindex;
1788     int count = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0);
1789    
1790     pvar->settings.CompressionLevel =
1791     (int) SendMessage(compressionControl, TBM_GETPOS, 0, 0);
1792    
1793     buf2index = 0;
1794     for (i = 0; i < count; i++) {
1795     int len = SendMessage(cipherControl, LB_GETTEXTLEN, i, 0);
1796    
1797     if (len > 0 && len < sizeof(buf)) { /* should always be true */
1798     buf[0] = 0;
1799     SendMessage(cipherControl, LB_GETTEXT, i, (LPARAM) buf);
1800     for (j = 0;
1801     j <= SSH_CIPHER_MAX
1802     && strcmp(buf, get_cipher_name(j)) != 0; j++) {
1803     }
1804     if (j <= SSH_CIPHER_MAX) {
1805     buf2[buf2index] = '0' + j;
1806     buf2index++;
1807     }
1808     }
1809     }
1810     buf2[buf2index] = 0;
1811     normalize_cipher_order(buf2);
1812     strcpy(pvar->settings.CipherOrder, buf2);
1813     SSH2_update_cipher_myproposal(pvar); // yutaka
1814    
1815     buf[0] = 0;
1816     GetDlgItemText(dlg, IDC_READWRITEFILENAME, buf, sizeof(buf));
1817     j = copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles,
1818     sizeof(pvar->settings.
1819     KnownHostsFiles), buf);
1820     buf[0] = 0;
1821     bufindex = 0;
1822     GetDlgItemText(dlg, IDC_READONLYFILENAME, buf, sizeof(buf));
1823     for (i = 0; buf[i] != 0; i++) {
1824     if (buf[i] == ';') {
1825     buf[i] = 0;
1826     if (j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1827     pvar->settings.KnownHostsFiles[j] = ';';
1828     j++;
1829     j += copy_teraterm_dir_relative_path(pvar->settings.
1830     KnownHostsFiles + j,
1831     sizeof(pvar->settings.
1832     KnownHostsFiles)
1833     - j, buf + bufindex);
1834     }
1835     bufindex = i + 1;
1836     }
1837     }
1838     if (bufindex < i && j < sizeof(pvar->settings.KnownHostsFiles) - 1) {
1839     pvar->settings.KnownHostsFiles[j] = ';';
1840     j++;
1841     copy_teraterm_dir_relative_path(pvar->settings.KnownHostsFiles + j,
1842     sizeof(pvar->settings.
1843     KnownHostsFiles) - j,
1844     buf + bufindex);
1845     }
1846 yutakakn 2789
1847     // get SSH HeartBeat(keep-alive)
1848     SendMessage(GetDlgItem(dlg, IDC_HEARTBEAT_EDIT), WM_GETTEXT, sizeof(buf), (LPARAM)buf);
1849     i = atoi(buf);
1850     if (i < 0)
1851     i = 60;
1852     pvar->settings.ssh_heartbeat_overtime = i;
1853    
1854 yutakakn 2728 }
1855    
1856     static void move_cur_sel_delta(HWND listbox, int delta)
1857     {
1858     int curPos = (int) SendMessage(listbox, LB_GETCURSEL, 0, 0);
1859     int maxPos = (int) SendMessage(listbox, LB_GETCOUNT, 0, 0) - 1;
1860     int newPos = curPos + delta;
1861     char buf[1024];
1862    
1863     if (curPos >= 0 && newPos >= 0 && newPos <= maxPos) {
1864     int len = SendMessage(listbox, LB_GETTEXTLEN, curPos, 0);
1865    
1866     if (len > 0 && len < sizeof(buf)) { /* should always be true */
1867     buf[0] = 0;
1868     SendMessage(listbox, LB_GETTEXT, curPos, (LPARAM) buf);
1869     SendMessage(listbox, LB_DELETESTRING, curPos, 0);
1870     SendMessage(listbox, LB_INSERTSTRING, newPos,
1871     (LPARAM) (char FAR *) buf);
1872     SendMessage(listbox, LB_SETCURSEL, newPos, 0);
1873     }
1874     }
1875     }
1876    
1877     static int get_keys_file_name(HWND parent, char FAR * buf, int bufsize,
1878     int readonly)
1879     {
1880     #ifdef TERATERM32
1881     OPENFILENAME params;
1882     char fullname_buf[2048] = "ssh_known_hosts";
1883    
1884     params.lStructSize = sizeof(OPENFILENAME);
1885     params.hwndOwner = parent;
1886     params.lpstrFilter = NULL;
1887     params.lpstrCustomFilter = NULL;
1888     params.nFilterIndex = 0;
1889     buf[0] = 0;
1890     params.lpstrFile = fullname_buf;
1891     params.nMaxFile = sizeof(fullname_buf);
1892     params.lpstrFileTitle = NULL;
1893     params.lpstrInitialDir = NULL;
1894     params.lpstrTitle =
1895     readonly ? "Choose a read-only known-hosts file to add" :
1896     "Choose a read/write known-hosts file";
1897     params.Flags = (readonly ? OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST : 0)
1898     | OFN_HIDEREADONLY | (!readonly ? OFN_NOREADONLYRETURN : 0);
1899     params.lpstrDefExt = NULL;
1900    
1901     if (GetOpenFileName(&params) != 0) {
1902     copy_teraterm_dir_relative_path(buf, bufsize, fullname_buf);
1903     return 1;
1904     } else {
1905     int err = CommDlgExtendedError();
1906    
1907     if (err != 0) {
1908     char buf[1024];
1909    
1910     _snprintf(buf, sizeof(buf),
1911     "Cannot show file dialog box: error %d", err);
1912     buf[sizeof(buf) - 1] = 0;
1913     MessageBox(parent, buf, "TTSSH Error",
1914     MB_OK | MB_ICONEXCLAMATION);
1915     }
1916    
1917     return 0;
1918     }
1919     #else
1920     return 0;
1921     #endif
1922     }
1923    
1924     static void choose_read_write_file(HWND dlg)
1925     {
1926     char buf[1024];
1927    
1928     if (get_keys_file_name(dlg, buf, sizeof(buf), 0)) {
1929     SetDlgItemText(dlg, IDC_READWRITEFILENAME, buf);
1930     }
1931     }
1932    
1933     static void choose_read_only_file(HWND dlg)
1934     {
1935     char buf[1024];
1936     char buf2[4096];
1937    
1938     if (get_keys_file_name(dlg, buf, sizeof(buf), 1)) {
1939     buf2[0] = 0;
1940     GetDlgItemText(dlg, IDC_READONLYFILENAME, buf2, sizeof(buf2));
1941     if (buf2[0] != 0 && buf2[strlen(buf2) - 1] != ';') {
1942     strncat(buf2, ";", sizeof(buf2));
1943     }
1944     strncat(buf2, buf, sizeof(buf2));
1945     SetDlgItemText(dlg, IDC_READONLYFILENAME, buf2);
1946     }
1947     }
1948    
1949     static BOOL CALLBACK TTXSetupDlg(HWND dlg, UINT msg, WPARAM wParam,
1950     LPARAM lParam)
1951     {
1952     switch (msg) {
1953     case WM_INITDIALOG:
1954     SetWindowLong(dlg, DWL_USER, lParam);
1955     init_setup_dlg((PTInstVar) lParam, dlg);
1956     return TRUE;
1957     case WM_COMMAND:
1958     switch (LOWORD(wParam)) {
1959     case IDOK:
1960     complete_setup_dlg((PTInstVar) GetWindowLong(dlg, DWL_USER),
1961     dlg);
1962     EndDialog(dlg, 1);
1963     return TRUE;
1964     case IDCANCEL: /* there isn't a cancel button, but other Windows
1965     UI things can send this message */
1966     EndDialog(dlg, 0);
1967     return TRUE;
1968     case IDC_SSHMOVECIPHERUP:
1969     move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), -1);
1970     set_move_button_status(dlg);
1971     SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
1972     return TRUE;
1973     case IDC_SSHMOVECIPHERDOWN:
1974     move_cur_sel_delta(GetDlgItem(dlg, IDC_SSHCIPHERPREFS), 1);
1975     set_move_button_status(dlg);
1976     SetFocus(GetDlgItem(dlg, IDC_SSHCIPHERPREFS));
1977     return TRUE;
1978     case IDC_SSHCIPHERPREFS:
1979     set_move_button_status(dlg);
1980     return TRUE;
1981     case IDC_CHOOSEREADWRITEFILE:
1982     choose_read_write_file(dlg);
1983     return TRUE;
1984     case IDC_CHOOSEREADONLYFILE:
1985     choose_read_only_file(dlg);
1986     return TRUE;
1987     }
1988     break;
1989     }
1990    
1991     return FALSE;
1992     }
1993    
1994 yutakakn 2816
1995     //
1996     // SSH key generator dialog (2005.4.10 yutaka)
1997     //
1998    
1999     typedef struct {
2000     RSA *rsa;
2001     DSA *dsa;
2002     } ssh_private_key_t;
2003    
2004     static ssh_private_key_t private_key = {NULL, NULL};
2005    
2006     typedef struct {
2007     RSA *rsa;
2008     DSA *dsa;
2009     } ssh_public_key_t;
2010    
2011     static ssh_public_key_t public_key = {NULL, NULL};;
2012    
2013     static void free_ssh_key(void)
2014     {
2015     // DSA_free(), RSA_free()��NULL���n�����������������B
2016     DSA_free(private_key.dsa);
2017     private_key.dsa = NULL;
2018     DSA_free(public_key.dsa);
2019     public_key.dsa = NULL;
2020    
2021     RSA_free(private_key.rsa);
2022     private_key.rsa = NULL;
2023     RSA_free(public_key.rsa);
2024     public_key.rsa = NULL;
2025     }
2026    
2027    
2028     static BOOL generate_ssh_key(enum hostkey_type type)
2029     {
2030     int bits = 1024;
2031    
2032     // if SSH key already is generated, should free the resource.
2033     free_ssh_key();
2034    
2035     if (type == KEY_RSA1 || type == KEY_RSA) {
2036     RSA *priv = NULL;
2037     RSA *pub = NULL;
2038    
2039     // private key
2040     priv = RSA_generate_key(bits, 35, NULL, NULL);
2041     if (priv == NULL)
2042     goto error;
2043     private_key.rsa = priv;
2044    
2045     // public key
2046     pub = RSA_new();
2047     pub->n = BN_new();
2048     pub->e = BN_new();
2049     if (pub->n == NULL || pub->e == NULL) {
2050     RSA_free(pub);
2051     goto error;
2052     }
2053    
2054     BN_copy(pub->n, priv->n);
2055     BN_copy(pub->e, priv->e);
2056     public_key.rsa = pub;
2057    
2058     } else if (type == KEY_DSA) {
2059     DSA *priv = NULL;
2060     DSA *pub = NULL;
2061    
2062     // private key
2063     priv = DSA_generate_parameters(bits, NULL, 0, NULL, NULL, NULL, NULL);
2064     if (priv == NULL)
2065     goto error;
2066     if (!DSA_generate_key(priv)) {
2067     // TODO: free 'priv'?
2068     goto error;
2069     }
2070     private_key.dsa = priv;
2071    
2072     // public key
2073     pub = DSA_new();
2074     if (pub == NULL)
2075     goto error;
2076     pub->p = BN_new();
2077     pub->q = BN_new();
2078     pub->g = BN_new();
2079     pub->pub_key = BN_new();
2080     if (pub->p == NULL || pub->q == NULL || pub->g == NULL || pub->pub_key == NULL) {
2081     DSA_free(pub);
2082     goto error;
2083     }
2084    
2085     BN_copy(pub->p, priv->p);
2086     BN_copy(pub->q, priv->q);
2087     BN_copy(pub->g, priv->g);
2088     BN_copy(pub->pub_key, priv->pub_key);
2089     public_key.dsa = pub;
2090    
2091     } else {
2092     goto error;
2093     }
2094    
2095     return TRUE;
2096    
2097     error:
2098     free_ssh_key();
2099     return FALSE;
2100     }
2101    
2102    
2103     //
2104     // RC4
2105     //
2106    
2107     /* Size of key to use */
2108     #define SEED_SIZE 20
2109    
2110     /* Number of bytes to reseed after */
2111     #define REKEY_BYTES (1 << 24)
2112    
2113     static int rc4_ready = 0;
2114     static RC4_KEY rc4;
2115    
2116     static void seed_rng(void)
2117     {
2118     if (RAND_status() != 1)
2119     return;
2120     }
2121    
2122     static void arc4random_stir(void)
2123     {
2124     unsigned char rand_buf[SEED_SIZE];
2125     int i;
2126    
2127     memset(&rc4, 0, sizeof(rc4));
2128     if (RAND_bytes(rand_buf, sizeof(rand_buf)) <= 0) {
2129     //fatal("Couldn't obtain random bytes (error %ld)",
2130     // ERR_get_error());
2131     }
2132     RC4_set_key(&rc4, sizeof(rand_buf), rand_buf);
2133    
2134     /*
2135     * Discard early keystream, as per recommendations in:
2136     * http://www.wisdom.weizmann.ac.il/~itsik/RC4/Papers/Rc4_ksa.ps
2137     */
2138     for(i = 0; i <= 256; i += sizeof(rand_buf))
2139     RC4(&rc4, sizeof(rand_buf), rand_buf, rand_buf);
2140    
2141     memset(rand_buf, 0, sizeof(rand_buf));
2142    
2143     rc4_ready = REKEY_BYTES;
2144     }
2145    
2146     static unsigned int arc4random(void)
2147     {
2148     unsigned int r = 0;
2149     static int first_time = 1;
2150    
2151     if (rc4_ready <= 0) {
2152     if (first_time) {
2153     seed_rng();
2154     }
2155     first_time = 0;
2156     arc4random_stir();
2157     }
2158    
2159     RC4(&rc4, sizeof(r), (unsigned char *)&r, (unsigned char *)&r);
2160    
2161     rc4_ready -= sizeof(r);
2162    
2163     return(r);
2164     }
2165    
2166     //
2167     // SSH1 3DES
2168     //
2169     /*
2170     * This is used by SSH1:
2171     *
2172     * What kind of triple DES are these 2 routines?
2173     *
2174     * Why is there a redundant initialization vector?
2175     *
2176     * If only iv3 was used, then, this would till effect have been
2177     * outer-cbc. However, there is also a private iv1 == iv2 which
2178     * perhaps makes differential analysis easier. On the other hand, the
2179     * private iv1 probably makes the CRC-32 attack ineffective. This is a
2180     * result of that there is no longer any known iv1 to use when
2181     * choosing the X block.
2182     */
2183     struct ssh1_3des_ctx
2184     {
2185     EVP_CIPHER_CTX k1, k2, k3;
2186     };
2187    
2188     static int ssh1_3des_init(EVP_CIPHER_CTX *ctx, const u_char *key, const u_char *iv, int enc)
2189     {
2190     struct ssh1_3des_ctx *c;
2191     u_char *k1, *k2, *k3;
2192    
2193     if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
2194     c = malloc(sizeof(*c));
2195     EVP_CIPHER_CTX_set_app_data(ctx, c);
2196     }
2197     if (key == NULL)
2198     return (1);
2199     if (enc == -1)
2200     enc = ctx->encrypt;
2201     k1 = k2 = k3 = (u_char *) key;
2202     k2 += 8;
2203     if (EVP_CIPHER_CTX_key_length(ctx) >= 16+8) {
2204     if (enc)
2205     k3 += 16;
2206     else
2207     k1 += 16;
2208     }
2209     EVP_CIPHER_CTX_init(&c->k1);
2210     EVP_CIPHER_CTX_init(&c->k2);
2211     EVP_CIPHER_CTX_init(&c->k3);
2212     if (EVP_CipherInit(&c->k1, EVP_des_cbc(), k1, NULL, enc) == 0 ||
2213     EVP_CipherInit(&c->k2, EVP_des_cbc(), k2, NULL, !enc) == 0 ||
2214     EVP_CipherInit(&c->k3, EVP_des_cbc(), k3, NULL, enc) == 0) {
2215     memset(c, 0, sizeof(*c));
2216     free(c);
2217     EVP_CIPHER_CTX_set_app_data(ctx, NULL);
2218     return (0);
2219     }
2220     return (1);
2221     }
2222    
2223     static int ssh1_3des_cbc(EVP_CIPHER_CTX *ctx, u_char *dest, const u_char *src, u_int len)
2224     {
2225     struct ssh1_3des_ctx *c;
2226    
2227     if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) == NULL) {
2228     //error("ssh1_3des_cbc: no context");
2229     return (0);
2230     }
2231     if (EVP_Cipher(&c->k1, dest, (u_char *)src, len) == 0 ||
2232     EVP_Cipher(&c->k2, dest, dest, len) == 0 ||
2233     EVP_Cipher(&c->k3, dest, dest, len) == 0)
2234     return (0);
2235     return (1);
2236     }
2237    
2238     static int ssh1_3des_cleanup(EVP_CIPHER_CTX *ctx)
2239     {
2240     struct ssh1_3des_ctx *c;
2241    
2242     if ((c = EVP_CIPHER_CTX_get_app_data(ctx)) != NULL) {
2243     EVP_CIPHER_CTX_cleanup(&c->k1);
2244     EVP_CIPHER_CTX_cleanup(&c->k2);
2245     EVP_CIPHER_CTX_cleanup(&c->k3);
2246     memset(c, 0, sizeof(*c));
2247     free(c);
2248     EVP_CIPHER_CTX_set_app_data(ctx, NULL);
2249     }
2250     return (1);
2251     }
2252    
2253     void ssh1_3des_iv(EVP_CIPHER_CTX *evp, int doset, u_char *iv, int len)
2254     {
2255     struct ssh1_3des_ctx *c;
2256    
2257     if (len != 24)
2258     //fatal("%s: bad 3des iv length: %d", __func__, len);
2259     ;
2260    
2261     if ((c = EVP_CIPHER_CTX_get_app_data(evp)) == NULL)
2262     //fatal("%s: no 3des context", __func__);
2263     ;
2264    
2265     if (doset) {
2266     //debug3("%s: Installed 3DES IV", __func__);
2267     memcpy(c->k1.iv, iv, 8);
2268     memcpy(c->k2.iv, iv + 8, 8);
2269     memcpy(c->k3.iv, iv + 16, 8);
2270     } else {
2271     //debug3("%s: Copying 3DES IV", __func__);
2272     memcpy(iv, c->k1.iv, 8);
2273     memcpy(iv + 8, c->k2.iv, 8);
2274     memcpy(iv + 16, c->k3.iv, 8);
2275     }
2276     }
2277    
2278     const EVP_CIPHER *evp_ssh1_3des(void)
2279     {
2280     static EVP_CIPHER ssh1_3des;
2281    
2282     memset(&ssh1_3des, 0, sizeof(EVP_CIPHER));
2283     ssh1_3des.nid = NID_undef;
2284     ssh1_3des.block_size = 8;
2285     ssh1_3des.iv_len = 0;
2286     ssh1_3des.key_len = 16;
2287     ssh1_3des.init = ssh1_3des_init;
2288     ssh1_3des.cleanup = ssh1_3des_cleanup;
2289     ssh1_3des.do_cipher = ssh1_3des_cbc;
2290     ssh1_3des.flags = EVP_CIPH_CBC_MODE | EVP_CIPH_VARIABLE_LENGTH;
2291     return (&ssh1_3des);
2292     }
2293    
2294     static void ssh_make_comment(char *comment, int maxlen)
2295     {
2296     char user[UNLEN + 1], host[128];
2297     DWORD dwSize;
2298     WSADATA wsaData;
2299     int ret;
2300    
2301     // get Windows logon user name
2302     dwSize = sizeof(user);
2303     if (GetUserName(user, &dwSize) == 0) {
2304     strcpy(user, "yutaka");
2305     }
2306    
2307     // get local hostname (by WinSock)
2308     ret = WSAStartup(MAKEWORD(2,2), &wsaData);
2309     if (ret == 0) {
2310     if (gethostname(host, sizeof(host)) != 0) {
2311     ret = WSAGetLastError();
2312     }
2313     WSACleanup();
2314     }
2315     if (ret != 0) {
2316     strcpy(host, "sai");
2317     }
2318    
2319     _snprintf(comment, maxlen, "%s@%s", user, host);
2320     }
2321    
2322     // uuencode (rfc1521)
2323 yutakakn 2856 int uuencode(unsigned char *src, int srclen, unsigned char *target, int targsize)
2324 yutakakn 2816 {
2325     char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2326     char pad = '=';
2327     int datalength = 0;
2328     unsigned char input[3];
2329     unsigned char output[4];
2330     int i;
2331    
2332     while (srclen > 2) {
2333     input[0] = *src++;
2334     input[1] = *src++;
2335     input[2] = *src++;
2336     srclen -= 3;
2337    
2338     output[0] = input[0] >> 2;
2339     output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
2340     output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
2341     output[3] = input[2] & 0x3f;
2342     if (output[0] >= 64 ||
2343     output[1] >= 64 ||
2344     output[2] >= 64 ||
2345     output[3] >= 64)
2346     return -1;
2347    
2348     if (datalength + 4 > targsize)
2349     return (-1);
2350     target[datalength++] = base64[output[0]];
2351     target[datalength++] = base64[output[1]];
2352     target[datalength++] = base64[output[2]];
2353     target[datalength++] = base64[output[3]];
2354     }
2355    
2356     if (srclen != 0) {
2357     /* Get what's left. */
2358     input[0] = input[1] = input[2] = '\0';
2359     for (i = 0; i < srclen; i++)
2360     input[i] = *src++;
2361    
2362     output[0] = input[0] >> 2;
2363     output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
2364     output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
2365     if (output[0] >= 64 ||
2366     output[1] >= 64 ||
2367     output[2] >= 64)
2368     return -1;
2369    
2370     if (datalength + 4 > targsize)
2371     return (-1);
2372     target[datalength++] = base64[output[0]];
2373     target[datalength++] = base64[output[1]];
2374     if (srclen == 1)
2375     target[datalength++] = pad;
2376     else
2377     target[datalength++] = base64[output[2]];
2378     target[datalength++] = pad;
2379     }
2380     if (datalength >= targsize)
2381     return (-1);
2382     target[datalength] = '\0'; /* Returned value doesn't count \0. */
2383    
2384     return (datalength); // success
2385     }
2386    
2387     static BOOL CALLBACK TTXKeyGenerator(HWND dlg, UINT msg, WPARAM wParam,
2388     LPARAM lParam)
2389     {
2390     static enum hostkey_type key_type;
2391    
2392     switch (msg) {
2393     case WM_INITDIALOG:
2394     {
2395     // default key type
2396     SendMessage(GetDlgItem(dlg, IDC_RSA_TYPE), BM_SETCHECK, BST_CHECKED, 0);
2397     key_type = KEY_RSA;
2398    
2399     // passphrase edit box disabled(default)
2400     EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE);
2401     EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE);
2402    
2403     // file saving dialog disabled(default)
2404     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE);
2405     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE);
2406    
2407     }
2408     return TRUE;
2409    
2410     case WM_COMMAND:
2411     switch (LOWORD(wParam)) {
2412     case IDOK: // key generate button pressed
2413     // passphrase edit box disabled(default)
2414     EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), FALSE);
2415     EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), FALSE);
2416    
2417     // file saving dialog disabled(default)
2418     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), FALSE);
2419     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PRIBATE_KEY), FALSE);
2420    
2421     if (generate_ssh_key(key_type)) {
2422     // passphrase edit box disabled(default)
2423     EnableWindow(GetDlgItem(dlg, IDC_KEY_EDIT), TRUE);
2424     EnableWindow(GetDlgItem(dlg, IDC_CONFIRM_EDIT), TRUE);
2425    
2426     // file saving dialog disabled(default)
2427     EnableWindow(GetDlgItem(dlg, IDC_SAVE_PUBLIC_KEY), TRUE);
2428     EnableWindow(GetDlgItem(dlg