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 9553 - (show annotations) (download) (as text)
Fri Dec 3 11:43:08 2021 UTC (2 years, 4 months ago) by youlab
File MIME type: text/x-csrc
File size: 69279 byte(s)
Windows Vista以降でVirtual Storeが有効の場合、ホスト鍵の種類が同じで、
鍵の内容が異なるときに、known_hostsからの鍵削除ができない問題を修正した。

Windows Vista以降でVirtual Storeが有効の場合、Host key rotationで
元々あったホスト鍵を削除してしまう問題を修正した。

Feedback from
r9179
r9178

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

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