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 2847 - (hide annotations) (download) (as text)
Fri Oct 21 13:43:08 2005 UTC (18 years, 5 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 85316 byte(s)
Historyチェックボックスのenable / disable追加。

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