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 2873 - (hide annotations) (download) (as text)
Fri Jun 23 13:57:24 2006 UTC (17 years, 9 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 86352 byte(s)
TTSSH 2.28にて遅延パケット圧縮をサポートした。

1 yutakakn 2728 /*
2     Copyright (c) 1998-2001, Robert O'Callahan
3     All rights reserved.
4    
5     Redistribution and use in source and binary forms, with or without modification,
6     are permitted provided that the following conditions are met:
7    
8     Redistributions of source code must retain the above copyright notice, this list of
9     conditions and the following disclaimer.
10    
11     Redistributions in binary form must reproduce the above copyright notice, this list
12     of conditions and the following disclaimer in the documentation and/or other materials
13     provided with the distribution.
14    
15     The name of Robert O'Callahan may not be used to endorse or promote products derived from
16     this software without specific prior written permission.
17    
18     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
19     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21     THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22     EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23     SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25     OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27     */
28    
29     /* Teraterm extension mechanism
30     Robert O'Callahan (roc+tt@cs.cmu.edu)
31    
32     Teraterm by Takashi Teranishi (teranishi@rikaxp.riken.go.jp)
33     */
34    
35     #include "ttxssh.h"
36     #include "fwdui.h"
37     #include "util.h"
38 yutakakn 2748 #include "ssh.h"
39 yutakakn 2728
40     #include <stdlib.h>
41     #include <stdio.h>
42     #include <string.h>
43     #include <io.h>
44     #include <fcntl.h>
45     #include <sys/stat.h>
46     #include <time.h>
47    
48     #include "resource.h"
49     #include <commctrl.h>
50     #include <commdlg.h>
51     #ifdef INET6
52     #include <winsock2.h>
53     static char FAR *ProtocolFamilyList[] = { "UNSPEC", "IPv6", "IPv4", NULL };
54     #else
55     #include <winsock.h>
56     #endif /* INET6 */
57    
58 yutakakn 2816 #include <Lmcons.h>
59    
60     // include OpenSSL header file
61 yutakakn 2782 #include <openssl/opensslv.h>
62 yutakakn 2816 #include <openssl/evp.h>
63     #include <openssl/rsa.h>
64     #include <openssl/dsa.h>
65     #include <openssl/bn.h>
66     #include <openssl/pem.h>
67     #include <openssl/rand.h>
68     #include <openssl/rc4.h>
69 yutakakn 2831 #include <openssl/md5.h>
70 yutakakn 2782
71 yutakakn 2820 // include ZLib header file
72     #include <zlib.h>
73    
74 yutakakn 2816 #include "buffer.h"
75     #include "cipher.h"
76    
77 yutakakn 2728 #define MATCH_STR(s, o) _strnicmp((s), (o), NUM_ELEM(o) - 1)
78    
79     /* This extension implements SSH, so we choose a load order in the
80     "protocols" range. */
81     #define ORDER 2500
82    
83     #ifdef TERATERM32
84     static HICON SecureIcon = NULL;
85     #endif
86    
87     static TInstVar FAR *pvar;
88    
89     #ifdef TERATERM32
90     /* WIN32 allows multiple instances of a DLL */
91     static TInstVar InstVar;
92     #define GET_VAR()
93     #else
94     /* WIN16 does not allow multiple instances of a DLL */
95    
96     /* maximum number of Tera Term instances */
97     #define MAXNUMINST 32
98     /* list of task handles for Tera Term instances */
99     static HANDLE FAR TaskList[MAXNUMINST];
100     /* variable sets for instances */
101     static TInstVar FAR *FAR InstVar[MAXNUMINST];
102    
103     /* Here's how the TS settings work.
104     Whenever the TS settings are read or written to the INI file, then
105     the shared memory containing those settings is updated.
106     When Teraterm starts, the shared memory is read to initialize the TS
107     settings. */
108    
109     /* TS settings shared across instances */
110     static TS_SSH ts_SSH_settings;
111    
112    
113     extern void SSH2_update_cipher_myproposal(PTInstVar pvar);
114    
115    
116     static BOOL NewVar()
117     {
118     int i = 0;
119     HANDLE Task = GetCurrentTask();
120    
121     if (TaskList[0] == NULL)
122    
123     if (Task == NULL)
124     return FALSE;
125     while ((i < MAXNUMINST) && (TaskList[i] != NULL))
126     i++;
127     if (i >= MAXNUMINST)
128     return FALSE;
129     pvar = (TInstVar FAR *) malloc(sizeof(TInstVar));
130     InstVar[i] = pvar;
131     TaskList[i] = Task;
132     return TRUE;
133     }
134    
135     void DelVar()
136     {
137     int i = 0;
138     HANDLE Task = GetCurrentTask();
139    
140     if (Task == NULL)
141     return;
142     while ((i < MAXNUMINST) && (TaskList[i] != Task))
143     i++;
144     if (i >= MAXNUMINST)
145     return;
146     free(TaskList[i]);
147     TaskList[i] = NULL;
148     }
149    
150     BOOL GetVar()
151     {
152     int i = 0;
153     HANDLE Task = GetCurrentTask();
154    
155     if (Task == NULL)
156     return FALSE;
157     while ((i < MAXNUMINST) && (TaskList[i] != Task))
158     i++;
159     if (i >= MAXNUMINST)
160     return FALSE;
161     pvar = InstVar[i];
162     return TRUE;
163     }
164    
165     #define GET_VAR() if (!GetVar()) return
166     #endif
167    
168     /*
169     This code makes lots of assumptions about the order in which Teraterm
170     does things, and how. A key assumption is that the Notification window
171     passed into WSAAsyncSelect is the main terminal window. We also assume
172     that the socket used in the first WSAconnect is the main session socket.
173     */
174    
175     static void init_TTSSH(PTInstVar pvar)
176     {
177     pvar->socket = INVALID_SOCKET;
178     pvar->OldLargeIcon = NULL;
179     pvar->OldSmallIcon = NULL;
180     pvar->NotificationWindow = NULL;
181     pvar->hostdlg_activated = FALSE;
182     pvar->socket = INVALID_SOCKET;
183     pvar->NotificationWindow = NULL;
184     pvar->protocol_major = 0;
185     pvar->protocol_minor = 0;
186    
187     PKT_init(pvar);
188     SSH_init(pvar);
189     CRYPT_init(pvar);
190     AUTH_init(pvar);
191     HOSTS_init(pvar);
192     FWD_init(pvar);
193     FWDUI_init(pvar);
194 yutakakn 2748
195     ssh_heartbeat_lock_initialize();
196 yutakakn 2728 }
197    
198     static void uninit_TTSSH(PTInstVar pvar)
199     {
200 yutakakn 2766 halt_ssh_heartbeat_thread(pvar);
201    
202 yutakakn 2809 ssh2_channel_free();
203    
204 yutakakn 2728 SSH_end(pvar);
205     PKT_end(pvar);
206     AUTH_end(pvar);
207     CRYPT_end(pvar);
208     HOSTS_end(pvar);
209     FWD_end(pvar);
210     FWDUI_end(pvar);
211    
212     if (pvar->OldLargeIcon != NULL) {
213     PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_BIG,
214     (LPARAM) pvar->OldLargeIcon);
215     pvar->OldLargeIcon = NULL;
216     }
217     if (pvar->OldSmallIcon != NULL) {
218     PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_SMALL,
219     (LPARAM) pvar->OldSmallIcon);
220     pvar->OldSmallIcon = NULL;
221     }
222 yutakakn 2766
223     ssh_heartbeat_lock_finalize();
224 yutakakn 2728 }
225    
226     static void PASCAL FAR TTXInit(PTTSet ts, PComVar cv)
227     {
228     #ifndef TERATERM32
229     if (!NewVar())
230     return; /* should be called first */
231     pvar->ts_SSH = &ts_SSH_settings;
232     #endif
233     pvar->settings = *pvar->ts_SSH;
234     pvar->ts = ts;
235     pvar->cv = cv;
236     pvar->fatal_error = FALSE;
237     pvar->showing_err = FALSE;
238     pvar->err_msg = NULL;
239    
240     init_TTSSH(pvar);
241     }
242    
243     static void normalize_cipher_order(char FAR * buf)
244     {
245     char ciphers_listed[SSH_CIPHER_MAX + 1];
246     char ciphers_allowed[SSH_CIPHER_MAX + 1];
247     int i, j;
248    
249     /* SSH_CIPHER_NONE means that all ciphers below that one are disabled.
250     We *never* allow no encryption. */
251     #if 0
252     static char default_ciphers[] = {
253     SSH_CIPHER_3DES,
254     SSH_CIPHER_NONE,
255     SSH_CIPHER_DES, SSH_CIPHER_BLOWFISH
256     };
257     #else
258     // for SSH2(yutaka)
259     static char default_ciphers[] = {
260     SSH_CIPHER_AES128,
261     SSH_CIPHER_3DES_CBC,
262     SSH_CIPHER_3DES,
263     SSH_CIPHER_NONE,
264     SSH_CIPHER_DES, SSH_CIPHER_BLOWFISH
265     };
266     #endif
267    
268     memset(ciphers_listed, 0, sizeof(ciphers_listed));
269    
270     memset(ciphers_allowed, 0, sizeof(ciphers_allowed));
271     for (i = 0; i < NUM_ELEM(default_ciphers); i++) {
272     ciphers_allowed[default_ciphers[i]] = 1;
273     }
274    
275     for (i = 0; buf[i] != 0; i++) {
276     int cipher_num = buf[i] - '0';
277    
278     if (cipher_num < 0 || cipher_num > SSH_CIPHER_MAX
279     || !ciphers_allowed[cipher_num]
280     || ciphers_listed[cipher_num]) {
281     memmove(buf + i, buf + i + 1, strlen(buf + i + 1) + 1);
282     i--;
283     } else {
284     ciphers_listed[cipher_num] = 1;
285     }
286     }
287    
288     for (j = 0; j < NUM_ELEM(default_ciphers); j++) {
289     int cipher_num = default_ciphers[j];
290    
291     if (!ciphers_listed[cipher_num]) {
292     buf[i] = cipher_num + '0';
293     i++;
294     }
295     }
296    
297     buf[i] = 0;
298     }
299    
300     /* Remove local settings from the shared memory block. */
301     static void clear_local_settings(PTInstVar pvar)
302     {
303     pvar->ts_SSH->TryDefaultAuth = FALSE;
304     }
305    
306     static BOOL read_BOOL_option(PCHAR fileName, char FAR * keyName, BOOL def)
307     {
308     char buf[1024];
309    
310     buf[0] = 0;
311     GetPrivateProfileString("TTSSH", keyName, "", buf, sizeof(buf),
312     fileName);
313     if (buf[0] == 0) {
314     return def;
315     } else {
316     return atoi(buf) != 0 ||
317 yutakakn 2850 _stricmp(buf, "yes") == 0 || _stricmp(buf, "y") == 0;
318 yutakakn 2728 }
319     }
320    
321     static void read_string_option(PCHAR fileName, char FAR * keyName,
322     char FAR * def, char FAR * buf, int bufSize)
323     {
324    
325     buf[0] = 0;
326     GetPrivateProfileString("TTSSH", keyName, def, buf, bufSize, fileName);
327     }
328    
329     static void read_ssh_options(PTInstVar pvar, PCHAR fileName)
330     {
331     char buf[1024];
332     TS_SSH FAR *settings = pvar->ts_SSH;
333    
334     #define READ_STD_STRING_OPTION(name) \
335     read_string_option(fileName, #name, "", settings->name, sizeof(settings->name))
336    
337     settings->Enabled = read_BOOL_option(fileName, "Enabled", FALSE);
338    
339     buf[0] = 0;
340     GetPrivateProfileString("TTSSH", "Compression", "", buf, sizeof(buf),
341     fileName);
342     settings->CompressionLevel = atoi(buf);
343     if (settings->CompressionLevel < 0 || settings->CompressionLevel > 9) {
344     settings->CompressionLevel = 0;
345     }
346    
347     READ_STD_STRING_OPTION(DefaultUserName);
348     READ_STD_STRING_OPTION(DefaultForwarding);
349     READ_STD_STRING_OPTION(DefaultRhostsLocalUserName);
350     READ_STD_STRING_OPTION(DefaultRhostsHostPrivateKeyFile);
351     READ_STD_STRING_OPTION(DefaultRSAPrivateKeyFile);
352    
353     READ_STD_STRING_OPTION(CipherOrder);
354     normalize_cipher_order(settings->CipherOrder);
355     SSH2_update_cipher_myproposal(pvar); // yutaka
356 yutakakn 2833 SSH2_update_compression_myproposal(pvar); // SSH2 packet compression (2005.7.9 yutaka)
357 yutakakn 2728
358     read_string_option(fileName, "KnownHostsFiles", "ssh_known_hosts",
359     settings->KnownHostsFiles,
360     sizeof(settings->KnownHostsFiles));
361    
362     buf[0] = 0;
363     GetPrivateProfileString("TTSSH", "DefaultAuthMethod", "", buf,
364     sizeof(buf), fileName);
365     settings->DefaultAuthMethod = atoi(buf);
366     if (settings->DefaultAuthMethod != SSH_AUTH_PASSWORD
367     && settings->DefaultAuthMethod != SSH_AUTH_RSA
368 yutakakn 2800 && settings->DefaultAuthMethod != SSH_AUTH_TIS // add (2005.3.12 yutaka)
369 yutakakn 2728 && settings->DefaultAuthMethod != SSH_AUTH_RHOSTS) {
370     /* this default can never be SSH_AUTH_RHOSTS_RSA because that is not a
371     selection in the dialog box; SSH_AUTH_RHOSTS_RSA is automatically chosen
372     when the dialog box has rhosts selected and an host private key file
373     is supplied. */
374     settings->DefaultAuthMethod = SSH_AUTH_PASSWORD;
375     }
376    
377     buf[0] = 0;
378     GetPrivateProfileString("TTSSH", "LogLevel", "", buf, sizeof(buf),
379     fileName);
380     settings->LogLevel = atoi(buf);
381    
382     buf[0] = 0;
383     GetPrivateProfileString("TTSSH", "WriteBufferSize", "", buf,
384     sizeof(buf), fileName);
385     settings->WriteBufferSize = atoi(buf);
386     if (settings->WriteBufferSize <= 0) {
387     settings->WriteBufferSize = 2 * 1024 * 1024;
388     }
389    
390     settings->LocalForwardingIdentityCheck =
391     read_BOOL_option(fileName, "LocalForwardingIdentityCheck", TRUE);
392    
393     // SSH protocol version (2004.10.11 yutaka)
394 yutakakn 2738 // default is SSH2 (2004.11.30 yutaka)
395     settings->ssh_protocol_version = GetPrivateProfileInt("TTSSH", "ProtocolVersion", 2, fileName);
396 yutakakn 2728
397 yutakakn 2748 // SSH heartbeat time(second) (2004.12.11 yutaka)
398     settings->ssh_heartbeat_overtime = GetPrivateProfileInt("TTSSH", "HeartBeat", 60, fileName);
399    
400 yutakakn 2782 // SSH2 keyboard-interactive (2005.1.23 yutaka)
401 yutakakn 2799 // �f�t�H���g���������������BOpenSSH 4.0����keyboard-interactive���\�b�h�����`�������������������A
402     // ���Y���\�b�h���g�����R�l�N�V���������������������B(2005.3.12 yutaka)
403     settings->ssh2_keyboard_interactive = GetPrivateProfileInt("TTSSH", "KeyboardInteractive", 0, fileName);
404 yutakakn 2782
405 yutakakn 2728 clear_local_settings(pvar);
406     }
407    
408     static void write_ssh_options(PTInstVar pvar, PCHAR fileName,
409     TS_SSH FAR * settings)
410     {
411     char buf[1024];
412    
413     WritePrivateProfileString("TTSSH", "Enabled",
414     settings->Enabled ? "1" : "0", fileName);
415    
416     _itoa(settings->CompressionLevel, buf, 10);
417     WritePrivateProfileString("TTSSH", "Compression", buf, fileName);
418    
419     WritePrivateProfileString("TTSSH", "DefaultUserName",
420     settings->DefaultUserName, fileName);
421    
422     WritePrivateProfileString("TTSSH", "DefaultForwarding",
423     settings->DefaultForwarding, fileName);
424    
425     WritePrivateProfileString("TTSSH", "CipherOrder",
426     settings->CipherOrder, fileName);
427    
428     WritePrivateProfileString("TTSSH", "KnownHostsFiles",
429     settings->KnownHostsFiles, fileName);
430    
431     WritePrivateProfileString("TTSSH", "DefaultRhostsLocalUserName",
432     settings->DefaultRhostsLocalUserName,
433     fileName);
434    
435     WritePrivateProfileString("TTSSH", "DefaultRhostsHostPrivateKeyFile",
436     settings->DefaultRhostsHostPrivateKeyFile,
437     fileName);
438    
439     WritePrivateProfileString("TTSSH", "DefaultRSAPrivateKeyFile",
440     settings->DefaultRSAPrivateKeyFile,
441     fileName);
442    
443     _itoa(settings->DefaultAuthMethod, buf, 10);
444     WritePrivateProfileString("TTSSH", "DefaultAuthMethod", buf, fileName);
445    
446     _itoa(settings->LogLevel, buf, 10);
447     WritePrivateProfileString("TTSSH", "LogLevel", buf, fileName);
448    
449     _itoa(settings->WriteBufferSize, buf, 10);
450     WritePrivateProfileString("TTSSH", "WriteBufferSize", buf, fileName);
451    
452     WritePrivateProfileString("TTSSH", "LocalForwardingIdentityCheck",
453     settings->
454     LocalForwardingIdentityCheck ? "1" : "0",
455     fileName);
456    
457     // SSH protocol version (2004.10.11 yutaka)
458     WritePrivateProfileString("TTSSH", "ProtocolVersion",
459     settings->ssh_protocol_version==2 ? "2" : "1",
460     fileName);
461    
462 yutakakn 2748 // SSH heartbeat time(second) (2004.12.11 yutaka)
463     _snprintf(buf, sizeof(buf), "%d", settings->ssh_heartbeat_overtime);
464     WritePrivateProfileString("TTSSH", "HeartBeat", buf, fileName);
465    
466 yutakakn 2782 // SSH2 keyboard-interactive (2005.1.23 yutaka)
467     WritePrivateProfileString("TTSSH", "KeyboardInteractive",
468     settings->ssh2_keyboard_interactive ? "1" : "0",
469     fileName);
470    
471 yutakakn 2728 }
472    
473 yutakakn 2748
474 yutakakn 2728 /* find free port in all protocol family */
475     static unsigned short find_local_port(PTInstVar pvar)
476     {
477     int tries;
478     #ifdef INET6
479     SOCKET connecter;
480     struct addrinfo hints;
481     struct addrinfo FAR *res;
482     struct addrinfo FAR *res0;
483     unsigned short port;
484     char pname[NI_MAXHOST];
485     #endif /* INET6 */
486    
487     if (pvar->session_settings.DefaultAuthMethod != SSH_AUTH_RHOSTS) {
488     return 0;
489     }
490    
491     /* The random numbers here are only used to try to get fresh
492     ports across runs (dangling ports can cause bind errors
493     if we're unlucky). They do not need to be (and are not)
494     cryptographically strong.
495     */
496     srand((unsigned) GetTickCount());
497    
498     #ifdef INET6
499     for (tries = 20; tries > 0; tries--) {
500     memset(&hints, 0, sizeof(hints));
501     hints.ai_family = pvar->ts->ProtocolFamily;
502     hints.ai_flags = AI_PASSIVE;
503     hints.ai_socktype = SOCK_STREAM;
504     port = (unsigned) rand() % 512 + 512;
505     _snprintf(pname, sizeof(pname), "%d", (int) port);
506     if (getaddrinfo(NULL, pname, &hints, &res0)) {
507     return 0;
508     /* NOT REACHED */
509     }
510    
511     for (res = res0; res; res = res->ai_next) {
512     if (res->ai_family == AF_INET || res->ai_family == AF_INET6)
513     continue;
514    
515     connecter =
516     socket(res->ai_family, res->ai_socktype, res->ai_protocol);
517     if (connecter == INVALID_SOCKET) {
518     freeaddrinfo(res0);
519     return 0;
520     }
521    
522     if (bind(connecter, res->ai_addr, res->ai_addrlen) !=
523     SOCKET_ERROR) {
524     return port;
525     freeaddrinfo(res0);
526     closesocket(connecter);
527     } else if (WSAGetLastError() != WSAEADDRINUSE) {
528     closesocket(connecter);
529     freeaddrinfo(res0);
530     return 0;
531     }
532    
533     closesocket(connecter);
534     }
535     freeaddrinfo(res0);
536     }
537    
538     return 0;
539     #else
540     for (tries = 20; tries > 0; tries--) {
541     SOCKET connecter = socket(AF_INET, SOCK_STREAM, 0);
542     struct sockaddr_in connecter_addr;
543    
544     connecter_addr.sin_family = AF_INET;
545     connecter_addr.sin_port = (unsigned) rand() % 512 + 512;
546     connecter_addr.sin_addr.s_addr = htonl(INADDR_ANY);
547    
548     if (connecter == INVALID_SOCKET) {
549     return 0;
550     }
551    
552     if (bind
553     (connecter, (struct sockaddr FAR *) &connecter_addr,
554     sizeof(connecter_addr)) != SOCKET_ERROR) {
555     closesocket(connecter);
556     return connecter_addr.sin_port;
557     } else if (WSAGetLastError() != WSAEADDRINUSE) {
558     closesocket(connecter);
559     return 0;
560     }
561    
562     closesocket(connecter);
563     }
564    
565     return 0;
566     #endif /* INET6 */
567     }
568    
569     static int PASCAL FAR TTXconnect(SOCKET s,
570     const struct sockaddr FAR * name,
571     int namelen)
572     {
573     GET_VAR();
574    
575     #ifdef INET6
576     if (pvar->socket == INVALID_SOCKET) {
577     struct sockaddr_storage ss;
578     int len;
579    
580     pvar->socket = s;
581    
582     memset(&ss, 0, sizeof(ss));
583     switch (pvar->ts->ProtocolFamily) {
584     case AF_INET:
585     len = sizeof(struct sockaddr_in);
586     ((struct sockaddr_in FAR *) &ss)->sin_family = AF_INET;
587     ((struct sockaddr_in FAR *) &ss)->sin_addr.s_addr = INADDR_ANY;
588     ((struct sockaddr_in FAR *) &ss)->sin_port =
589     htons(find_local_port(pvar));
590     break;
591     case AF_INET6:
592     len = sizeof(struct sockaddr_in6);
593     ((struct sockaddr_in6 FAR *) &ss)->sin6_family = AF_INET6;
594     #if 0 /* symbol "in6addr_any" is not included in wsock32.lib */
595     /* if wsock32.lib will be linked, we can't refer "in6addr_any" */
596     ((struct sockaddr_in6 FAR *) &ss)->sin6_addr = in6addr_any;
597     #eles
598     memset(&((struct sockaddr_in6 FAR *) &ss)->sin6_addr, 0,
599     sizeof(struct in_addr6));
600     #endif /* 0 */
601     ((struct sockaddr_in6 FAR *) &ss)->sin6_port =
602     htons(find_local_port(pvar));
603     break;
604     default:
605     /* NOT REACHED */
606     break;
607     }
608    
609     bind(s, (struct sockaddr FAR *) &ss, len);
610     }
611     #else
612     if (pvar->socket == INVALID_SOCKET) {
613     struct sockaddr_in addr;
614    
615     pvar->socket = s;
616    
617     addr.sin_family = AF_INET;
618     addr.sin_port = htons(find_local_port(pvar));
619     addr.sin_addr.s_addr = INADDR_ANY;
620     memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
621    
622     bind(s, (struct sockaddr FAR *) &addr, sizeof(addr));
623     }
624     #endif /* INET6 */
625    
626     return (pvar->Pconnect) (s, name, namelen);
627     }
628    
629     static int PASCAL FAR TTXWSAAsyncSelect(SOCKET s, HWND hWnd, u_int wMsg,
630     long lEvent)
631     {
632     GET_VAR();
633    
634     if (s == pvar->socket) {
635     pvar->notification_events = lEvent;
636     pvar->notification_msg = wMsg;
637    
638     if (pvar->NotificationWindow == NULL) {
639     pvar->NotificationWindow = hWnd;
640     AUTH_advance_to_next_cred(pvar);
641     }
642     }
643    
644     return (pvar->PWSAAsyncSelect) (s, hWnd, wMsg, lEvent);
645     }
646    
647     static int PASCAL FAR TTXrecv(SOCKET s, char FAR * buf, int len, int flags)
648     {
649     GET_VAR();
650    
651     if (s == pvar->socket) {
652 yutakakn 2748 int ret;
653    
654     ssh_heartbeat_lock();
655     ret = PKT_recv(pvar, buf, len);
656     ssh_heartbeat_unlock();
657     return (ret);
658    
659 yutakakn 2728 } else {
660     return (pvar->Precv) (s, buf, len, flags);
661     }
662     }
663    
664     static int PASCAL FAR TTXsend(SOCKET s, char const FAR * buf, int len,
665     int flags)
666     {
667     GET_VAR();
668    
669     if (s == pvar->socket) {
670 yutakakn 2748 ssh_heartbeat_lock();
671 yutakakn 2728 SSH_send(pvar, buf, len);
672 yutakakn 2748 ssh_heartbeat_unlock();
673 yutakakn 2728 return len;
674     } else {
675     return (pvar->Psend) (s, buf, len, flags);
676     }
677     }
678    
679     void notify_established_secure_connection(PTInstVar pvar)
680     {
681     #ifdef TERATERM32
682     if (SecureIcon == NULL) {
683     SecureIcon = LoadIcon(hInst, MAKEINTRESOURCE(IDI_SECURETT));
684     }
685    
686     if (SecureIcon != NULL) {
687     pvar->OldSmallIcon =
688     (HICON) SendMessage(pvar->NotificationWindow, WM_GETICON,
689     ICON_SMALL, 0);
690     pvar->OldLargeIcon =
691     (HICON) SendMessage(pvar->NotificationWindow, WM_GETICON,
692     ICON_BIG, 0);
693     PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_BIG,
694     (LPARAM) SecureIcon);
695     PostMessage(pvar->NotificationWindow, WM_SETICON, ICON_SMALL,
696     (LPARAM) SecureIcon);
697     }
698     #endif
699    
700     notify_verbose_message(pvar, "Entering secure mode",
701     LOG_LEVEL_VERBOSE);
702     }
703    
704     void notify_closed_connection(PTInstVar pvar)
705     {
706 yutakakn 2766 SSH_notify_disconnecting(pvar, NULL);
707     AUTH_notify_disconnecting(pvar);
708     HOSTS_notify_disconnecting(pvar);
709    
710 yutakakn 2728 PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
711     pvar->socket, MAKELPARAM(FD_CLOSE, 0));
712    
713     }
714    
715     static void add_err_msg(PTInstVar pvar, char FAR * msg)
716     {
717     if (pvar->err_msg != NULL) {
718     char FAR *buf =
719     (char FAR *) malloc(strlen(pvar->err_msg) + 3 + strlen(msg));
720    
721     strcpy(buf, pvar->err_msg);
722     strcat(buf, "\n\n");
723     strcat(buf, msg);
724     free(pvar->err_msg);
725     pvar->err_msg = buf;
726     } else {
727     pvar->err_msg = _strdup(msg);
728     }
729     }
730    
731     void notify_nonfatal_error(PTInstVar pvar, char FAR * msg)
732     {
733     if (!pvar->showing_err) {
734 yutakakn 2868 // �������������������m���E�B���h�E�����������A�f�X�N�g�b�v���I�[�i�[������
735     // ���b�Z�[�W�{�b�N�X���o���������B(2006.6.11 yutaka)
736     if (pvar->NotificationWindow == NULL) {
737     MessageBox(NULL, msg, "Tera Term: not fatal error", MB_OK|MB_ICONINFORMATION);
738     msg[0] = '\0';
739    
740     } else {
741     PostMessage(pvar->NotificationWindow, WM_COMMAND,
742     ID_SSHASYNCMESSAGEBOX, 0);
743     }
744 yutakakn 2728 }
745     if (msg[0] != 0) {
746     notify_verbose_message(pvar, msg, LOG_LEVEL_ERROR);
747     add_err_msg(pvar, msg);
748     }
749     }
750    
751     void notify_fatal_error(PTInstVar pvar, char FAR * msg)
752     {
753     if (msg[0] != 0) {
754     notify_verbose_message(pvar, msg, LOG_LEVEL_FATAL);
755     add_err_msg(pvar, msg);
756     }
757    
758     if (!pvar->fatal_error) {
759     pvar->fatal_error = TRUE;
760    
761     SSH_notify_disconnecting(pvar, msg);
762     AUTH_notify_disconnecting(pvar);
763     HOSTS_notify_disconnecting(pvar);
764    
765     PostMessage(pvar->NotificationWindow, WM_USER_COMMNOTIFY,
766     pvar->socket, MAKELPARAM(FD_CLOSE,
767     (pvar->PWSAGetLastError) ()));
768     }
769     }
770    
771     void notify_verbose_message(PTInstVar pvar, char FAR * msg, int level)
772     {
773     if (level <= pvar->session_settings.LogLevel) {
774     char buf[1024];
775     int file;
776    
777     get_teraterm_dir_relative_name(buf, NUM_ELEM(buf), "TTSSH.LOG");
778     file = _open(buf, _O_RDWR | _O_APPEND | _O_CREAT | _O_TEXT,
779     _S_IREAD | _S_IWRITE);
780    
781     if (file >= 0) {
782     _write(file, msg, strlen(msg));
783     _write(file, "\n", 1);
784     _close(file);
785     }
786     }
787     }
788    
789     static void PASCAL FAR TTXOpenTCP(TTXSockHooks FAR * hooks)
790     {
791     GET_VAR();
792    
793     if (pvar->settings.Enabled) {
794 yutakakn 2805 char buf[1024] = "\n---------------------------------------------------------------------\nInitiating SSH session at ";
795 yutakakn 2728 struct tm FAR *newtime;
796     time_t long_time;
797    
798     pvar->session_settings = pvar->settings;
799    
800     time(&long_time);
801     newtime = localtime(&long_time);
802     strcat(buf, asctime(newtime));
803     buf[strlen(buf) - 1] = 0;
804     notify_verbose_message(pvar, buf, LOG_LEVEL_VERBOSE);
805    
806     FWDUI_load_settings(pvar);
807    
808     pvar->cv->TelAutoDetect = FALSE;
809     /* This next line should not be needed because Teraterm's
810     CommLib should find ts->Telnet == 0 ... but we'll do this
811     just to be on the safe side. */
812     pvar->cv->TelFlag = FALSE;
813    
814     pvar->Precv = *hooks->Precv;
815     pvar->Psend = *hooks->Psend;
816     pvar->PWSAAsyncSelect = *hooks->PWSAAsyncSelect;
817     pvar->Pconnect = *hooks->Pconnect;
818     pvar->PWSAGetLastError = *hooks->PWSAGetLastError;
819    
820     *hooks->Precv = TTXrecv;
821     *hooks->Psend = TTXsend;
822     *hooks->PWSAAsyncSelect = TTXWSAAsyncSelect;
823     *hooks->Pconnect = TTXconnect;
824    
825     SSH_open(pvar);
826     HOSTS_open(pvar);
827     FWDUI_open(pvar);
828     }
829     }
830    
831     static void PASCAL FAR TTXCloseTCP(TTXSockHooks FAR * hooks)
832     {
833     GET_VAR();
834    
835     if (pvar->session_settings.Enabled) {
836     pvar->socket = INVALID_SOCKET;
837    
838     notify_verbose_message(pvar, "Terminating SSH session...",
839     LOG_LEVEL_VERBOSE);
840    
841     *hooks->Precv = pvar->Precv;
842     *hooks->Psend = pvar->Psend;
843     *hooks->PWSAAsyncSelect = pvar->PWSAAsyncSelect;
844     *hooks->Pconnect = pvar->Pconnect;
845     }
846    
847     uninit_TTSSH(pvar);
848     init_TTSSH(pvar);
849     }
850    
851     static void enable_dlg_items(HWND dlg, int from, int to, BOOL enabled)
852     {
853     for (; from <= to; from++) {
854     EnableWindow(GetDlgItem(dlg, from), enabled);
855     }
856     }
857    
858     static BOOL CALLBACK TTXHostDlg(HWND dlg, UINT msg, WPARAM wParam,
859     LPARAM lParam)
860     {
861     static char *ssh_version[] = {"SSH1", "SSH2", NULL};
862     PGetHNRec GetHNRec;
863     char EntName[7];
864     char TempHost[HostNameMaxLength + 1];
865     WORD i, j, w;
866     BOOL Ok;
867    
868     GET_VAR();
869    
870     switch (msg) {
871     case WM_INITDIALOG:
872     GetHNRec = (PGetHNRec) lParam;
873     SetWindowLong(dlg, DWL_USER, lParam);
874    
875 yutakakn 2846 // �z�X�g�q�X�g�����`�F�b�N�{�b�N�X������ (2005.10.21 yutaka)
876     if (pvar->ts->HistoryList > 0) {
877     SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_SETCHECK, BST_CHECKED, 0);
878     } else {
879     SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_SETCHECK, BST_UNCHECKED, 0);
880     }
881    
882 yutakakn 2728 if (GetHNRec->PortType == IdFile)
883     GetHNRec->PortType = IdTCPIP;
884     CheckRadioButton(dlg, IDC_HOSTTCPIP, IDC_HOSTSERIAL,
885     IDC_HOSTTCPIP + GetHNRec->PortType - 1);
886    
887     strcpy(EntName, "Host");
888    
889     i = 1;
890     do {
891     sprintf(&EntName[4], "%d", i);
892     GetPrivateProfileString("Hosts", EntName, "",
893     TempHost, sizeof(TempHost),
894     GetHNRec->SetupFN);
895     if (strlen(TempHost) > 0)
896     SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_ADDSTRING,
897     0, (LPARAM) TempHost);
898     i++;
899     } while ((i <= 99) && (strlen(TempHost) > 0));
900    
901     SendDlgItemMessage(dlg, IDC_HOSTNAME, EM_LIMITTEXT,
902     HostNameMaxLength - 1, 0);
903    
904     SendDlgItemMessage(dlg, IDC_HOSTNAME, CB_SETCURSEL, 0, 0);
905    
906     CheckRadioButton(dlg, IDC_HOSTTELNET, IDC_HOSTOTHER,
907     pvar->settings.Enabled ? IDC_HOSTSSH : GetHNRec->
908     Telnet ? IDC_HOSTTELNET : IDC_HOSTOTHER);
909     SendDlgItemMessage(dlg, IDC_HOSTTCPPORT, EM_LIMITTEXT, 5, 0);
910     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TCPPort, FALSE);
911     #ifdef INET6
912     for (i = 0; ProtocolFamilyList[i]; ++i) {
913     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_ADDSTRING,
914     0, (LPARAM) ProtocolFamilyList[i]);
915     }
916     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, EM_LIMITTEXT,
917     ProtocolFamilyMaxLength - 1, 0);
918     SendDlgItemMessage(dlg, IDC_HOSTTCPPROTOCOL, CB_SETCURSEL, 0, 0);
919     #endif /* INET6 */
920    
921     /////// SSH version
922     for (i = 0; ssh_version[i]; ++i) {
923     SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_ADDSTRING,
924     0, (LPARAM) ssh_version[i]);
925     }
926     SendDlgItemMessage(dlg, IDC_SSH_VERSION, EM_LIMITTEXT,
927     NUM_ELEM(ssh_version) - 1, 0);
928    
929 yutakakn 2734 if (pvar->settings.ssh_protocol_version == 1) {
930     SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 0, 0); // SSH1
931     } else {
932 yutakakn 2728 SendDlgItemMessage(dlg, IDC_SSH_VERSION, CB_SETCURSEL, 1, 0); // SSH2
933     }
934    
935     if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
936     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE); // enabled
937     } else {
938     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
939     }
940     /////// SSH version
941    
942    
943     j = 0;
944     w = 1;
945     strcpy(EntName, "COM");
946     for (i = 1; i <= GetHNRec->MaxComPort; i++) {
947     sprintf(&EntName[3], "%d", i);
948     SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_ADDSTRING,
949     0, (LPARAM) EntName);
950     j++;
951     if (GetHNRec->ComPort == i)
952     w = j;
953     }
954     if (j > 0)
955     SendDlgItemMessage(dlg, IDC_HOSTCOM, CB_SETCURSEL, w - 1, 0);
956     else /* All com ports are already used */
957     GetHNRec->PortType = IdTCPIP;
958    
959 yutakakn 2803 if (GetHNRec->PortType == IdTCPIP) {
960 yutakakn 2728 enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
961 yutakakn 2803
962     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
963     enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, TRUE);
964     }
965 yutakakn 2728 #ifdef INET6
966     else {
967     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
968     FALSE);
969     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
970     IDC_HOSTTCPPROTOCOL, FALSE);
971 yutakakn 2803
972     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
973     enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, FALSE); // disabled (2004.11.23 yutaka)
974 yutakakn 2728 }
975     #else
976     else
977     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
978     FALSE);
979     #endif /* INET6 */
980    
981     // Host dialog���t�H�[�J�X�������� (2004.10.2 yutaka)
982 yutakakn 2803 if (GetHNRec->PortType == IdTCPIP) {
983     HWND hwnd = GetDlgItem(dlg, IDC_HOSTNAME);
984     SetFocus(hwnd);
985     } else {
986     HWND hwnd = GetDlgItem(dlg, IDC_HOSTCOM);
987     SetFocus(hwnd);
988 yutakakn 2728 }
989    
990 yutakakn 2734 // SetFocus()���t�H�[�J�X���������������AFALSE�������K�v�������B
991     // TRUE���������ATABSTOP�������������������R���g���[�����I�������B
992     // (2004.11.23 yutaka)
993     return FALSE;
994     //return TRUE;
995 yutakakn 2728
996     case WM_COMMAND:
997     switch (LOWORD(wParam)) {
998     case IDOK:
999     GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
1000     if (GetHNRec != NULL) {
1001     if (IsDlgButtonChecked(dlg, IDC_HOSTTCPIP)) {
1002     #ifdef INET6
1003     char afstr[BUFSIZ];
1004     #endif /* INET6 */
1005     i = GetDlgItemInt(dlg, IDC_HOSTTCPPORT, &Ok, FALSE);
1006     if (Ok) {
1007     GetHNRec->TCPPort = i;
1008     } else {
1009     MessageBox(dlg, "Teraterm",
1010     "The TCP port must be a number.",
1011     MB_OK | MB_ICONEXCLAMATION);
1012     return TRUE;
1013     }
1014     #ifdef INET6
1015     #define getaf(str) \
1016     ((strcmp((str), "IPv6") == 0) ? AF_INET6 : \
1017     ((strcmp((str), "IPv4") == 0) ? AF_INET : AF_UNSPEC))
1018     memset(afstr, 0, sizeof(afstr));
1019     GetDlgItemText(dlg, IDC_HOSTTCPPROTOCOL, afstr,
1020     sizeof(afstr));
1021     GetHNRec->ProtocolFamily = getaf(afstr);
1022     #endif /* INET6 */
1023     GetHNRec->PortType = IdTCPIP;
1024     GetDlgItemText(dlg, IDC_HOSTNAME, GetHNRec->HostName,
1025     HostNameMaxLength);
1026     GetHNRec->Telnet = FALSE;
1027     pvar->hostdlg_activated = TRUE;
1028     pvar->hostdlg_Enabled = FALSE;
1029     if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1030     GetHNRec->Telnet = TRUE;
1031     } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1032     pvar->hostdlg_Enabled = TRUE;
1033    
1034     // check SSH protocol version
1035     memset(afstr, 0, sizeof(afstr));
1036     GetDlgItemText(dlg, IDC_SSH_VERSION, afstr, sizeof(afstr));
1037 yutakakn 2850 if (_stricmp(afstr, "SSH1") == 0) {
1038 yutakakn 2728 pvar->settings.ssh_protocol_version = 1;
1039     } else {
1040     pvar->settings.ssh_protocol_version = 2;
1041     }
1042     }
1043 yutakakn 2846
1044     // host history check button
1045     if (SendMessage(GetDlgItem(dlg, IDC_HISTORY), BM_GETCHECK, 0, 0) == BST_CHECKED) {
1046     pvar->ts->HistoryList = 1;
1047     } else {
1048     pvar->ts->HistoryList = 0;
1049     }
1050    
1051 yutakakn 2728 } else {
1052     GetHNRec->PortType = IdSerial;
1053     GetHNRec->HostName[0] = 0;
1054     memset(EntName, 0, sizeof(EntName));
1055     GetDlgItemText(dlg, IDC_HOSTCOM, EntName,
1056     sizeof(EntName) - 1);
1057     GetHNRec->ComPort = (BYTE) (EntName[3]) - 0x30;
1058     if (strlen(EntName) > 4)
1059     GetHNRec->ComPort =
1060     GetHNRec->ComPort * 10 + (BYTE) (EntName[4]) -
1061     0x30;
1062     }
1063     }
1064     EndDialog(dlg, 1);
1065     return TRUE;
1066    
1067     case IDCANCEL:
1068     EndDialog(dlg, 0);
1069     return TRUE;
1070    
1071     case IDC_HOSTTCPIP:
1072     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1073     TRUE);
1074     #ifdef INET6
1075     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1076     IDC_HOSTTCPPROTOCOL, TRUE);
1077     #endif /* INET6 */
1078     enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, FALSE);
1079    
1080 yutakakn 2734 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, TRUE); // disabled (2004.11.23 yutaka)
1081 yutakakn 2728 if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1082     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, TRUE);
1083     } else {
1084     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1085     }
1086    
1087 yutakakn 2847 enable_dlg_items(dlg, IDC_HISTORY, IDC_HISTORY, TRUE); // disabled
1088    
1089 yutakakn 2728 return TRUE;
1090    
1091     case IDC_HOSTSERIAL:
1092     enable_dlg_items(dlg, IDC_HOSTCOMLABEL, IDC_HOSTCOM, TRUE);
1093     enable_dlg_items(dlg, IDC_HOSTNAMELABEL, IDC_HOSTTCPPORT,
1094     FALSE);
1095     #ifdef INET6
1096     enable_dlg_items(dlg, IDC_HOSTTCPPROTOCOLLABEL,
1097     IDC_HOSTTCPPROTOCOL, FALSE);
1098     #endif /* INET6 */
1099     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1100 yutakakn 2734 enable_dlg_items(dlg, IDC_SSH_VERSION_LABEL, IDC_SSH_VERSION_LABEL, FALSE); // disabled (2004.11.23 yutaka)
1101 yutakakn 2728
1102 yutakakn 2847 enable_dlg_items(dlg, IDC_HISTORY, IDC_HISTORY, FALSE); // disabled
1103    
1104 yutakakn 2728 return TRUE;
1105    
1106     case IDC_HOSTSSH:
1107     enable_dlg_items(dlg, IDC_SSH_VERSION,
1108     IDC_SSH_VERSION, TRUE);
1109     goto hostssh_enabled;
1110    
1111     case IDC_HOSTTELNET:
1112     case IDC_HOSTOTHER:
1113     enable_dlg_items(dlg, IDC_SSH_VERSION, IDC_SSH_VERSION, FALSE); // disabled
1114     hostssh_enabled:
1115    
1116     GetHNRec = (PGetHNRec) GetWindowLong(dlg, DWL_USER);
1117    
1118     if (IsDlgButtonChecked(dlg, IDC_HOSTTELNET)) {
1119     if (GetHNRec != NULL)
1120     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, GetHNRec->TelPort,
1121     FALSE);
1122     } else if (IsDlgButtonChecked(dlg, IDC_HOSTSSH)) {
1123     SetDlgItemInt(dlg, IDC_HOSTTCPPORT, 22, FALSE);
1124     }
1125     return TRUE;
1126    
1127     case IDC_HOSTHELP:
1128     PostMessage(GetParent(dlg), WM_USER_DLGHELP2, 0, 0);
1129     }
1130     }
1131     return FALSE;
1132     }
1133    
1134     static BOOL FAR PASCAL TTXGetHostName(HWND parent, PGetHNRec rec)
1135     {
1136     return (BOOL) DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_HOSTDLG),
1137     parent, TTXHostDlg, (LONG) rec);
1138     }
1139    
1140     static void PASCAL FAR TTXGetUIHooks(TTXUIHooks FAR * hooks)
1141     {
1142     GET_VAR();
1143    
1144     *hooks->GetHostName = TTXGetHostName;
1145     }
1146    
1147     static void FAR PASCAL TTXReadINIFile(PCHAR fileName, PTTSet ts)
1148     {
1149     GET_VAR();
1150    
1151     (pvar->ReadIniFile) (fileName, ts);
1152     read_ssh_options(pvar, fileName);
1153     pvar->settings = *pvar->ts_SSH;
1154     notify_verbose_message(pvar, "Reading INI file", LOG_LEVEL_VERBOSE);
1155     FWDUI_load_settings(pvar);
1156     }
1157    
1158     static void FAR PASCAL TTXWriteINIFile(PCHAR fileName, PTTSet ts)
1159     {
1160     GET_VAR();
1161    
1162     (pvar->WriteIniFile) (fileName, ts);
1163     *pvar->ts_SSH = pvar->settings;
1164     clear_local_settings(pvar);
1165     notify_verbose_message(pvar, "Writing INI file", LOG_LEVEL_VERBOSE);
1166     write_ssh_options(pvar, fileName, pvar->ts_SSH);
1167     }
1168    
1169     static void read_ssh_options_from_user_file(PTInstVar pvar,
1170     char FAR * user_file_name)
1171     {
1172     if (user_file_name[0] == '.') {
1173     read_ssh_options(pvar, user_file_name);
1174     } else {
1175     char buf[1024];
1176    
1177     get_teraterm_dir_relative_name(buf, sizeof(buf), user_file_name);
1178     read_ssh_options(pvar, buf);
1179     }
1180    
1181     pvar->settings = *pvar->ts_SSH;
1182     FWDUI_load_settings(pvar);
1183     }
1184    
1185 yutakakn 2784
1186     // @���u�����N���u�������B (2005.1.26 yutaka)
1187     static void replace_to_blank(char *src, char *dst, int dst_len)
1188     {
1189     int len, i;
1190    
1191     len = strlen(src);
1192     if (dst_len < len) // buffer overflow check
1193     return;
1194    
1195     for (i = 0 ; i < len ; i++) {
1196     if (src[i] == '@') { // @ ���o��������
1197     if (i < len - 1 && src[i + 1] == '@') { // �������� @ �����A�b�g�}�[�N���F������
1198     *dst++ = '@';
1199     i++;
1200     } else {
1201     *dst++ = ' '; // �������u��������
1202     }
1203     } else {
1204     *dst++ = src[i];
1205     }
1206     }
1207     *dst = '\0';
1208     }
1209    
1210 yutakakn 2728 /* returns 1 if the option text must be deleted */
1211     static int parse_option(PTInstVar pvar, char FAR * option)
1212     {
1213     if ((option[0] == '-' || option[0] == '/')) {
1214     if (MATCH_STR(option + 1, "ssh") == 0) {
1215     if (option[4] == 0) {
1216     pvar->settings.Enabled = 1;
1217     } else if (MATCH_STR(option + 4, "-L") == 0
1218     || MATCH_STR(option + 4, "-R") == 0
1219 yutakakn 2850 || _stricmp(option + 4, "-X") == 0) {
1220 yutakakn 2728 if (pvar->settings.DefaultForwarding[0] == 0) {
1221     strcpy(pvar->settings.DefaultForwarding, option + 5);
1222     } else {
1223     strcat(pvar->settings.DefaultForwarding, ";");
1224     strcat(pvar->settings.DefaultForwarding, option + 5);
1225     }
1226     } else if (MATCH_STR(option + 4, "-f=") == 0) {
1227     read_ssh_options_from_user_file(pvar, option + 7);
1228     } else if (MATCH_STR(option + 4, "-v") == 0) {
1229     pvar->settings.LogLevel = LOG_LEVEL_VERBOSE;
1230 yutakakn 2850 } else if (_stricmp(option + 4, "-autologin") == 0
1231     || _stricmp(option + 4, "-autologon") == 0) {
1232 yutakakn 2728 pvar->settings.TryDefaultAuth = TRUE;
1233 yutakakn 2739
1234 yutakakn 2728 } else if (MATCH_STR(option + 4, "-consume=") == 0) {
1235     read_ssh_options_from_user_file(pvar, option + 13);
1236     DeleteFile(option + 13);
1237     } else {
1238     char buf[1024];
1239    
1240     _snprintf(buf, sizeof(buf),
1241     "Unrecognized command-line option: %s", option);
1242     buf[sizeof(buf) - 1] = 0;
1243    
1244     MessageBox(NULL, buf, "TTSSH", MB_OK | MB_ICONEXCLAMATION);
1245     }
1246    
1247     return 1;
1248     } else if (MATCH_STR(option + 1, "t=") == 0) {
1249     if (strcmp(option + 3, "2") == 0) {
1250     pvar->settings.Enabled = 1;
1251     return 1;
1252     } else {
1253     pvar->settings.Enabled = 0;
1254     }
1255     } else if (MATCH_STR(option + 1, "f=") == 0) {
1256     read_ssh_options_from_user_file(pvar, option + 3);
1257    
1258     // /1 ������ /2 �I�v�V�������V�K���� (2004.10.3 yutaka)
1259     } else if (MATCH_STR(option + 1, "1") == 0) {
1260     // command line: /ssh /1 is SSH1 only
1261     pvar->settings.ssh_protocol_version = 1;
1262    
1263     } else if (MATCH_STR(option + 1, "2") == 0) {
1264     // command line: /ssh /2 is SSH2 & SSH1
1265     pvar->settings.ssh_protocol_version = 2;
1266    
1267     } else if (MATCH_STR(option + 1, "nossh") == 0) {
1268     // '/nossh' �I�v�V�����������B
1269     // TERATERM.INI ��SSH���L�������������������A������Cygterm���N��������������
1270     // �����������������B(2004.10.11 yutaka)
1271     pvar->settings.Enabled = 0;
1272    
1273 yutakakn 2739 } else if (MATCH_STR(option + 1, "auth") == 0) {
1274 yutakakn 2784 // SSH2�������O�C���I�v�V����������
1275 yutakakn 2739 //
1276 yutakakn 2784 // SYNOPSIS: /ssh /auth=passowrd /user=���[�U�� /passwd=�p�X���[�h
1277     // /ssh /auth=publickey /user=���[�U�� /passwd=�p�X���[�h /keyfile=�p�X
1278     // EXAMPLE: /ssh /auth=password /user=nike /passwd=a@bc
1279     // /ssh /auth=publickey /user=foo /passwd=bar /keyfile=d:\tmp\id_rsa
1280     // NOTICE: �p�X���[�h���p�X�������������������A�u�����N���������� @ ���g�������B
1281 yutakakn 2739 //
1282 yutakakn 2784 // (2004.11.30 yutaka)
1283     // (2005.1.26 yutaka) ���������B���J���F���T�|�[�g�B
1284     //
1285 yutakakn 2739 pvar->ssh2_autologin = 1; // for SSH2 (2004.11.30 yutaka)
1286    
1287 yutakakn 2784 if (MATCH_STR(option + 5, "=password") == 0) { // �p�X���[�h/keyboard-interactive�F��
1288     //pvar->auth_state.cur_cred.method = SSH_AUTH_PASSWORD;
1289     pvar->ssh2_authmethod = SSH_AUTH_PASSWORD;
1290 yutakakn 2739
1291 yutakakn 2784 } else if (MATCH_STR(option + 5, "=publickey") == 0) { // ���J���F��
1292     //pvar->auth_state.cur_cred.method = SSH_AUTH_RSA;
1293     pvar->ssh2_authmethod = SSH_AUTH_RSA;
1294    
1295 yutakakn 2739 } else {
1296     // TODO:
1297    
1298     }
1299    
1300     } else if (MATCH_STR(option + 1, "user=") == 0) {
1301 yutakakn 2784 replace_to_blank(option + 6, pvar->ssh2_username, sizeof(pvar->ssh2_username));
1302     //_snprintf(pvar->ssh2_username, sizeof(pvar->ssh2_username), "%s", option + 6);
1303 yutakakn 2739
1304     } else if (MATCH_STR(option + 1, "passwd=") == 0) {
1305 yutakakn 2784 replace_to_blank(option + 8, pvar->ssh2_password, sizeof(pvar->ssh2_password));
1306     //_snprintf(pvar->ssh2_password, sizeof(pvar->ssh2_password), "%s", option + 8);
1307 yutakakn 2739
1308 yutakakn 2784 } else if (MATCH_STR(option + 1, "keyfile=") == 0) {
1309     replace_to_blank(option + 9, pvar->ssh2_keyfile, sizeof(pvar->ssh2_keyfile));
1310    
1311 yutakakn 2728 }
1312    
1313     }
1314    
1315     return 0;
1316     }
1317    
1318     static void FAR PASCAL TTXParseParam(PCHAR param, PTTSet ts,
1319     PCHAR DDETopic)
1320     {
1321     int i;
1322     BOOL inParam = FALSE;
1323     BOOL inQuotes = FALSE;
1324     PCHAR option = NULL;
1325     GET_VAR();
1326    
1327     if (pvar->hostdlg_activated) {
1328     pvar->settings.Enabled = pvar->hostdlg_Enabled;
1329     }
1330    
1331     for (i = 0; param[i] != 0; i++) {
1332     if (inQuotes ? param[i] ==
1333     '"' : (param[i] == ' ' || param[i] == '\t')) {
1334     if (option != NULL) {
1335     char ch = param[i];
1336    
1337     param[i] = 0;
1338     if (parse_option
1339     (pvar, *option == '"' ? option + 1 : option)) {
1340     memset(option, ' ', i + 1 - (option - param));
1341     } else {
1342     param[i] = ch;
1343     }
1344     option = NULL;
1345     }
1346     inParam = FALSE;
1347     inQuotes = FALSE;
1348     } else if (!inParam) {
1349     if (param[i] == '"') {
1350     inQuotes = TRUE;
1351     inParam = TRUE;
1352     option = param + i;
1353     } else if (param[i] != ' ' && param[i] != '\t') {
1354     inParam = TRUE;
1355     option = param + i;
1356     }
1357     }
1358     }
1359    
1360     if (option != NULL) {
1361     if (parse_option(pvar, option)) {
1362     memset(option, ' ', i - (option - param));
1363     }
1364     }
1365    
1366     FWDUI_load_settings(pvar);
1367    
1368     (pvar->ParseParam) (param, ts, DDETopic);
1369    
1370     }
1371    
1372     static void PASCAL FAR TTXGetSetupHooks(TTXSetupHooks FAR * hooks)
1373     {
1374     GET_VAR();
1375    
1376     pvar->ReadIniFile = *hooks->ReadIniFile;
1377     pvar->WriteIniFile = *hooks->WriteIniFile;
1378     pvar->ParseParam = *hooks->ParseParam;
1379    
1380     *hooks->ReadIniFile = TTXReadINIFile;
1381     *hooks->WriteIniFile = TTXWriteINIFile;
1382     *hooks->ParseParam = TTXParseParam;
1383     }
1384    
1385     static void PASCAL FAR TTXSetWinSize(int rows, int cols)
1386     {
1387     GET_VAR();
1388    
1389     SSH_notify_win_size(pvar, cols, rows);
1390     }
1391    
1392     static void insertMenuBeforeItem(HMENU menu, WORD beforeItemID, WORD flags,
1393     WORD newItemID, char FAR * text)
1394     {
1395     int i, j;
1396    
1397     for (i = GetMenuItemCount(menu) - 1; i >= 0; i--) {
1398     HMENU submenu = GetSubMenu(menu, i);
1399    
1400     for (j = GetMenuItemCount(submenu) - 1; j >= 0; j--) {
1401     if (GetMenuItemID(submenu, j) == beforeItemID) {
1402     InsertMenu(submenu, j, MF_BYPOSITION | flags, newItemID,
1403     text);
1404     return;
1405     }
1406     }
1407     }
1408     }
1409    
1410     static void PASCAL FAR TTXModifyMenu(HMENU menu)
1411     {
1412     GET_VAR();
1413    
1414     /* inserts before ID_HELP_ABOUT */
1415     insertMenuBeforeItem(menu, 50990, MF_ENABLED, ID_ABOUTMENU,
1416     "About &TTSSH...");
1417    
1418     /* inserts before ID_SETUP_TCPIP */
1419     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHSETUPMENU,
1420     "SS&H...");
1421     /* inserts before ID_SETUP_TCPIP */
1422     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHAUTHSETUPMENU,
1423     "SSH &Authentication...");
1424     /* inserts before ID_SETUP_TCPIP */
1425     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHFWDSETUPMENU,
1426     "SSH F&orwarding...");
1427 yutakakn 2816
1428     insertMenuBeforeItem(menu, 50360, MF_ENABLED, ID_SSHKEYGENMENU,
1429     "SSH KeyGenerator...");
1430 yutakakn 2728 }
1431    
1432     static void append_about_text(HWND dlg, char FAR * prefix, char FAR * msg)
1433     {
1434     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1435     (LPARAM) prefix);
1436     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0, (LPARAM) msg);
1437     SendDlgItemMessage(dlg, IDC_ABOUTTEXT, EM_REPLACESEL, 0,
1438     (LPARAM) (char FAR *) "\r\n");
1439     }
1440    
1441 yutakakn 2792 // ���s�t�@�C�������o�[�W�������������� (2005.2.28 yutaka)
1442 yutakakn 2793 void get_file_version(char *exefile, int *major, int *minor, int *release, int *build)
1443 yutakakn 2792 {
1444     typedef struct {
1445     WORD wLanguage;
1446     WORD wCodePage;
1447     } LANGANDCODEPAGE, *LPLANGANDCODEPAGE;
1448     LPLANGANDCODEPAGE lplgcode;
1449     UINT unLen;
1450     DWORD size;
1451     char *buf = NULL;
1452     BOOL ret;
1453     int i;
1454     char fmt[80];
1455     char *pbuf;
1456    
1457     size = GetFileVersionInfoSize(exefile, NULL);
1458     if (size == 0) {
1459     goto error;
1460     }
1461     buf = malloc(size);
1462     ZeroMemory(buf, size);
1463    
1464     if (GetFileVersionInfo(exefile, 0, size, buf) == FALSE) {
1465     goto error;
1466     }
1467    
1468     ret = VerQueryValue(buf,
1469     "\\VarFileInfo\\Translation",
1470     (LPVOID *)&lplgcode, &unLen);
1471     if (ret == FALSE)
1472     goto error;
1473    
1474     for (i = 0 ; i < (int)(unLen / sizeof(LANGANDCODEPAGE)) ; i++) {
1475     _snprintf(fmt, sizeof(fmt), "\\StringFileInfo\\%04x%04x\\FileVersion",
1476     lplgcode[i].wLanguage, lplgcode[i].wCodePage);
1477     VerQueryValue(buf, fmt, &pbuf, &unLen);
1478     if (unLen > 0) { // get success
1479     int n, a, b, c, d;
1480    
1481     n = sscanf(pbuf, "%d, %d, %d, %d", &a, &b, &c, &d);
1482     if (n == 4) { // convert success
1483     *major = a;
1484     *minor = b;
1485     *release = c;
1486     *build = d;
1487     break;
1488     }
1489     }
1490     }
1491    
1492     free(buf);
1493     return;
1494    
1495     error:
1496     free(buf);
1497     *major = *minor = *release = *build = 0;
1498     }
1499    
1500 yutakakn 2728 static void init_about_dlg(PTInstVar pvar, HWND dlg)
1501     {
1502     char buf[1024];
1503 yutakakn 2792 int a, b, c, d;
1504 yutakakn 2728
1505 yutakakn 2792 // TTSSH���o�[�W�������������� (2005.2.28 yutaka)
1506     get_file_version("ttxssh.dll", &a, &b, &c, &d);
1507     _snprintf(buf, sizeof(buf), "TTSSH\r\nTeraterm Secure Shell extension, %d.%d", a, b);
1508     SendMessage(GetDlgItem(dlg, IDC_TTSSH_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1509    
1510 yutakakn 2782 // OpenSSL���o�[�W�������������� (2005.1.24 yutaka)
1511 yutakakn 2820 // ���������� (2005.5.11 yutaka)
1512     #ifdef OPENSSL_VERSION_TEXT
1513 yutakakn 2782 SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)OPENSSL_VERSION_TEXT);
1514 yutakakn 2820 #else
1515     SendMessage(GetDlgItem(dlg, IDC_OPENSSL_VERSION), WM_SETTEXT, 0, (LPARAM)"Unknown");
1516     #endif
1517 yutakakn 2782
1518 yutakakn 2820 // zlib���o�[�W�������������� (2005.5.11 yutaka)
1519     #ifdef ZLIB_VERSION
1520 yutakakn 2823 _snprintf(buf, sizeof(buf), "ZLib %s", ZLIB_VERSION);
1521 yutakakn 2820 #else
1522 yutakakn 2823 _snprintf(buf, sizeof(buf), "ZLib Unknown");
1523 yutakakn 2820 #endif
1524     SendMessage(GetDlgItem(dlg, IDC_ZLIB_VERSION), WM_SETTEXT, 0, (LPARAM)buf);
1525    
1526    
1527 yutakakn 2728 // TTSSH�_�C�A���O���\������SSH������������ (2004.10.30 yutaka)
1528     if (pvar->socket != INVALID_SOCKET) {
1529     if (SSHv1(pvar)) {
1530     SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1531     append_about_text(dlg, "Server ID: ", buf);
1532     SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1533     append_about_text(dlg, "Using protocol: ", buf);
1534     CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1535     append_about_text(dlg, "Encryption: ", buf);
1536     CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1537     append_about_text(dlg, "Server keys: ", buf);
1538     AUTH_get_auth_info(pvar, buf, sizeof(buf));
1539     append_about_text(dlg, "Authentication: ", buf);
1540     SSH_get_compression_info(pvar, buf, sizeof(buf));
1541     append_about_text(dlg, "Compression: ", buf);
1542    
1543     } else { // SSH2
1544     SSH_get_server_ID_info(pvar, buf, sizeof(buf));
1545     append_about_text(dlg, "Server ID: ", buf);
1546    
1547     append_about_text(dlg, "Client ID: ", pvar->client_version_string);
1548    
1549     SSH_get_protocol_version_info(pvar, buf, sizeof(buf));
1550     append_about_text(dlg, "Using protocol: ", buf);
1551    
1552     if (pvar->kex_type == KEX_DH_GRP1_SHA1) {
1553     strcpy(buf, KEX_DH1);
1554     } else if (pvar->kex_type == KEX_DH_GRP14_SHA1) {
1555     strcpy(buf, KEX_DH14);
1556     } else {
1557     strcpy(buf, KEX_DHGEX);
1558     }
1559     append_about_text(dlg, "KEX: ", buf);
1560    
1561     if (pvar->hostkey_type == KEY_DSA) {
1562     strcpy(buf, "ssh-dss");
1563     } else {
1564     strcpy(buf, "ssh-rsa");
1565     }
1566     append_about_text(dlg, "Host Key: ", buf);
1567    
1568 yutakakn 2758 // add HMAC algorithm (2004.12.17 yutaka)
1569     buf[0] = '\0';
1570     if (pvar->ctos_hmac == HMAC_SHA1) {
1571     strcat(buf, "hmac-sha1");
1572     } else if (pvar->ctos_hmac == HMAC_MD5) {
1573     strcat(buf, "hmac-md5");
1574     }
1575     strcat(buf, " to server, ");
1576     if (pvar->stoc_hmac == HMAC_SHA1) {
1577     strcat(buf, "hmac-sha1");
1578     } else if (pvar->stoc_hmac == HMAC_MD5) {
1579     strcat(buf, "hmac-md5");
1580     }
1581     strcat(buf, " from server");
1582     append_about_text(dlg, "HMAC: ", buf);
1583    
1584 yutakakn 2728 CRYPT_get_cipher_info(pvar, buf, sizeof(buf));
1585     append_about_text(dlg, "Encryption: ", buf);
1586     CRYPT_get_server_key_info(pvar, buf, sizeof(buf));
1587     append_about_text(dlg, "Server keys: ", buf);
1588     AUTH_get_auth_info(pvar, buf, sizeof(buf));
1589     append_about_text(dlg, "Authentication: ", buf);
1590 yutakakn 2873
1591 yutakakn 2728 SSH_get_compression_info(pvar, buf, sizeof(buf));
1592 yutakakn 2873 if (pvar->ctos_compression == COMP_DELAYED) { // �x���p�P�b�g���k������ (2006.6.23 yutaka)
1593     append_about_text(dlg, "Delayed Compression: ", buf);
1594     } else {
1595     append_about_text(dlg, "Compression: ", buf);
1596     }
1597 yutakakn 2728
1598     }
1599     }
1600     }
1601    
1602     static BOOL CALLBACK TTXAboutDlg(HWND dlg, UINT msg, WPARAM wParam,
1603     LPARAM lParam)
1604     {
1605     switch (msg) {
1606     case WM_INITDIALOG:
1607     init_about_dlg((PTInstVar) lParam, dlg);
1608     return TRUE;
1609     case WM_COMMAND:
1610     switch (LOWORD(wParam)) {
1611     case IDOK:
1612     EndDialog(dlg, 1);
1613     return TRUE;
1614     case IDCANCEL: /* there isn't a cancel button, but other Windows
1615     UI things can send this message */
1616     EndDialog(dlg, 0);
1617     return TRUE;
1618     }
1619     break;
1620     }
1621    
1622     return FALSE;
1623     }
1624    
1625     static char FAR *get_cipher_name(int cipher)
1626     {
1627     switch (cipher) {
1628     case SSH_CIPHER_NONE:
1629     return "<ciphers below this line are disabled>";
1630     case SSH_CIPHER_RC4:
1631     return "RC4";
1632     case SSH_CIPHER_3DES:
1633     return "3DES";
1634     case SSH_CIPHER_DES:
1635     return "DES";
1636     case SSH_CIPHER_IDEA:
1637     return "IDEA";
1638     case SSH_CIPHER_TSS:
1639     return "TSS";
1640     case SSH_CIPHER_BLOWFISH:
1641     return "Blowfish";
1642    
1643     // for SSH2(yutaka)
1644     case SSH_CIPHER_AES128:
1645     return "AES128(SSH2)";
1646     case SSH_CIPHER_3DES_CBC:
1647     return "3DES-CBC(SSH2)";
1648    
1649     default:
1650     return NULL;
1651     }
1652     }
1653    
1654     static void set_move_button_status(HWND dlg)
1655     {
1656     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1657     int curPos = (int) SendMessage(cipherControl, LB_GETCURSEL, 0, 0);
1658     int maxPos = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0) - 1;
1659    
1660     EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERUP), curPos > 0
1661     && curPos <= maxPos);
1662     EnableWindow(GetDlgItem(dlg, IDC_SSHMOVECIPHERDOWN), curPos >= 0
1663     && curPos < maxPos);
1664     }
1665    
1666     static void init_setup_dlg(PTInstVar pvar, HWND dlg)
1667     {
1668     HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1669     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1670     int i;
1671     int ch;
1672    
1673     SendMessage(compressionControl, TBM_SETRANGE, TRUE, MAKELONG(0, 9));
1674     SendMessage(compressionControl, TBM_SETPOS, TRUE,
1675     pvar->settings.CompressionLevel);
1676    
1677     normalize_cipher_order(pvar->settings.CipherOrder);
1678     SSH2_update_cipher_myproposal(pvar); // yutaka
1679    
1680     for (i = 0; pvar->settings.CipherOrder[i] != 0; i++) {
1681     int cipher = pvar->settings.CipherOrder[i] - '0';
1682     char FAR *name = get_cipher_name(cipher);
1683    
1684     if (name != NULL) {
1685     SendMessage(cipherControl, LB_ADDSTRING, 0, (LPARAM) name);
1686     }
1687     }
1688    
1689     SendMessage(cipherControl, LB_SETCURSEL, 0, 0);
1690     set_move_button_status(dlg);
1691    
1692     for (i = 0; (ch = pvar->settings.KnownHostsFiles[i]) != 0 && ch != ';';
1693     i++) {
1694     }
1695     if (ch != 0) {
1696     pvar->settings.KnownHostsFiles[i] = 0;
1697     SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1698     pvar->settings.KnownHostsFiles);
1699     pvar->settings.KnownHostsFiles[i] = ch;
1700     SetDlgItemText(dlg, IDC_READONLYFILENAME,
1701     pvar->settings.KnownHostsFiles + i + 1);
1702     } else {
1703     SetDlgItemText(dlg, IDC_READWRITEFILENAME,
1704     pvar->settings.KnownHostsFiles);
1705     }
1706 yutakakn 2789
1707     // SSH2 HeartBeat(keep-alive)������ (2005.2.22 yutaka)
1708     {
1709     char buf[10];
1710     _snprintf(buf, sizeof(buf), "%d", pvar->settings.ssh_heartbeat_overtime);
1711     SetDlgItemText(dlg, IDC_HEARTBEAT_EDIT, buf);
1712     }
1713    
1714 yutakakn 2728 }
1715    
1716     void get_teraterm_dir_relative_name(char FAR * buf, int bufsize,
1717     char FAR * basename)
1718     {
1719     int filename_start = 0;
1720     int i;
1721     int ch;
1722    
1723     if (basename[0] == '\\' || basename[0] == '/'
1724     || (basename[0] != 0 && basename[1] == ':')) {
1725     strncpy(buf, basename, bufsize);
1726     buf[bufsize - 1] = 0;
1727     return;
1728     }
1729    
1730     GetModuleFileName(NULL, buf, bufsize);
1731     for (i = 0; (ch = buf[i]) != 0; i++) {
1732     if (ch == '\\' || ch == '/' || ch == ':') {
1733     filename_start = i + 1;
1734     }
1735     }
1736    
1737     if (bufsize > filename_start) {
1738     strncpy(buf + filename_start, basename, bufsize - filename_start);
1739     }
1740     buf[bufsize - 1] = 0;
1741     }
1742    
1743     int copy_teraterm_dir_relative_path(char FAR * dest, int destsize,
1744     char FAR * basename)
1745     {
1746     char buf[1024];
1747     int filename_start = 0;
1748     int i;
1749     int ch, ch2;
1750    
1751     if (basename[0] != '\\' && basename[0] != '/'
1752     && (basename[0] == 0 || basename[1] != ':')) {
1753     strncpy(dest, basename, destsize);
1754     dest[destsize - 1] = 0;
1755     return strlen(dest);
1756     }
1757    
1758     GetModuleFileName(NULL, buf, sizeof(buf));
1759     for (i = 0; (ch = buf[i]) != 0; i++) {
1760     if (ch == '\\' || ch == '/' || ch == ':') {
1761     filename_start = i + 1;
1762     }
1763     }
1764    
1765     for (i = 0; i < filename_start; i++) {
1766     ch = toupper(buf[i]);
1767     ch2 = toupper(basename[i]);
1768    
1769     if (ch == ch2
1770     || ((ch == '\\' || ch == '/')
1771     && (ch2 == '\\' || ch2 == '/'))) {
1772     } else {
1773     break;
1774     }
1775     }
1776    
1777     if (i == filename_start) {
1778     strncpy(dest, basename + i, destsize);
1779     } else {
1780     strncpy(dest, basename, destsize);
1781     }
1782     dest[destsize - 1] = 0;
1783     return strlen(dest);
1784     }
1785    
1786     static void complete_setup_dlg(PTInstVar pvar, HWND dlg)
1787     {
1788     char buf[4096];
1789     char buf2[1024];
1790     HWND compressionControl = GetDlgItem(dlg, IDC_SSHCOMPRESSIONLEVEL);
1791     HWND cipherControl = GetDlgItem(dlg, IDC_SSHCIPHERPREFS);
1792     int i, j, buf2index, bufindex;
1793     int count = (int) SendMessage(cipherControl, LB_GETCOUNT, 0, 0);
1794    
1795     pvar->settings.CompressionLevel =
1796     (int) SendMessage(compressionControl, TBM_GETPOS, 0, 0);
1797    
1798     buf2index = 0;
1799     for (i = 0; i < count; i++) {
1800     int len = SendMessage(cipherControl, LB_GETTEXTLEN, i, 0);
1801    
1802     if (len > 0 && len < sizeof(buf)) { /* should always be true */
1803     buf[0] = 0;
1804     SendMessage(cipherControl, LB_GETTEXT, i, (LPARAM) buf);
1805     for (j = 0;
1806     j <= SSH_CIPHER_MAX
1807     && strcmp(buf, get_cipher_name(j)) != 0; j++) {
1808     }
1809     if (j <= SSH_CIPHER_MAX) {
1810     buf2[buf2index] = '0' + j;
1811     buf2index++;
1812     }
1813     }
1814     }
1815     buf2[buf2index] = 0;
1816     normalize_cipher_order(buf2);
1817     strcpy(pvar->settings.CipherOrder, buf2);
1818     SSH2_update_cipher_myproposal(pvar); // yutaka
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);