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

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