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 2846 - (hide annotations) (download) (as text)
Fri Oct 21 13:36:47 2005 UTC (18 years, 5 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/ttxssh.c
File MIME type: text/x-csrc
File size: 85041 byte(s)
接続ダイアログに History チェックボックスを追加した。
2.18へアップデート。

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