Develop and Download Open Source Software

Browse Subversion Repository

Contents of /trunk/ttssh2/ttxssh/hosts.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 8240 - (show annotations) (download) (as text)
Wed Oct 2 14:00:04 2019 UTC (4 years, 6 months ago) by zmatsuo
File MIME type: text/x-csrc
File size: 67857 byte(s)
ttssh2でSetI18DlgStrs()を使用するようにした
1 /*
2 * Copyright (c) 1998-2001, Robert O'Callahan
3 * (C) 2004-2019 TeraTerm Project
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 This code is copyright (C) 1998-1999 Robert O'Callahan.
32 See LICENSE.TXT for the license.
33 */
34 #include "ttxssh.h"
35 #include "util.h"
36 #include "resource.h"
37 #include "matcher.h"
38 #include "ssh.h"
39 #include "key.h"
40 #include "hosts.h"
41 #include "dns.h"
42 #include "dlglib.h"
43 #include "compat_win.h"
44
45 #include <openssl/bn.h>
46 #include <openssl/evp.h>
47 #include <openssl/rsa.h>
48 #include <openssl/dsa.h>
49
50 #include <fcntl.h>
51 #include <io.h>
52 #include <errno.h>
53 #include <sys/stat.h>
54 #include <direct.h>
55 #include <memory.h>
56
57
58 #undef DialogBoxParam
59 #define DialogBoxParam(p1,p2,p3,p4,p5) \
60 TTDialogBoxParam(p1,p2,p3,p4,p5)
61 #undef EndDialog
62 #define EndDialog(p1,p2) \
63 TTEndDialog(p1, p2)
64
65 // BASE64�\���������i��������'='�����������������j
66 static char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
67
68
69 BOOL HOSTS_resume_session_after_known_hosts(PTInstVar pvar);
70 void HOSTS_cancel_session_after_known_hosts(PTInstVar pvar);
71
72
73 static char **parse_multi_path(char *buf)
74 {
75 int i;
76 int ch;
77 int num_paths = 1;
78 char ** result;
79 int last_path_index;
80
81 for (i = 0; (ch = buf[i]) != 0; i++) {
82 if (ch == ';') {
83 num_paths++;
84 }
85 }
86
87 result =
88 (char **) malloc(sizeof(char *) * (num_paths + 1));
89
90 last_path_index = 0;
91 num_paths = 0;
92 for (i = 0; (ch = buf[i]) != 0; i++) {
93 if (ch == ';') {
94 buf[i] = 0;
95 result[num_paths] = _strdup(buf + last_path_index);
96 num_paths++;
97 buf[i] = ch;
98 last_path_index = i + 1;
99 }
100 }
101 if (i > last_path_index) {
102 result[num_paths] = _strdup(buf + last_path_index);
103 num_paths++;
104 }
105 result[num_paths] = NULL;
106 return result;
107 }
108
109 void HOSTS_init(PTInstVar pvar)
110 {
111 pvar->hosts_state.prefetched_hostname = NULL;
112 key_init(&pvar->hosts_state.hostkey);
113 pvar->hosts_state.hosts_dialog = NULL;
114 pvar->hosts_state.file_names = NULL;
115
116 /*
117 * �O�����I�v�V�����w��(/nosecuritywarning)���c���������������������������B
118 */
119 pvar->nocheck_known_hosts = FALSE;
120 }
121
122 void HOSTS_open(PTInstVar pvar)
123 {
124 pvar->hosts_state.file_names =
125 parse_multi_path(pvar->session_settings.KnownHostsFiles);
126 }
127
128 //
129 // known_hosts�t�@�C�������e�������� pvar->hosts_state.file_data ����������
130 //
131 static int begin_read_file(PTInstVar pvar, char *name,
132 int suppress_errors)
133 {
134 int fd;
135 int length;
136 int amount_read;
137 char buf[2048];
138
139 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
140 fd = _open(buf, _O_RDONLY | _O_SEQUENTIAL | _O_BINARY);
141 if (fd == -1) {
142 if (!suppress_errors) {
143 if (errno == ENOENT) {
144 UTIL_get_lang_msg("MSG_HOSTS_READ_ENOENT_ERROR", pvar,
145 "An error occurred while trying to read a known_hosts file.\n"
146 "The specified filename does not exist.");
147 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
148 } else {
149 UTIL_get_lang_msg("MSG_HOSTS_READ_ERROR", pvar,
150 "An error occurred while trying to read a known_hosts file.");
151 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
152 }
153 }
154 return 0;
155 }
156
157 length = (int) _lseek(fd, 0, SEEK_END);
158 _lseek(fd, 0, SEEK_SET);
159
160 if (length >= 0 && length < 0x7FFFFFFF) {
161 pvar->hosts_state.file_data = malloc(length + 1);
162 if (pvar->hosts_state.file_data == NULL) {
163 if (!suppress_errors) {
164 UTIL_get_lang_msg("MSG_HOSTS_ALLOC_ERROR", pvar,
165 "Memory ran out while trying to allocate space to read a known_hosts file.");
166 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
167 }
168 _close(fd);
169 return 0;
170 }
171 } else {
172 if (!suppress_errors) {
173 UTIL_get_lang_msg("MSG_HOSTS_READ_ERROR", pvar,
174 "An error occurred while trying to read a known_hosts file.");
175 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
176 }
177 _close(fd);
178 return 0;
179 }
180
181 amount_read = _read(fd, pvar->hosts_state.file_data, length);
182 pvar->hosts_state.file_data[length] = 0;
183
184 _close(fd);
185
186 if (amount_read != length) {
187 if (!suppress_errors) {
188 UTIL_get_lang_msg("MSG_HOSTS_READ_ERROR", pvar,
189 "An error occurred while trying to read a known_hosts file.");
190 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
191 }
192 free(pvar->hosts_state.file_data);
193 pvar->hosts_state.file_data = NULL;
194 return 0;
195 } else {
196 return 1;
197 }
198 }
199
200 static int end_read_file(PTInstVar pvar, int suppress_errors)
201 {
202 free(pvar->hosts_state.file_data);
203 pvar->hosts_state.file_data = NULL;
204 return 1;
205 }
206
207 static int begin_read_host_files(PTInstVar pvar, int suppress_errors)
208 {
209 pvar->hosts_state.file_num = 0;
210 pvar->hosts_state.file_data = NULL;
211 return 1;
212 }
213
214 // MIME64�����������X�L�b�v����
215 static int eat_base64(char *data)
216 {
217 int index = 0;
218 int ch;
219
220 for (;;) {
221 ch = data[index];
222 if (ch == '=' || strchr(base64, ch)) {
223 // BASE64���\�������������������� index ���i����
224 index++;
225 } else {
226 break;
227 }
228 }
229
230 return index;
231 }
232
233 static int eat_spaces(char *data)
234 {
235 int index = 0;
236 int ch;
237
238 while ((ch = data[index]) == ' ' || ch == '\t') {
239 index++;
240 }
241 return index;
242 }
243
244 static int eat_digits(char *data)
245 {
246 int index = 0;
247 int ch;
248
249 while ((ch = data[index]) >= '0' && ch <= '9') {
250 index++;
251 }
252 return index;
253 }
254
255 static int eat_to_end_of_line(char *data)
256 {
257 int index = 0;
258 int ch;
259
260 while ((ch = data[index]) != '\n' && ch != '\r' && ch != 0) {
261 index++;
262 }
263
264 while ((ch = data[index]) == '\n' || ch == '\r') {
265 index++;
266 }
267
268 return index;
269 }
270
271 static int eat_to_end_of_pattern(char *data)
272 {
273 int index = 0;
274 int ch;
275
276 while (ch = data[index], is_pattern_char(ch)) {
277 index++;
278 }
279
280 return index;
281 }
282
283 // SSH2���� BASE64 �`�����i�[����������
284 static Key *parse_base64data(char *data)
285 {
286 int count;
287 unsigned char *blob = NULL;
288 int len, n;
289 Key *key = NULL;
290 char ch;
291
292 // BASE64���������T�C�Y������
293 count = eat_base64(data);
294 len = 2 * count;
295 blob = malloc(len);
296 if (blob == NULL)
297 goto error;
298
299 // BASE64�f�R�[�h
300 ch = data[count];
301 data[count] = '\0'; // ���������s�R�[�h������������������������������������
302 n = b64decode(blob, len, data);
303 data[count] = ch;
304 if (n < 0) {
305 goto error;
306 }
307
308 key = key_from_blob(blob, n);
309 if (key == NULL)
310 goto error;
311
312 error:
313 if (blob != NULL)
314 free(blob);
315
316 return (key);
317 }
318
319
320 static char *parse_bignum(char *data)
321 {
322 uint32 digits = 0;
323 BIGNUM *num = BN_new();
324 BIGNUM *billion = BN_new();
325 BIGNUM *digits_num = BN_new();
326 BN_CTX *ctx = BN_CTX_new();
327 char *result;
328 int ch;
329 int leftover_digits = 1;
330
331 BN_CTX_init(ctx);
332 BN_set_word(num, 0);
333 BN_set_word(billion, 1000000000L);
334
335 while ((ch = *data) >= '0' && ch <= '9') {
336 if (leftover_digits == 1000000000L) {
337 BN_set_word(digits_num, digits);
338 BN_mul(num, num, billion, ctx);
339 BN_add(num, num, digits_num);
340 leftover_digits = 1;
341 digits = 0;
342 }
343
344 digits = digits * 10 + ch - '0';
345 leftover_digits *= 10;
346 data++;
347 }
348
349 BN_set_word(digits_num, digits);
350 BN_set_word(billion, leftover_digits);
351 BN_mul(num, num, billion, ctx);
352 BN_add(num, num, digits_num);
353
354 result = (char *) malloc(2 + BN_num_bytes(num));
355 set_ushort16_MSBfirst(result, BN_num_bits(num));
356 BN_bn2bin(num, result + 2);
357
358 BN_CTX_free(ctx);
359 BN_free(digits_num);
360 BN_free(num);
361 BN_free(billion);
362
363 return result;
364 }
365
366 //
367 // known_hosts�t�@�C�������e���������A�w�������z�X�g�����J�����T���B
368 //
369 static int check_host_key(PTInstVar pvar, char *hostname,
370 unsigned short tcpport, char *data,
371 Key *key)
372 {
373 int index = eat_spaces(data);
374 int matched = 0;
375 int keybits = 0;
376
377 if (data[index] == '#') {
378 return index + eat_to_end_of_line(data + index);
379 }
380
381 /* if we find an empty line, then it won't have any patterns matching the hostname
382 and so we skip it */
383 index--;
384 do {
385 int negated;
386 int bracketed;
387 char *end_bracket;
388 int host_matched = 0;
389 unsigned short keyfile_port = 22;
390
391 index++;
392 negated = data[index] == '!';
393
394 if (negated) {
395 index++;
396 bracketed = data[index] == '[';
397 if (bracketed) {
398 end_bracket = strstr(data + index + 1, "]:");
399 if (end_bracket != NULL) {
400 *end_bracket = ' ';
401 index++;
402 }
403 }
404 host_matched = match_pattern(data + index, hostname);
405 if (bracketed && end_bracket != NULL) {
406 *end_bracket = ']';
407 keyfile_port = atoi(end_bracket + 2);
408 }
409 if (host_matched && keyfile_port == tcpport) {
410 return index + eat_to_end_of_line(data + index);
411 }
412 } else {
413 bracketed = data[index] == '[';
414 if (bracketed) {
415 end_bracket = strstr(data + index + 1, "]:");
416 if (end_bracket != NULL) {
417 *end_bracket = ' ';
418 index++;
419 }
420 }
421 host_matched = match_pattern(data + index, hostname);
422 if (bracketed && end_bracket != NULL) {
423 *end_bracket = ']';
424 keyfile_port = atoi(end_bracket + 2);
425 }
426 if (host_matched && keyfile_port == tcpport) {
427 matched = 1;
428 }
429 }
430
431 index += eat_to_end_of_pattern(data + index);
432 } while (data[index] == ',');
433
434 if (!matched) {
435 return index + eat_to_end_of_line(data + index);
436 } else {
437 // ���������������t�H�[�}�b�g��������
438 // �����A���������v�����G���g�����������������������B
439 /*
440 [SSH1]
441 192.168.1.2 1024 35 13032....
442
443 [SSH2]
444 192.168.1.2 ssh-rsa AAAAB3NzaC1....
445 192.168.1.2 ssh-dss AAAAB3NzaC1....
446 192.168.1.2 rsa AAAAB3NzaC1....
447 192.168.1.2 dsa AAAAB3NzaC1....
448 192.168.1.2 rsa1 AAAAB3NzaC1....
449 */
450 int rsa1_key_bits;
451
452 index += eat_spaces(data + index);
453
454 rsa1_key_bits = atoi(data + index);
455 if (rsa1_key_bits > 0) { // RSA1������
456 if (!SSHv1(pvar)) { // SSH2��������������������
457 return index + eat_to_end_of_line(data + index);
458 }
459
460 key->type = KEY_RSA1;
461
462 key->bits = rsa1_key_bits;
463 index += eat_digits(data + index);
464 index += eat_spaces(data + index);
465
466 key->exp = parse_bignum(data + index);
467 index += eat_digits(data + index);
468 index += eat_spaces(data + index);
469
470 key->mod = parse_bignum(data + index);
471 } else {
472 char *cp, *p;
473 Key *key2;
474 ssh_keytype key_type;
475
476 if (!SSHv2(pvar)) { // SSH1��������������������
477 return index + eat_to_end_of_line(data + index);
478 }
479
480 cp = data + index;
481 p = strchr(cp, ' ');
482 if (p == NULL) {
483 return index + eat_to_end_of_line(data + index);
484 }
485 index += (p - cp); // setup index
486 *p = '\0';
487 key_type = get_keytype_from_name(cp);
488 *p = ' ';
489
490 index += eat_spaces(data + index); // update index
491
492 // base64 decode
493 key2 = parse_base64data(data + index);
494 if (key2 == NULL) {
495 return index + eat_to_end_of_line(data + index);
496 }
497
498 // setup
499 key->type = key2->type;
500 key->dsa = key2->dsa;
501 key->rsa = key2->rsa;
502 key->ecdsa = key2->ecdsa;
503 key->ed25519_pk = key2->ed25519_pk;
504
505 index += eat_base64(data + index);
506 index += eat_spaces(data + index);
507
508 // Key�\�������g���������� (2008.3.2 yutaka)
509 free(key2);
510 }
511
512 return index + eat_to_end_of_line(data + index);
513 }
514 }
515
516 //
517 // known_hosts�t�@�C�������z�X�g�������v�����s������
518 // return_always
519 // 0: �������������T��
520 // 1: 1�s�����T��������
521 //
522 static int read_host_key(PTInstVar pvar,
523 char *hostname, unsigned short tcpport,
524 int suppress_errors, int return_always,
525 Key *key)
526 {
527 int i;
528 int while_flg;
529
530 for (i = 0; hostname[i] != 0; i++) {
531 int ch = hostname[i];
532
533 if (!is_pattern_char(ch) || ch == '*' || ch == '?') {
534 if (!suppress_errors) {
535 UTIL_get_lang_msg("MSG_HOSTS_HOSTNAME_INVALID_ERROR", pvar,
536 "The host name contains an invalid character.\n"
537 "This session will be terminated.");
538 notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE);
539 }
540 return 0;
541 }
542 }
543
544 if (i == 0) {
545 if (!suppress_errors) {
546 UTIL_get_lang_msg("MSG_HOSTS_HOSTNAME_EMPTY_ERROR", pvar,
547 "The host name should not be empty.\n"
548 "This session will be terminated.");
549 notify_fatal_error(pvar, pvar->ts->UIMsg, TRUE);
550 }
551 return 0;
552 }
553
554 // hostkey type is KEY_UNSPEC.
555 key_init(key);
556
557 do {
558 if (pvar->hosts_state.file_data == NULL
559 || pvar->hosts_state.file_data[pvar->hosts_state.file_data_index] == 0) {
560 char *filename;
561 int keep_going = 1;
562
563 if (pvar->hosts_state.file_data != NULL) {
564 end_read_file(pvar, suppress_errors);
565 }
566
567 do {
568 filename =
569 pvar->hosts_state.file_names[pvar->hosts_state.file_num];
570
571 if (filename == NULL) {
572 return 1;
573 } else {
574 pvar->hosts_state.file_num++;
575
576 if (filename[0] != 0) {
577 if (begin_read_file(pvar, filename, suppress_errors)) {
578 pvar->hosts_state.file_data_index = 0;
579 keep_going = 0;
580 }
581 }
582 }
583 } while (keep_going);
584 }
585
586 pvar->hosts_state.file_data_index +=
587 check_host_key(pvar, hostname, tcpport,
588 pvar->hosts_state.file_data +
589 pvar->hosts_state.file_data_index,
590 key);
591
592 if (!return_always) {
593 // �L�����L�[��������������
594 while_flg = (key->type == KEY_UNSPEC);
595 }
596 else {
597 while_flg = 0;
598 }
599 } while (while_flg);
600
601 return 1;
602 }
603
604 static void finish_read_host_files(PTInstVar pvar, int suppress_errors)
605 {
606 if (pvar->hosts_state.file_data != NULL) {
607 end_read_file(pvar, suppress_errors);
608 }
609 }
610
611 // �T�[�o�����������O���Aknown_hosts�t�@�C�������z�X�g���J�������������������B
612 void HOSTS_prefetch_host_key(PTInstVar pvar, char *hostname, unsigned short tcpport)
613 {
614 Key key; // known_hosts���o�^������������
615
616 if (!begin_read_host_files(pvar, 1)) {
617 return;
618 }
619
620 memset(&key, 0, sizeof(key));
621 if (!read_host_key(pvar, hostname, tcpport, 1, 0, &key)) {
622 return;
623 }
624
625 key_copy(&pvar->hosts_state.hostkey, &key);
626 key_init(&key);
627
628 free(pvar->hosts_state.prefetched_hostname);
629 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
630
631 finish_read_host_files(pvar, 1);
632 }
633
634
635 // known_hosts�t�@�C�������Y�������L�[���������������B
636 //
637 // return:
638 // *keyptr != NULL ��������
639 //
640 static int parse_hostkey_file(PTInstVar pvar, char *hostname,
641 unsigned short tcpport, char *data, Key **keyptr)
642 {
643 int index = eat_spaces(data);
644 int matched = 0;
645 int keybits = 0;
646 ssh_keytype ktype;
647 Key *key;
648
649 *keyptr = NULL;
650
651 if (data[index] == '#') {
652 return index + eat_to_end_of_line(data + index);
653 }
654
655 /* if we find an empty line, then it won't have any patterns matching the hostname
656 and so we skip it */
657 index--;
658 do {
659 int negated;
660 int bracketed;
661 char *end_bracket;
662 int host_matched = 0;
663 unsigned short keyfile_port = 22;
664
665 index++;
666 negated = data[index] == '!';
667
668 if (negated) {
669 index++;
670 bracketed = data[index] == '[';
671 if (bracketed) {
672 end_bracket = strstr(data + index + 1, "]:");
673 if (end_bracket != NULL) {
674 *end_bracket = ' ';
675 index++;
676 }
677 }
678 host_matched = match_pattern(data + index, hostname);
679 if (bracketed && end_bracket != NULL) {
680 *end_bracket = ']';
681 keyfile_port = atoi(end_bracket + 2);
682 }
683 if (host_matched && keyfile_port == tcpport) {
684 return index + eat_to_end_of_line(data + index);
685 }
686 }
687 else {
688 bracketed = data[index] == '[';
689 if (bracketed) {
690 end_bracket = strstr(data + index + 1, "]:");
691 if (end_bracket != NULL) {
692 *end_bracket = ' ';
693 index++;
694 }
695 }
696 host_matched = match_pattern(data + index, hostname);
697 if (bracketed && end_bracket != NULL) {
698 *end_bracket = ']';
699 keyfile_port = atoi(end_bracket + 2);
700 }
701 if (host_matched && keyfile_port == tcpport) {
702 matched = 1;
703 }
704 }
705
706 index += eat_to_end_of_pattern(data + index);
707 } while (data[index] == ',');
708
709 if (!matched) {
710 return index + eat_to_end_of_line(data + index);
711 }
712 else {
713 // ���������������t�H�[�}�b�g��������
714 // �����A���������v�����G���g�����������������������B
715 /*
716 [SSH1]
717 192.168.1.2 1024 35 13032....
718
719 [SSH2]
720 192.168.1.2 ssh-rsa AAAAB3NzaC1....
721 192.168.1.2 ssh-dss AAAAB3NzaC1....
722 192.168.1.2 rsa AAAAB3NzaC1....
723 192.168.1.2 dsa AAAAB3NzaC1....
724 192.168.1.2 rsa1 AAAAB3NzaC1....
725 */
726 int rsa1_key_bits;
727
728 index += eat_spaces(data + index);
729
730 rsa1_key_bits = atoi(data + index);
731 if (rsa1_key_bits > 0) { // RSA1������
732 if (!SSHv1(pvar)) { // SSH2��������������������
733 return index + eat_to_end_of_line(data + index);
734 }
735
736 key = key_new(KEY_RSA1);
737 key->bits = rsa1_key_bits;
738
739 index += eat_digits(data + index);
740 index += eat_spaces(data + index);
741 key->exp = parse_bignum(data + index);
742
743 index += eat_digits(data + index);
744 index += eat_spaces(data + index);
745 key->mod = parse_bignum(data + index);
746
747 // setup
748 *keyptr = key;
749
750 }
751 else {
752 char *cp, *p;
753
754 if (!SSHv2(pvar)) { // SSH1��������������������
755 return index + eat_to_end_of_line(data + index);
756 }
757
758 cp = data + index;
759 p = strchr(cp, ' ');
760 if (p == NULL) {
761 return index + eat_to_end_of_line(data + index);
762 }
763 index += (p - cp); // setup index
764 *p = '\0';
765 ktype = get_keytype_from_name(cp);
766 *p = ' ';
767
768 index += eat_spaces(data + index); // update index
769
770 // base64 decode
771 key = parse_base64data(data + index);
772 if (key == NULL) {
773 return index + eat_to_end_of_line(data + index);
774 }
775
776 // setup
777 *keyptr = key;
778
779 index += eat_base64(data + index);
780 index += eat_spaces(data + index);
781 }
782
783 return index + eat_to_end_of_line(data + index);
784 }
785 }
786
787 // known_hosts�t�@�C�������z�X�g���J�������������B
788 // �������������������������������AHost key rotation�p���V�K���p�������B
789 //
790 // return 1: success
791 // 0: fail
792 int HOSTS_hostkey_foreach(PTInstVar pvar, hostkeys_foreach_fn *callback, void *ctx)
793 {
794 int success = 0;
795 int suppress_errors = 1;
796 unsigned short tcpport;
797 char *filename;
798 char *hostname;
799 Key *key;
800
801 if (!begin_read_host_files(pvar, 1)) {
802 goto error;
803 }
804
805 // Host key rotation�����Aknown_hosts �t�@�C�������������������A
806 // ������������1�������t�@�C�������������i2�������t�@�C����ReadOnly�������j�B
807 filename = pvar->hosts_state.file_names[pvar->hosts_state.file_num];
808 pvar->hosts_state.file_num++;
809
810 pvar->hosts_state.file_data_index = -1;
811 if (filename[0] != 0) {
812 if (begin_read_file(pvar, filename, suppress_errors)) {
813 pvar->hosts_state.file_data_index = 0;
814 }
815 }
816 if (pvar->hosts_state.file_data_index == -1)
817 goto error;
818
819 // ���������������z�X�g�����|�[�g�����B
820 hostname = pvar->ssh_state.hostname;
821 tcpport = pvar->ssh_state.tcpport;
822
823 // known_hosts�t�@�C�������e�������� pvar->hosts_state.file_data �������������������B
824 // ������ \0 �B
825 while (pvar->hosts_state.file_data[pvar->hosts_state.file_data_index] != 0) {
826 key = NULL;
827
828 pvar->hosts_state.file_data_index +=
829 parse_hostkey_file(pvar, hostname, tcpport,
830 pvar->hosts_state.file_data +
831 pvar->hosts_state.file_data_index,
832 &key);
833
834 // �Y�����������������������A�R�[���o�b�N�����������o���B
835 if (key != NULL) {
836 if (callback(key, ctx) == 0)
837 key_free(key);
838 }
839 }
840
841 success = 1;
842
843 error:
844 finish_read_host_files(pvar, 1);
845
846 return (success);
847 }
848
849
850 static BOOL equal_mp_ints(unsigned char *num1,
851 unsigned char *num2)
852 {
853 if (num1 == NULL || num2 == NULL) {
854 return FALSE;
855 } else {
856 uint32 bytes = (get_ushort16_MSBfirst(num1) + 7) / 8;
857
858 if (bytes != (get_ushort16_MSBfirst(num2) + 7) / 8) {
859 return FALSE; /* different byte lengths */
860 } else {
861 return memcmp(num1 + 2, num2 + 2, bytes) == 0;
862 }
863 }
864 }
865
866
867 // ���J�������r���s���B
868 //
869 // return
870 // -1 ... �����^������
871 // 0 ... ����������
872 // 1 ... ������
873 int HOSTS_compare_public_key(Key *src, Key *key)
874 {
875 int bits;
876 unsigned char *exp;
877 unsigned char *mod;
878 const EC_GROUP *group;
879 const EC_POINT *pa, *pb;
880 Key *a, *b;
881
882 if (src->type != key->type) {
883 return -1;
884 }
885
886 switch (key->type) {
887 case KEY_RSA1: // SSH1 host public key
888 bits = key->bits;
889 exp = key->exp;
890 mod = key->mod;
891
892 /* just check for equal exponent and modulus */
893 return equal_mp_ints(exp, src->exp)
894 && equal_mp_ints(mod, src->mod);
895 /*
896 return equal_mp_ints(exp, pvar->hosts_state.key_exp)
897 && equal_mp_ints(mod, pvar->hosts_state.key_mod);
898 */
899
900 case KEY_RSA: // SSH2 RSA host public key
901 return key->rsa != NULL && src->rsa != NULL &&
902 BN_cmp(key->rsa->e, src->rsa->e) == 0 &&
903 BN_cmp(key->rsa->n, src->rsa->n) == 0;
904
905 case KEY_DSA: // SSH2 DSA host public key
906 return key->dsa != NULL && src->dsa &&
907 BN_cmp(key->dsa->p, src->dsa->p) == 0 &&
908 BN_cmp(key->dsa->q, src->dsa->q) == 0 &&
909 BN_cmp(key->dsa->g, src->dsa->g) == 0 &&
910 BN_cmp(key->dsa->pub_key, src->dsa->pub_key) == 0;
911
912 case KEY_ECDSA256:
913 case KEY_ECDSA384:
914 case KEY_ECDSA521:
915 if (key->ecdsa == NULL || src->ecdsa == NULL) {
916 return FALSE;
917 }
918 group = EC_KEY_get0_group(key->ecdsa);
919 pa = EC_KEY_get0_public_key(key->ecdsa),
920 pb = EC_KEY_get0_public_key(src->ecdsa);
921 return EC_POINT_cmp(group, pa, pb, NULL) == 0;
922
923 case KEY_ED25519:
924 a = key;
925 b = src;
926 return a->ed25519_pk != NULL && b->ed25519_pk != NULL &&
927 memcmp(a->ed25519_pk, b->ed25519_pk, ED25519_PK_SZ) == 0;
928
929 default:
930 return FALSE;
931 }
932 }
933
934 #if 0
935 // pvar->hosts_state.hostkey ���n���������J����������������������
936 // -1 ... �����^������
937 // 0 ... ����������
938 // 1 ... ������
939 static int match_key(PTInstVar pvar, Key *key)
940 {
941 return HOSTS_compare_public_key(&pvar->hosts_state.hostkey, key);
942 }
943 #endif
944
945 static void hosts_dlg_set_fingerprint(PTInstVar pvar, HWND dlg, digest_algorithm dgst_alg)
946 {
947 char *fp = NULL;
948
949 // fingerprint����������
950 switch (dgst_alg) {
951 case SSH_DIGEST_MD5:
952 fp = key_fingerprint(&pvar->hosts_state.hostkey, SSH_FP_HEX, dgst_alg);
953 if (fp != NULL) {
954 SendMessage(GetDlgItem(dlg, IDC_FINGER_PRINT), WM_SETTEXT, 0, (LPARAM)fp);
955 free(fp);
956 }
957 break;
958 case SSH_DIGEST_SHA256:
959 default:
960 fp = key_fingerprint(&pvar->hosts_state.hostkey, SSH_FP_BASE64, SSH_DIGEST_SHA256);
961 if (fp != NULL) {
962 SendMessage(GetDlgItem(dlg, IDC_FINGER_PRINT), WM_SETTEXT, 0, (LPARAM)fp);
963 free(fp);
964 }
965 break;
966 }
967
968 // �r�W���A����fingerprint���\������
969 fp = key_fingerprint(&pvar->hosts_state.hostkey, SSH_FP_RANDOMART, dgst_alg);
970 if (fp != NULL) {
971 SendMessage(GetDlgItem(dlg, IDC_FP_RANDOMART), WM_SETTEXT, 0, (LPARAM)fp);
972 free(fp);
973 }
974 }
975
976 static void init_hosts_dlg(PTInstVar pvar, HWND dlg)
977 {
978 char buf[1024];
979 char buf2[2048];
980 int i, j;
981 int ch;
982
983 // static text�� # �������z�X�g�����u������
984 GetDlgItemText(dlg, IDC_HOSTWARNING, buf, sizeof(buf));
985 for (i = 0; (ch = buf[i]) != 0 && ch != '#'; i++) {
986 buf2[i] = ch;
987 }
988 strncpy_s(buf2 + i, sizeof(buf2) - i,
989 pvar->hosts_state.prefetched_hostname, _TRUNCATE);
990 j = i + strlen(buf2 + i);
991 for (; buf[i] == '#'; i++) {
992 }
993 strncpy_s(buf2 + j, sizeof(buf2) - j, buf + i, _TRUNCATE);
994
995 SetDlgItemText(dlg, IDC_HOSTWARNING, buf2);
996
997 pvar->hFontFixed = UTIL_get_lang_fixedfont(dlg, pvar->ts->UILanguageFile);
998 if (pvar->hFontFixed != NULL) {
999 SendDlgItemMessage(dlg, IDC_FP_RANDOMART, WM_SETFONT,
1000 (WPARAM)pvar->hFontFixed, MAKELPARAM(TRUE,0));
1001 }
1002
1003 CheckDlgButton(dlg, IDC_FP_HASH_ALG_SHA256, TRUE);
1004 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_SHA256);
1005 }
1006
1007 static int print_mp_int(char *buf, unsigned char *mp)
1008 {
1009 int i = 0, j, k;
1010 BIGNUM *num = BN_new();
1011 int ch;
1012
1013 BN_bin2bn(mp + 2, (get_ushort16_MSBfirst(mp) + 7) / 8, num);
1014
1015 do {
1016 buf[i] = (char) ((BN_div_word(num, 10)) + '0');
1017 i++;
1018 } while (!BN_is_zero(num));
1019
1020 /* we need to reverse the digits */
1021 for (j = 0, k = i - 1; j < k; j++, k--) {
1022 ch = buf[j];
1023 buf[j] = buf[k];
1024 buf[k] = ch;
1025 }
1026
1027 buf[i] = 0;
1028 return i;
1029 }
1030
1031 //
1032 // known_hosts �t�@�C�������������G���g�������������B
1033 //
1034 static char *format_host_key(PTInstVar pvar)
1035 {
1036 int host_len = strlen(pvar->hosts_state.prefetched_hostname);
1037 char *result = NULL;
1038 int index;
1039 ssh_keytype type = pvar->hosts_state.hostkey.type;
1040
1041 switch (type) {
1042 case KEY_RSA1:
1043 {
1044 int result_len = host_len + 50 + 8 +
1045 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.exp) / 3 +
1046 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.mod) / 3;
1047 result = (char *) malloc(result_len);
1048
1049 if (pvar->ssh_state.tcpport == 22) {
1050 strncpy_s(result, result_len, pvar->hosts_state.prefetched_hostname, _TRUNCATE);
1051 index = host_len;
1052 }
1053 else {
1054 _snprintf_s(result, result_len, _TRUNCATE, "[%s]:%d",
1055 pvar->hosts_state.prefetched_hostname,
1056 pvar->ssh_state.tcpport);
1057 index = strlen(result);
1058 }
1059
1060 // ��2����(sizeOfBuffer)���w�������������A�������o�b�t�@�T�C�Y����
1061 // �����������������������C�������B
1062 // �|�[�g������22���O�������AVS2005��debug build�����Aadd_host_key()��
1063 // free(keydata)���A���������u�u���[�N�|�C���g���������������B�q�[�v������������������
1064 // �����������l�����������B�v���������O�����������B
1065 // release build�����������������B
1066 _snprintf_s(result + index, result_len - index, _TRUNCATE,
1067 " %d ", pvar->hosts_state.hostkey.bits);
1068 index += strlen(result + index);
1069 index += print_mp_int(result + index, pvar->hosts_state.hostkey.exp);
1070 result[index] = ' ';
1071 index++;
1072 index += print_mp_int(result + index, pvar->hosts_state.hostkey.mod);
1073 strncpy_s(result + index, result_len - index, " \r\n", _TRUNCATE);
1074
1075 break;
1076 }
1077
1078 case KEY_RSA:
1079 case KEY_DSA:
1080 case KEY_ECDSA256:
1081 case KEY_ECDSA384:
1082 case KEY_ECDSA521:
1083 case KEY_ED25519:
1084 {
1085 Key *key = &pvar->hosts_state.hostkey;
1086 char *blob = NULL;
1087 int blen, uulen, msize;
1088 char *uu = NULL;
1089 int n;
1090
1091 key_to_blob(key, &blob, &blen);
1092 uulen = 2 * blen;
1093 uu = malloc(uulen);
1094 if (uu == NULL) {
1095 goto error;
1096 }
1097 n = uuencode(blob, blen, uu, uulen);
1098 if (n > 0) {
1099 msize = host_len + 50 + uulen;
1100 result = malloc(msize);
1101 if (result == NULL) {
1102 goto error;
1103 }
1104
1105 // setup
1106 if (pvar->ssh_state.tcpport == 22) {
1107 _snprintf_s(result, msize, _TRUNCATE, "%s %s %s\r\n",
1108 pvar->hosts_state.prefetched_hostname,
1109 get_sshname_from_key(key),
1110 uu);
1111 } else {
1112 _snprintf_s(result, msize, _TRUNCATE, "[%s]:%d %s %s\r\n",
1113 pvar->hosts_state.prefetched_hostname,
1114 pvar->ssh_state.tcpport,
1115 get_sshname_from_key(key),
1116 uu);
1117 }
1118 }
1119 error:
1120 if (blob != NULL)
1121 free(blob);
1122 if (uu != NULL)
1123 free(uu);
1124
1125 break;
1126 }
1127
1128 default:
1129 return NULL;
1130
1131 }
1132
1133 return result;
1134 }
1135
1136 static char *format_specified_host_key(Key *key, char *hostname, unsigned short tcpport)
1137 {
1138 int host_len = strlen(hostname);
1139 char *result = NULL;
1140 int index;
1141 ssh_keytype type = key->type;
1142
1143 switch (type) {
1144 case KEY_RSA1:
1145 {
1146 int result_len = host_len + 50 + 8 +
1147 get_ushort16_MSBfirst(key->exp) / 3 +
1148 get_ushort16_MSBfirst(key->mod) / 3;
1149 result = (char *) malloc(result_len);
1150
1151 if (tcpport == 22) {
1152 strncpy_s(result, result_len, hostname, _TRUNCATE);
1153 index = host_len;
1154 }
1155 else {
1156 _snprintf_s(result, result_len, _TRUNCATE, "[%s]:%d",
1157 hostname,
1158 tcpport);
1159 index = strlen(result);
1160 }
1161
1162 _snprintf_s(result + index, result_len - host_len, _TRUNCATE,
1163 " %d ", key->bits);
1164 index += strlen(result + index);
1165 index += print_mp_int(result + index, key->exp);
1166 result[index] = ' ';
1167 index++;
1168 index += print_mp_int(result + index, key->mod);
1169 strncpy_s(result + index, result_len - index, " \r\n", _TRUNCATE);
1170
1171 break;
1172 }
1173
1174 case KEY_RSA:
1175 case KEY_DSA:
1176 case KEY_ECDSA256:
1177 case KEY_ECDSA384:
1178 case KEY_ECDSA521:
1179 case KEY_ED25519:
1180 {
1181 //Key *key = &pvar->hosts_state.hostkey;
1182 char *blob = NULL;
1183 int blen, uulen, msize;
1184 char *uu = NULL;
1185 int n;
1186
1187 key_to_blob(key, &blob, &blen);
1188 uulen = 2 * blen;
1189 uu = malloc(uulen);
1190 if (uu == NULL) {
1191 goto error;
1192 }
1193 n = uuencode(blob, blen, uu, uulen);
1194 if (n > 0) {
1195 msize = host_len + 50 + uulen;
1196 result = malloc(msize);
1197 if (result == NULL) {
1198 goto error;
1199 }
1200
1201 // setup
1202 if (tcpport == 22) {
1203 _snprintf_s(result, msize, _TRUNCATE, "%s %s %s\r\n",
1204 hostname,
1205 get_sshname_from_key(key),
1206 uu);
1207 }
1208 else {
1209 _snprintf_s(result, msize, _TRUNCATE, "[%s]:%d %s %s\r\n",
1210 hostname,
1211 tcpport,
1212 get_sshname_from_key(key),
1213 uu);
1214 }
1215 }
1216 error:
1217 if (blob != NULL)
1218 free(blob);
1219 if (uu != NULL)
1220 free(uu);
1221
1222 break;
1223 }
1224
1225 default:
1226 return NULL;
1227
1228 }
1229
1230 return result;
1231 }
1232
1233 static void add_host_key(PTInstVar pvar)
1234 {
1235 char *name = NULL;
1236
1237 if ( pvar->hosts_state.file_names != NULL)
1238 name = pvar->hosts_state.file_names[0];
1239
1240 if (name == NULL || name[0] == 0) {
1241 UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar,
1242 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
1243 "Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
1244 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1245 } else {
1246 char *keydata = format_host_key(pvar);
1247 int length = strlen(keydata);
1248 int fd;
1249 int amount_written;
1250 int close_result;
1251 char buf[FILENAME_MAX];
1252
1253 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
1254 fd = _open(buf,
1255 _O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY,
1256 _S_IREAD | _S_IWRITE);
1257 if (fd == -1) {
1258 if (errno == EACCES) {
1259 UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar,
1260 "An error occurred while trying to write the host key.\n"
1261 "You do not have permission to write to the known-hosts file.");
1262 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1263 } else {
1264 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1265 "An error occurred while trying to write the host key.\n"
1266 "The host key could not be written.");
1267 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1268 }
1269 return;
1270 }
1271
1272 amount_written = _write(fd, keydata, length);
1273 free(keydata);
1274 close_result = _close(fd);
1275
1276 if (amount_written != length || close_result == -1) {
1277 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1278 "An error occurred while trying to write the host key.\n"
1279 "The host key could not be written.");
1280 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1281 }
1282 }
1283 }
1284
1285 // �w�������L�[�� known_hosts �����������B
1286 void HOSTS_add_host_key(PTInstVar pvar, Key *key)
1287 {
1288 char *name = NULL;
1289 char *hostname;
1290 unsigned short tcpport;
1291
1292 hostname = pvar->ssh_state.hostname;
1293 tcpport = pvar->ssh_state.tcpport;
1294
1295 if (pvar->hosts_state.file_names != NULL)
1296 name = pvar->hosts_state.file_names[0];
1297
1298 if (name == NULL || name[0] == 0) {
1299 UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar,
1300 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
1301 "Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
1302 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1303 }
1304 else {
1305 char *keydata = format_specified_host_key(key, hostname, tcpport);
1306 int length = strlen(keydata);
1307 int fd;
1308 int amount_written;
1309 int close_result;
1310 char buf[FILENAME_MAX];
1311
1312 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
1313 fd = _open(buf,
1314 _O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY,
1315 _S_IREAD | _S_IWRITE);
1316 if (fd == -1) {
1317 if (errno == EACCES) {
1318 UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar,
1319 "An error occurred while trying to write the host key.\n"
1320 "You do not have permission to write to the known-hosts file.");
1321 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1322 }
1323 else {
1324 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1325 "An error occurred while trying to write the host key.\n"
1326 "The host key could not be written.");
1327 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1328 }
1329 return;
1330 }
1331
1332 amount_written = _write(fd, keydata, length);
1333 free(keydata);
1334 close_result = _close(fd);
1335
1336 if (amount_written != length || close_result == -1) {
1337 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1338 "An error occurred while trying to write the host key.\n"
1339 "The host key could not be written.");
1340 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1341 }
1342 }
1343 }
1344
1345 //
1346 // �����z�X�g�����e���������L�[����������
1347 // add_host_key ����������������
1348 //
1349 static void delete_different_key(PTInstVar pvar)
1350 {
1351 char *name = pvar->hosts_state.file_names[0];
1352
1353 if (name == NULL || name[0] == 0) {
1354 UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar,
1355 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
1356 "Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
1357 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1358 }
1359 else {
1360 Key key; // known_hosts���o�^������������
1361 int length;
1362 char filename[MAX_PATH];
1363 char tmp[L_tmpnam];
1364 int fd;
1365 int amount_written = 0;
1366 int close_result;
1367 int data_index = 0;
1368 char buf[FILENAME_MAX];
1369
1370 // �������������t�@�C�����J��
1371 _getcwd(filename, sizeof(filename));
1372 tmpnam_s(tmp,sizeof(tmp));
1373 strcat_s(filename, sizeof(filename), tmp);
1374 fd = _open(filename,
1375 _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY | _O_TRUNC,
1376 _S_IREAD | _S_IWRITE);
1377
1378 if (fd == -1) {
1379 if (errno == EACCES) {
1380 UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar,
1381 "An error occurred while trying to write the host key.\n"
1382 "You do not have permission to write to the known-hosts file.");
1383 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1384 } else {
1385 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1386 "An error occurred while trying to write the host key.\n"
1387 "The host key could not be written.");
1388 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1389 }
1390 return;
1391 }
1392
1393 // �t�@�C��������������
1394 memset(&key, 0, sizeof(key));
1395 begin_read_host_files(pvar, 0);
1396 do {
1397 int host_index = 0;
1398 int matched = 0;
1399 int keybits = 0;
1400 char *data;
1401 int do_write = 0;
1402 length = amount_written = 0;
1403
1404 if (!read_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, 0, 1, &key)) {
1405 break;
1406 }
1407
1408 if (data_index == pvar->hosts_state.file_data_index) {
1409 // index ���i������ == ��������������
1410 break;
1411 }
1412
1413 data = pvar->hosts_state.file_data + data_index;
1414 host_index = eat_spaces(data);
1415
1416 if (data[host_index] == '#') {
1417 do_write = 1;
1418 }
1419 else {
1420 // �z�X�g������
1421 host_index--;
1422 do {
1423 int negated;
1424 int bracketed;
1425 char *end_bracket;
1426 int host_matched = 0;
1427 unsigned short keyfile_port = 22;
1428
1429 host_index++;
1430 negated = data[host_index] == '!';
1431
1432 if (negated) {
1433 host_index++;
1434 bracketed = data[host_index] == '[';
1435 if (bracketed) {
1436 end_bracket = strstr(data + host_index + 1, "]:");
1437 if (end_bracket != NULL) {
1438 *end_bracket = ' ';
1439 host_index++;
1440 }
1441 }
1442 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1443 if (bracketed && end_bracket != NULL) {
1444 *end_bracket = ']';
1445 keyfile_port = atoi(end_bracket + 2);
1446 }
1447 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1448 matched = 0;
1449 // �����o�[�W�����`�F�b�N�������� host_index ���i��������������
1450 host_index--;
1451 do {
1452 host_index++;
1453 host_index += eat_to_end_of_pattern(data + host_index);
1454 } while (data[host_index] == ',');
1455 break;
1456 }
1457 }
1458 else {
1459 bracketed = data[host_index] == '[';
1460 if (bracketed) {
1461 end_bracket = strstr(data + host_index + 1, "]:");
1462 if (end_bracket != NULL) {
1463 *end_bracket = ' ';
1464 host_index++;
1465 }
1466 }
1467 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1468 if (bracketed && end_bracket != NULL) {
1469 *end_bracket = ']';
1470 keyfile_port = atoi(end_bracket + 2);
1471 }
1472 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1473 matched = 1;
1474 }
1475 }
1476 host_index += eat_to_end_of_pattern(data + host_index);
1477 } while (data[host_index] == ',');
1478
1479 // �z�X�g������������
1480 if (!matched) {
1481 do_write = 1;
1482 }
1483 // �z�X�g��������
1484 else {
1485 // �����`�������� or ���v�����L�[
1486 if (HOSTS_compare_public_key(&pvar->hosts_state.hostkey, &key) != 0) {
1487 do_write = 1;
1488 }
1489 // �����`�������������v�������L�[���X�L�b�v������
1490 }
1491 }
1492
1493 // ������������
1494 if (do_write) {
1495 length = pvar->hosts_state.file_data_index - data_index;
1496 amount_written =
1497 _write(fd, pvar->hosts_state.file_data + data_index,
1498 length);
1499
1500 if (amount_written != length) {
1501 goto error1;
1502 }
1503 }
1504 data_index = pvar->hosts_state.file_data_index;
1505 } while (1); // ������������
1506
1507 error1:
1508 close_result = _close(fd);
1509 if (amount_written != length || close_result == -1) {
1510 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1511 "An error occurred while trying to write the host key.\n"
1512 "The host key could not be written.");
1513 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1514 goto error2;
1515 }
1516
1517 // �������������t�@�C���������l�[��
1518 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
1519 _unlink(buf);
1520 rename(filename, buf);
1521
1522 error2:
1523 _unlink(filename);
1524
1525 finish_read_host_files(pvar, 0);
1526
1527 // ���������������������������B
1528 key_init(&key);
1529 }
1530 }
1531
1532
1533 void HOSTS_delete_all_hostkeys(PTInstVar pvar)
1534 {
1535 char *name = pvar->hosts_state.file_names[0];
1536 char *hostname;
1537 unsigned short tcpport;
1538
1539 hostname = pvar->ssh_state.hostname;
1540 tcpport = pvar->ssh_state.tcpport;
1541
1542 if (name == NULL || name[0] == 0) {
1543 UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar,
1544 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
1545 "Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
1546 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1547 }
1548 else {
1549 Key key; // known_hosts���o�^������������
1550 int length;
1551 char filename[MAX_PATH];
1552 char tmp[L_tmpnam];
1553 int fd;
1554 int amount_written = 0;
1555 int close_result;
1556 int data_index = 0;
1557 char buf[FILENAME_MAX];
1558
1559 // �������������t�@�C�����J��
1560 _getcwd(filename, sizeof(filename));
1561 tmpnam_s(tmp, sizeof(tmp));
1562 strcat_s(filename, sizeof(filename), tmp);
1563 fd = _open(filename,
1564 _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY | _O_TRUNC,
1565 _S_IREAD | _S_IWRITE);
1566
1567 if (fd == -1) {
1568 if (errno == EACCES) {
1569 UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar,
1570 "An error occurred while trying to write the host key.\n"
1571 "You do not have permission to write to the known-hosts file.");
1572 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1573 }
1574 else {
1575 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1576 "An error occurred while trying to write the host key.\n"
1577 "The host key could not be written.");
1578 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1579 }
1580 return;
1581 }
1582
1583 // �t�@�C��������������
1584 memset(&key, 0, sizeof(key));
1585 begin_read_host_files(pvar, 0);
1586 do {
1587 int host_index = 0;
1588 int matched = 0;
1589 int keybits = 0;
1590 char *data;
1591 int do_write = 0;
1592 length = amount_written = 0;
1593
1594 if (!read_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, 0, 1, &key)) {
1595 break;
1596 }
1597
1598 if (data_index == pvar->hosts_state.file_data_index) {
1599 // index ���i������ == ��������������
1600 break;
1601 }
1602
1603 data = pvar->hosts_state.file_data + data_index;
1604 host_index = eat_spaces(data);
1605
1606 if (data[host_index] == '#') {
1607 do_write = 1;
1608 }
1609 else {
1610 // �z�X�g������
1611 host_index--;
1612 do {
1613 int negated;
1614 int bracketed;
1615 char *end_bracket;
1616 int host_matched = 0;
1617 unsigned short keyfile_port = 22;
1618
1619 host_index++;
1620 negated = data[host_index] == '!';
1621
1622 if (negated) {
1623 host_index++;
1624 bracketed = data[host_index] == '[';
1625 if (bracketed) {
1626 end_bracket = strstr(data + host_index + 1, "]:");
1627 if (end_bracket != NULL) {
1628 *end_bracket = ' ';
1629 host_index++;
1630 }
1631 }
1632 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1633 if (bracketed && end_bracket != NULL) {
1634 *end_bracket = ']';
1635 keyfile_port = atoi(end_bracket + 2);
1636 }
1637 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1638 matched = 0;
1639 // �����o�[�W�����`�F�b�N�������� host_index ���i��������������
1640 host_index--;
1641 do {
1642 host_index++;
1643 host_index += eat_to_end_of_pattern(data + host_index);
1644 } while (data[host_index] == ',');
1645 break;
1646 }
1647 }
1648 else {
1649 bracketed = data[host_index] == '[';
1650 if (bracketed) {
1651 end_bracket = strstr(data + host_index + 1, "]:");
1652 if (end_bracket != NULL) {
1653 *end_bracket = ' ';
1654 host_index++;
1655 }
1656 }
1657 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1658 if (bracketed && end_bracket != NULL) {
1659 *end_bracket = ']';
1660 keyfile_port = atoi(end_bracket + 2);
1661 }
1662 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1663 matched = 1;
1664 }
1665 }
1666 host_index += eat_to_end_of_pattern(data + host_index);
1667 } while (data[host_index] == ',');
1668
1669 // �z�X�g������������
1670 if (!matched) {
1671 do_write = 1;
1672 }
1673 // �z�X�g��������
1674 else {
1675 // ���������������������B
1676
1677 }
1678 }
1679
1680 // ������������
1681 if (do_write) {
1682 length = pvar->hosts_state.file_data_index - data_index;
1683 amount_written =
1684 _write(fd, pvar->hosts_state.file_data + data_index,
1685 length);
1686
1687 if (amount_written != length) {
1688 goto error1;
1689 }
1690 }
1691 data_index = pvar->hosts_state.file_data_index;
1692 } while (1); // ������������
1693
1694 error1:
1695 close_result = _close(fd);
1696 if (amount_written != length || close_result == -1) {
1697 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1698 "An error occurred while trying to write the host key.\n"
1699 "The host key could not be written.");
1700 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1701 goto error2;
1702 }
1703
1704 // �������������t�@�C���������l�[��
1705 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
1706 _unlink(buf);
1707 rename(filename, buf);
1708
1709 error2:
1710 _unlink(filename);
1711
1712 finish_read_host_files(pvar, 0);
1713
1714 // ���������������������������B
1715 key_init(&key);
1716 }
1717 }
1718
1719
1720 //
1721 // Unknown host���z�X�g���J���� known_hosts �t�@�C����������������������
1722 // ���[�U���m�F�������B
1723 // TODO: finger print���\�����s���B
1724 // (2006.3.25 yutaka)
1725 //
1726 static INT_PTR CALLBACK hosts_add_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1727 LPARAM lParam)
1728 {
1729 const static DlgTextInfo text_info[] = {
1730 { 0, "DLG_UNKNOWNHOST_TITLE" },
1731 { IDC_HOSTWARNING, "DLG_UNKNOWNHOST_WARNING" },
1732 { IDC_HOSTWARNING2, "DLG_UNKNOWNHOST_WARNING2" },
1733 { IDC_HOSTFINGERPRINT, "DLG_UNKNOWNHOST_FINGERPRINT" },
1734 { IDC_FP_HASH_ALG, "DLG_UNKNOWNHOST_FP_HASH_ALGORITHM" },
1735 { IDC_ADDTOKNOWNHOSTS, "DLG_UNKNOWNHOST_ADD" },
1736 { IDC_CONTINUE, "BTN_CONTINUE" },
1737 { IDCANCEL, "BTN_DISCONNECT" },
1738 };
1739 PTInstVar pvar;
1740
1741 switch (msg) {
1742 case WM_INITDIALOG:
1743 pvar = (PTInstVar) lParam;
1744 pvar->hosts_state.hosts_dialog = dlg;
1745 SetWindowLongPtr(dlg, DWLP_USER, lParam);
1746
1747 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
1748 SetI18DlgStrs("TTSSH", dlg, text_info, _countof(text_info), pvar->ts->UILanguageFile);
1749
1750 switch (pvar->dns_key_check) {
1751 case DNS_VERIFY_NOTFOUND:
1752 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_NOTFOUND", pvar, "No host key fingerprint found in DNS.");
1753 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1754 break;
1755 case DNS_VERIFY_MATCH:
1756 case DNS_VERIFY_AUTH_MATCH:
1757 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MATCH", pvar, "Matching host key fingerprint found in DNS.");
1758 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1759 break;
1760 case DNS_VERIFY_MISMATCH:
1761 case DNS_VERIFY_AUTH_MISMATCH:
1762 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MISMATCH", pvar, "Mismatching host key fingerprint found in DNS.");
1763 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1764 break;
1765 case DNS_VERIFY_DIFFERENTTYPE:
1766 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
1767 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_DIFFTYPE", pvar, "Mismatching host key type found in DNS.");
1768 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1769 break;
1770 }
1771
1772 switch (pvar->dns_key_check) {
1773 case DNS_VERIFY_MATCH:
1774 case DNS_VERIFY_MISMATCH:
1775 case DNS_VERIFY_DIFFERENTTYPE:
1776 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_NG", pvar, "Found insecure fingerprint in DNS.");
1777 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
1778 break;
1779 case DNS_VERIFY_AUTH_MATCH:
1780 case DNS_VERIFY_AUTH_MISMATCH:
1781 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
1782 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_OK", pvar, "Found secure fingerprint in DNS.");
1783 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
1784 break;
1785 }
1786
1787 init_hosts_dlg(pvar, dlg);
1788 // add host check box���`�F�b�N���f�t�H���g������������
1789 SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
1790
1791 CenterWindow(dlg, GetParent(dlg));
1792
1793 return TRUE; /* because we do not set the focus */
1794
1795 case WM_COMMAND:
1796 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
1797
1798 switch (LOWORD(wParam)) {
1799 case IDC_CONTINUE:
1800 // �F�������T�[�o�������f�������������A�L�����Z�������������B(2014.3.31 yutaka)
1801 if (!pvar->cv->Ready) {
1802 goto canceled;
1803 }
1804
1805 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1806 add_host_key(pvar);
1807 }
1808
1809 /*
1810 * known_hosts�_�C�A���O���������������~��������
1811 * SSH�T�[�o�����l�S�V�G�[�V���������J�������B
1812 */
1813 HOSTS_resume_session_after_known_hosts(pvar);
1814
1815 pvar->hosts_state.hosts_dialog = NULL;
1816
1817 EndDialog(dlg, 1);
1818 return TRUE;
1819
1820 case IDCANCEL: /* kill the connection */
1821 canceled:
1822 /*
1823 * known_hosts���L�����Z�����������A���J�p�����\�[�X���j�����������B
1824 */
1825 HOSTS_cancel_session_after_known_hosts(pvar);
1826
1827 pvar->hosts_state.hosts_dialog = NULL;
1828 notify_closed_connection(pvar, "authentication cancelled");
1829 EndDialog(dlg, 0);
1830 return TRUE;
1831
1832 case IDCLOSE:
1833 /*
1834 * known_hosts�����T�[�o�������l�b�g���[�N���f�����������A
1835 * �_�C�A���O�������������B
1836 */
1837 HOSTS_cancel_session_after_known_hosts(pvar);
1838
1839 pvar->hosts_state.hosts_dialog = NULL;
1840 EndDialog(dlg, 0);
1841 return TRUE;
1842
1843 case IDC_FP_HASH_ALG_MD5:
1844 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_MD5);
1845 return TRUE;
1846
1847 case IDC_FP_HASH_ALG_SHA256:
1848 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_SHA256);
1849 return TRUE;
1850
1851 default:
1852 return FALSE;
1853 }
1854
1855 case WM_DPICHANGED:
1856 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
1857 if (pvar->hFontFixed != NULL) {
1858 DeleteObject(pvar->hFontFixed);
1859 }
1860 pvar->hFontFixed = UTIL_get_lang_fixedfont(dlg, pvar->ts->UILanguageFile);
1861 if (pvar->hFontFixed != NULL) {
1862 SendDlgItemMessage(dlg, IDC_FP_RANDOMART, WM_SETFONT,
1863 (WPARAM)pvar->hFontFixed, MAKELPARAM(TRUE,0));
1864 }
1865 return FALSE;
1866
1867 case WM_DESTROY:
1868 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
1869 if (pvar->hFontFixed != NULL) {
1870 DeleteObject(pvar->hFontFixed);
1871 pvar->hFontFixed = NULL;
1872 }
1873 return FALSE;
1874
1875 default:
1876 return FALSE;
1877 }
1878 }
1879
1880 //
1881 // �u�����������m�F�_�C�A���O������
1882 //
1883 static INT_PTR CALLBACK hosts_replace_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1884 LPARAM lParam)
1885 {
1886 const static DlgTextInfo text_info[] = {
1887 { 0, "DLG_UNKNOWNHOST_TITLE" },
1888 { IDC_HOSTWARNING, "DLG_DIFFERENTKEY_WARNING" },
1889 { IDC_HOSTWARNING2, "DLG_DIFFERENTKEY_WARNING2" },
1890 { IDC_HOSTFINGERPRINT, "DLG_DIFFERENTKEY_FINGERPRINT" },
1891 { IDC_FP_HASH_ALG, "DLG_DIFFERENTKEY_FP_HASH_ALGORITHM" },
1892 { IDC_ADDTOKNOWNHOSTS, "DLG_DIFFERENTKEY_REPLACE" },
1893 { IDC_CONTINUE, "BTN_CONTINUE" },
1894 { IDCANCEL, "BTN_DISCONNECT" },
1895 };
1896 PTInstVar pvar;
1897
1898 switch (msg) {
1899 case WM_INITDIALOG:
1900 pvar = (PTInstVar) lParam;
1901 pvar->hosts_state.hosts_dialog = dlg;
1902 SetWindowLongPtr(dlg, DWLP_USER, lParam);
1903
1904 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
1905 SetI18DlgStrs("TTSSH", dlg, text_info, _countof(text_info), pvar->ts->UILanguageFile);
1906
1907 switch (pvar->dns_key_check) {
1908 case DNS_VERIFY_NOTFOUND:
1909 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_NOTFOUND", pvar, "No host key fingerprint found in DNS.");
1910 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1911 break;
1912 case DNS_VERIFY_MATCH:
1913 case DNS_VERIFY_AUTH_MATCH:
1914 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MATCH", pvar, "Matching host key fingerprint found in DNS.");
1915 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1916 break;
1917 case DNS_VERIFY_MISMATCH:
1918 case DNS_VERIFY_AUTH_MISMATCH:
1919 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MISMATCH", pvar, "Mismatching host key fingerprint found in DNS.");
1920 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1921 break;
1922 case DNS_VERIFY_DIFFERENTTYPE:
1923 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
1924 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_DIFFTYPE", pvar, "Mismatching host key type found in DNS.");
1925 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1926 break;
1927 }
1928
1929 switch (pvar->dns_key_check) {
1930 case DNS_VERIFY_MATCH:
1931 case DNS_VERIFY_MISMATCH:
1932 case DNS_VERIFY_DIFFERENTTYPE:
1933 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_NG", pvar, "Found insecure fingerprint in DNS.");
1934 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
1935 break;
1936 case DNS_VERIFY_AUTH_MATCH:
1937 case DNS_VERIFY_AUTH_MISMATCH:
1938 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
1939 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_OK", pvar, "Found secure fingerprint in DNS.");
1940 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
1941 break;
1942 }
1943
1944 init_hosts_dlg(pvar, dlg);
1945 CenterWindow(dlg, GetParent(dlg));
1946 // �f�t�H���g���`�F�b�N����������
1947 return TRUE; /* because we do not set the focus */
1948
1949 case WM_COMMAND:
1950 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
1951
1952 switch (LOWORD(wParam)) {
1953 case IDC_CONTINUE:
1954 // �F�������T�[�o�������f�������������A�L�����Z�������������B(2014.3.31 yutaka)
1955 if (!pvar->cv->Ready) {
1956 goto canceled;
1957 }
1958
1959 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1960 add_host_key(pvar);
1961 delete_different_key(pvar);
1962 }
1963
1964 /*
1965 * known_hosts�_�C�A���O���������������~��������
1966 * SSH�T�[�o�����l�S�V�G�[�V���������J�������B
1967 */
1968 HOSTS_resume_session_after_known_hosts(pvar);
1969
1970 pvar->hosts_state.hosts_dialog = NULL;
1971
1972 EndDialog(dlg, 1);
1973 return TRUE;
1974
1975 case IDCANCEL: /* kill the connection */
1976 canceled:
1977 /*
1978 * known_hosts���L�����Z�����������A���J�p�����\�[�X���j�����������B
1979 */
1980 HOSTS_cancel_session_after_known_hosts(pvar);
1981
1982 pvar->hosts_state.hosts_dialog = NULL;
1983 notify_closed_connection(pvar, "authentication cancelled");
1984 EndDialog(dlg, 0);
1985 return TRUE;
1986
1987 case IDCLOSE:
1988 /*
1989 * known_hosts�����T�[�o�������l�b�g���[�N���f�����������A
1990 * �_�C�A���O�������������B
1991 */
1992 HOSTS_cancel_session_after_known_hosts(pvar);
1993
1994 pvar->hosts_state.hosts_dialog = NULL;
1995 EndDialog(dlg, 0);
1996 return TRUE;
1997
1998 case IDC_FP_HASH_ALG_MD5:
1999 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_MD5);
2000 return TRUE;
2001
2002 case IDC_FP_HASH_ALG_SHA256:
2003 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_SHA256);
2004 return TRUE;
2005
2006 default:
2007 return FALSE;
2008 }
2009
2010 case WM_DPICHANGED:
2011 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2012 if (pvar->hFontFixed != NULL) {
2013 DeleteObject(pvar->hFontFixed);
2014 }
2015 pvar->hFontFixed = UTIL_get_lang_fixedfont(dlg, pvar->ts->UILanguageFile);
2016 if (pvar->hFontFixed != NULL) {
2017 SendDlgItemMessage(dlg, IDC_FP_RANDOMART, WM_SETFONT,
2018 (WPARAM)pvar->hFontFixed, MAKELPARAM(TRUE,0));
2019 }
2020 return FALSE;
2021
2022 case WM_DESTROY:
2023 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2024 if (pvar->hFontFixed != NULL) {
2025 DeleteObject(pvar->hFontFixed);
2026 pvar->hFontFixed = NULL;
2027 }
2028 return FALSE;
2029
2030 default:
2031 return FALSE;
2032 }
2033 }
2034
2035 //
2036 // �����z�X�g�����`�����������������m�F�_�C�A���O������
2037 //
2038 static INT_PTR CALLBACK hosts_add2_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
2039 LPARAM lParam)
2040 {
2041 const static DlgTextInfo text_info[] = {
2042 { 0, "DLG_DIFFERENTTYPEKEY_TITLE" },
2043 { IDC_HOSTWARNING, "DLG_DIFFERENTTYPEKEY_WARNING" },
2044 { IDC_HOSTWARNING2, "DLG_DIFFERENTTYPEKEY_WARNING2" },
2045 { IDC_HOSTFINGERPRINT, "DLG_DIFFERENTTYPEKEY_FINGERPRINT" },
2046 { IDC_FP_HASH_ALG, "DLG_DIFFERENTTYPEKEY_FP_HASH_ALGORITHM" },
2047 { IDC_ADDTOKNOWNHOSTS, "DLG_DIFFERENTTYPEKEY_ADD" },
2048 { IDC_CONTINUE, "BTN_CONTINUE" },
2049 { IDCANCEL, "BTN_DISCONNECT" },
2050 };
2051 PTInstVar pvar;
2052
2053 switch (msg) {
2054 case WM_INITDIALOG:
2055 pvar = (PTInstVar) lParam;
2056 pvar->hosts_state.hosts_dialog = dlg;
2057 SetWindowLongPtr(dlg, DWLP_USER, lParam);
2058
2059 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
2060 SetI18DlgStrs("TTSSH", dlg, text_info, _countof(text_info), pvar->ts->UILanguageFile);
2061
2062 switch (pvar->dns_key_check) {
2063 case DNS_VERIFY_NOTFOUND:
2064 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_NOTFOUND", pvar, "No host key fingerprint found in DNS.");
2065 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
2066 break;
2067 case DNS_VERIFY_MATCH:
2068 case DNS_VERIFY_AUTH_MATCH:
2069 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MATCH", pvar, "Matching host key fingerprint found in DNS.");
2070 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
2071 break;
2072 case DNS_VERIFY_MISMATCH:
2073 case DNS_VERIFY_AUTH_MISMATCH:
2074 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MISMATCH", pvar, "Mismatching host key fingerprint found in DNS.");
2075 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
2076 break;
2077 case DNS_VERIFY_DIFFERENTTYPE:
2078 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
2079 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_DIFFTYPE", pvar, "Mismatching host key type found in DNS.");
2080 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
2081 break;
2082 }
2083
2084 switch (pvar->dns_key_check) {
2085 case DNS_VERIFY_MATCH:
2086 case DNS_VERIFY_MISMATCH:
2087 case DNS_VERIFY_DIFFERENTTYPE:
2088 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_NG", pvar, "Found insecure fingerprint in DNS.");
2089 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
2090 break;
2091 case DNS_VERIFY_AUTH_MATCH:
2092 case DNS_VERIFY_AUTH_MISMATCH:
2093 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
2094 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_OK", pvar, "Found secure fingerprint in DNS.");
2095 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
2096 break;
2097 }
2098
2099 init_hosts_dlg(pvar, dlg);
2100 CenterWindow(dlg, GetParent(dlg));
2101 // add host check box ���f�t�H���g�� off ������
2102 // SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
2103
2104 return TRUE; /* because we do not set the focus */
2105
2106 case WM_COMMAND:
2107 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2108
2109 switch (LOWORD(wParam)) {
2110 case IDC_CONTINUE:
2111 // �F�������T�[�o�������f�������������A�L�����Z�������������B(2014.3.31 yutaka)
2112 if (!pvar->cv->Ready) {
2113 goto canceled;
2114 }
2115
2116 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
2117 add_host_key(pvar);
2118 }
2119
2120 /*
2121 * known_hosts�_�C�A���O���������������~��������
2122 * SSH�T�[�o�����l�S�V�G�[�V���������J�������B
2123 */
2124 HOSTS_resume_session_after_known_hosts(pvar);
2125
2126 pvar->hosts_state.hosts_dialog = NULL;
2127
2128 EndDialog(dlg, 1);
2129 return TRUE;
2130
2131 case IDCANCEL: /* kill the connection */
2132 canceled:
2133 /*
2134 * known_hosts���L�����Z�����������A���J�p�����\�[�X���j�����������B
2135 */
2136 HOSTS_cancel_session_after_known_hosts(pvar);
2137
2138 pvar->hosts_state.hosts_dialog = NULL;
2139 notify_closed_connection(pvar, "authentication cancelled");
2140 EndDialog(dlg, 0);
2141 return TRUE;
2142
2143 case IDCLOSE:
2144 /*
2145 * known_hosts�����T�[�o�������l�b�g���[�N���f�����������A
2146 * �_�C�A���O�������������B
2147 */
2148 HOSTS_cancel_session_after_known_hosts(pvar);
2149
2150 pvar->hosts_state.hosts_dialog = NULL;
2151 EndDialog(dlg, 0);
2152 return TRUE;
2153
2154 case IDC_FP_HASH_ALG_MD5:
2155 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_MD5);
2156 return TRUE;
2157
2158 case IDC_FP_HASH_ALG_SHA256:
2159 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_SHA256);
2160 return TRUE;
2161
2162 default:
2163 return FALSE;
2164 }
2165
2166 case WM_DPICHANGED:
2167 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2168 if (pvar->hFontFixed != NULL) {
2169 DeleteObject(pvar->hFontFixed);
2170 }
2171 pvar->hFontFixed = UTIL_get_lang_fixedfont(dlg, pvar->ts->UILanguageFile);
2172 if (pvar->hFontFixed != NULL) {
2173 SendDlgItemMessage(dlg, IDC_FP_RANDOMART, WM_SETFONT,
2174 (WPARAM)pvar->hFontFixed, MAKELPARAM(TRUE,0));
2175 }
2176 return FALSE;
2177
2178 case WM_DESTROY:
2179 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2180 if (pvar->hFontFixed != NULL) {
2181 DeleteObject(pvar->hFontFixed);
2182 pvar->hFontFixed = NULL;
2183 }
2184 return FALSE;
2185
2186 default:
2187 return FALSE;
2188 }
2189 }
2190
2191 void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar)
2192 {
2193 if (pvar->hosts_state.hosts_dialog == NULL) {
2194 /* known_hosts�������������AID_SSHASYNCMESSAGEBOX ���g����
2195 * MessageBox ���\�������������A�I�[�i�[����(no owner)�����������A
2196 * MessageBox ��Tera Term�������B���������������B
2197 * ���������� GetActiveWindow() �������o�����Aknown_hosts�_�C�A���O��
2198 * �I�[�i�[�� MessageBox ���������ATera Term�������B�����������B
2199 * �������Aknown_hosts�_�C�A���O���I�[�i�[������ Tera Term ���w������
2200 * �����������B
2201 */
2202 HWND cur_active = NULL;
2203
2204 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST),
2205 cur_active != NULL ? cur_active : wnd,
2206 hosts_add_dlg_proc, (LPARAM) pvar);
2207 }
2208 }
2209
2210 void HOSTS_do_different_key_dialog(HWND wnd, PTInstVar pvar)
2211 {
2212 if (pvar->hosts_state.hosts_dialog == NULL) {
2213 /* known_hosts�������������AID_SSHASYNCMESSAGEBOX ���g����
2214 * MessageBox ���\�������������A�I�[�i�[����(no owner)�����������A
2215 * MessageBox ��Tera Term�������B���������������B
2216 * ���������� GetActiveWindow() �������o�����Aknown_hosts�_�C�A���O��
2217 * �I�[�i�[�� MessageBox ���������ATera Term�������B�����������B
2218 * �������Aknown_hosts�_�C�A���O���I�[�i�[������ Tera Term ���w������
2219 * �����������B
2220 */
2221 HWND cur_active = NULL;
2222
2223 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTKEY),
2224 cur_active != NULL ? cur_active : wnd,
2225 hosts_replace_dlg_proc, (LPARAM) pvar);
2226 }
2227 }
2228
2229 void HOSTS_do_different_type_key_dialog(HWND wnd, PTInstVar pvar)
2230 {
2231 if (pvar->hosts_state.hosts_dialog == NULL) {
2232 /* known_hosts�������������AID_SSHASYNCMESSAGEBOX ���g����
2233 * MessageBox ���\�������������A�I�[�i�[����(no owner)�����������A
2234 * MessageBox ��Tera Term�������B���������������B
2235 * ���������� GetActiveWindow() �������o�����Aknown_hosts�_�C�A���O��
2236 * �I�[�i�[�� MessageBox ���������ATera Term�������B�����������B
2237 * �������Aknown_hosts�_�C�A���O���I�[�i�[������ Tera Term ���w������
2238 * �����������B
2239 */
2240 HWND cur_active = NULL;
2241
2242 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTTYPEKEY),
2243 cur_active != NULL ? cur_active : wnd,
2244 hosts_add2_dlg_proc, (LPARAM) pvar);
2245 }
2246 }
2247
2248 /*
2249 * �T�[�o�����������������z�X�g���J�������������`�F�b�N���A
2250 * �K�v�������� known_hosts �_�C�A���O�������o���B
2251 *
2252 * hostname: ���������z�X�g��
2253 * tcpport: �������|�[�g����
2254 * key: �T�[�o���������J��
2255 *
2256 * return:
2257 * TRUE: known_hosts�_�C�A���O�������o�����s�v
2258 * FALSE: known_hosts�_�C�A���O�������o����
2259 *
2260 */
2261 BOOL HOSTS_check_host_key(PTInstVar pvar, char *hostname, unsigned short tcpport, Key *key)
2262 {
2263 int found_different_key = 0, found_different_type_key = 0;
2264 Key key2; // known_hosts���o�^������������
2265 DWORD id;
2266
2267 pvar->dns_key_check = DNS_VERIFY_NONE;
2268
2269 // ������ known_hosts �t�@�C�������z�X�g���J�����������������������A���������r�����B
2270 if (pvar->hosts_state.prefetched_hostname != NULL
2271 && _stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0
2272 && HOSTS_compare_public_key(&pvar->hosts_state.hostkey, key) == 1) {
2273
2274 // ���������������B
2275 return TRUE;
2276 }
2277
2278 // �������������������������A�������_���t�@�C��������������
2279 memset(&key2, 0, sizeof(key2));
2280 if (begin_read_host_files(pvar, 0)) {
2281 do {
2282 if (!read_host_key(pvar, hostname, tcpport, 0, 0, &key2)) {
2283 break;
2284 }
2285
2286 if (key2.type != KEY_UNSPEC) {
2287 int match = HOSTS_compare_public_key(&key2, key);
2288 if (match == 1) {
2289 finish_read_host_files(pvar, 0);
2290 // ���������G���g�����Q�������A���v�����L�[�������������������B
2291 // About TTSSH �_�C�A���O�����\�����������A�������������������B
2292 key_copy(&pvar->hosts_state.hostkey, key);
2293
2294 return TRUE;
2295 }
2296 else if (match == 0) {
2297 // �L�[�� known_hosts ���������������A�L�[�����e���������B
2298 found_different_key = 1;
2299 }
2300 else {
2301 // �L�[���`������������
2302 found_different_type_key = 1;
2303 }
2304 }
2305 } while (key2.type != KEY_UNSPEC); // �L�[�����������������������[�v����
2306
2307 key_init(&key2);
2308 finish_read_host_files(pvar, 0);
2309 }
2310
2311 // known_hosts �������������L�[���������t�@�C�������������������A�������������������B
2312 key_copy(&pvar->hosts_state.hostkey, key);
2313
2314 free(pvar->hosts_state.prefetched_hostname);
2315 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
2316
2317 // "/nosecuritywarning"���w�����������������A�_�C�A���O���\���������� return success �����B
2318 if (pvar->nocheck_known_hosts == TRUE) {
2319 // ���������������B
2320 return TRUE;
2321 }
2322
2323 if (pvar->settings.VerifyHostKeyDNS && !is_numeric_hostname(hostname)) {
2324 pvar->dns_key_check = verify_hostkey_dns(pvar, hostname, key);
2325 }
2326
2327 // known_hosts�_�C�A���O�������I���\�������A�������_�����������[�U���m�F
2328 // �������K�v�����������A�����R�[�������X�����B
2329 // ����������known_hosts���m�F�����������A�T�[�o�����[�U���������������������������������B
2330 // (2007.10.1 yutaka)
2331 /*
2332 * known_hosts�_�C�A���O�����������\�����������������������B
2333 * known_hosts�_�C�A���O���\�������������������A�T�[�o�������f���s�����A
2334 * TTXCloseTCP�������o�����ATTSSH�����\�[�X�������������������B
2335 * SSH�n���h����������known_hosts�_�C�A���O���o�����~���������������A
2336 * �������J�����s���A�N�Z�X���������B
2337 * (2019.9.3 yutaka)
2338 */
2339 if (found_different_key) {
2340 // TTXProcessCommand ���� HOSTS_do_different_key_dialog() �������o���B
2341 id = ID_SSHDIFFERENTKEY;
2342 }
2343 else if (found_different_type_key) {
2344 // TTXProcessCommand ���� HOSTS_do_different_type_key_dialog() �������o���B
2345 id = ID_SSHDIFFERENT_TYPE_KEY;
2346 }
2347 else {
2348 // TTXProcessCommand ���� HOSTS_do_unknown_host_dialog() �������o���B
2349 id = ID_SSHUNKNOWNHOST;
2350 }
2351
2352 PostMessage(pvar->NotificationWindow, WM_COMMAND, id, 0);
2353
2354 logprintf(LOG_LEVEL_INFO, "Calling known_hosts dialog...(%s)",
2355 id == ID_SSHDIFFERENTKEY ? "SSHDIFFERENTKEY" :
2356 id == ID_SSHDIFFERENT_TYPE_KEY ? "SSHDIFFERENT_TYPE_KEY" : "SSHUNKNOWNHOST"
2357 );
2358
2359 return FALSE;
2360 }
2361
2362 /*
2363 * known_hosts�_�C�A���O�����[�U���F���ASSH�T�[�o�����l�S�V�G�[�V���������J�����B
2364 */
2365 BOOL HOSTS_resume_session_after_known_hosts(PTInstVar pvar)
2366 {
2367 enum ssh_kex_known_hosts type;
2368 int ret = FALSE;
2369
2370 type = pvar->contents_after_known_hosts.kex_type;
2371 if (type == SSH1_PUBLIC_KEY_KNOWN_HOSTS) {
2372 ret = handle_server_public_key_after_known_hosts(pvar);
2373
2374 } else if (type == SSH2_DH_KEX_REPLY_KNOWN_HOSTS) {
2375 ret = handle_SSH2_dh_kex_reply_after_known_hosts(pvar);
2376
2377 } else if (type == SSH2_DH_GEX_REPLY_KNOWN_HOSTS) {
2378 ret = handle_SSH2_dh_gex_reply_after_known_hosts(pvar);
2379
2380 } else if (type == SSH2_ECDH_KEX_REPLY_KNOWN_HOSTS) {
2381 ret = handle_SSH2_ecdh_kex_reply_after_known_hosts(pvar);
2382
2383 }
2384
2385 return (ret);
2386 }
2387
2388 /*
2389 * known_hosts�_�C�A���O��SSH�������L�����Z������
2390 */
2391 void HOSTS_cancel_session_after_known_hosts(PTInstVar pvar)
2392 {
2393 enum ssh_kex_known_hosts type;
2394
2395 type = pvar->contents_after_known_hosts.kex_type;
2396 if (type != NONE_KNOWN_HOSTS) {
2397 handle_SSH2_canel_reply_after_known_hosts(pvar);
2398 }
2399
2400 return;
2401 }
2402
2403
2404 void HOSTS_notify_disconnecting(PTInstVar pvar)
2405 {
2406 if (pvar->hosts_state.hosts_dialog != NULL) {
2407 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL, 0);
2408 /* the main window might not go away if it's not enabled. (see vtwin.cpp) */
2409 EnableWindow(pvar->NotificationWindow, TRUE);
2410 }
2411 }
2412
2413 // TCP�Z�b�V�������N���[�Y�����������Aknown_hosts�_�C�A���O���������������w�����o���B
2414 // HOSTS_notify_disconnecting()�����������A�_�C�A���O���������������A
2415 // SSH�T�[�o�����m���o�������B
2416 void HOSTS_notify_closing_on_exit(PTInstVar pvar)
2417 {
2418 if (pvar->hosts_state.hosts_dialog != NULL) {
2419 logprintf(LOG_LEVEL_INFO, "%s: Notify closing message to the known_hosts dialog.", __FUNCTION__);
2420 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCLOSE, 0);
2421 }
2422 }
2423
2424 void HOSTS_end(PTInstVar pvar)
2425 {
2426 int i;
2427
2428 free(pvar->hosts_state.prefetched_hostname);
2429 key_init(&pvar->hosts_state.hostkey);
2430
2431 if (pvar->hosts_state.file_names != NULL) {
2432 for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {
2433 free(pvar->hosts_state.file_names[i]);
2434 }
2435 free(pvar->hosts_state.file_names);
2436 }
2437 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26