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 2875 - (hide annotations) (download) (as text)
Mon Jun 26 13:26:49 2006 UTC (17 years, 9 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 86381 byte(s)
TTSSHのsetupダイアログの変更内容が次回接続時から反映されるようにした。

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