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 2915 - (hide annotations) (download) (as text)
Thu Oct 19 06:24:05 2006 UTC (17 years, 5 months ago) by maya
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 91279 byte(s)
SSHで接続中にNew connectionダイアログからtelnet接続できないのを修正した。

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