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 9048 - (show annotations) (download) (as text)
Wed Dec 16 12:24:13 2020 UTC (3 years, 3 months ago) by nmaya
File MIME type: text/x-csrc
File size: 68130 byte(s)
ソースファイルの著作権表記の "最後の発行の年" を削除

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

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