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 2891 - (hide annotations) (download) (as text)
Sat Aug 5 03:47:49 2006 UTC (17 years, 8 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 87174 byte(s)
パスワードをメモリ上に覚えておくかどうかの設定は teraterm.ini に反映させるようにした。

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