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 9504 - (show annotations) (download) (as text)
Fri Oct 29 15:19:06 2021 UTC (2 years, 5 months ago) by zmatsuo
File MIME type: text/x-csrc
File size: 68863 byte(s)
ssh_known_hosts(ファイル名)をUnicode化

- HOSTSState.file_names を char から wchar_t へ変更
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_teraterm_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_teraterm_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_teraterm_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 char filename[MAX_PATH];
1376 #if _MSC_VER < 1900 // less than VSC2015(VC14.0)
1377 char tmp[L_tmpnam];
1378 #endif
1379 int fd;
1380 int amount_written = 0;
1381 int close_result;
1382 int data_index = 0;
1383 wchar_t *buf;
1384 wchar_t *filenameW;
1385
1386 // �������������t�@�C�����J��
1387 #if _MSC_VER < 1900 // less than VSC2015(VC14.0)
1388 _getcwd(filename, sizeof(filename));
1389 tmpnam_s(tmp, sizeof(tmp));
1390 strcat_s(filename, sizeof(filename), tmp);
1391 #else // VSC2015(VC14.0) or later
1392 tmpnam_s(filename, sizeof(filename));
1393 #endif
1394 fd = _open(filename,
1395 _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY | _O_TRUNC,
1396 _S_IREAD | _S_IWRITE);
1397
1398 if (fd == -1) {
1399 if (errno == EACCES) {
1400 UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar,
1401 "An error occurred while trying to write the host key.\n"
1402 "You do not have permission to write to the known-hosts file.");
1403 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1404 } else {
1405 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1406 "An error occurred while trying to write the host key.\n"
1407 "The host key could not be written.");
1408 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1409 }
1410 return;
1411 }
1412
1413 // �t�@�C��������������
1414 memset(&key, 0, sizeof(key));
1415 begin_read_host_files(pvar, 0);
1416 do {
1417 int host_index = 0;
1418 int matched = 0;
1419 int keybits = 0;
1420 char *data;
1421 int do_write = 0;
1422 length = amount_written = 0;
1423
1424 if (!read_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, 0, 1, &key)) {
1425 break;
1426 }
1427
1428 if (data_index == pvar->hosts_state.file_data_index) {
1429 // index ���i������ == ��������������
1430 break;
1431 }
1432
1433 data = pvar->hosts_state.file_data + data_index;
1434 host_index = eat_spaces(data);
1435
1436 if (data[host_index] == '#') {
1437 do_write = 1;
1438 }
1439 else {
1440 // �z�X�g������
1441 host_index--;
1442 do {
1443 int negated;
1444 int bracketed;
1445 char *end_bracket;
1446 int host_matched = 0;
1447 unsigned short keyfile_port = 22;
1448
1449 host_index++;
1450 negated = data[host_index] == '!';
1451
1452 if (negated) {
1453 host_index++;
1454 bracketed = data[host_index] == '[';
1455 if (bracketed) {
1456 end_bracket = strstr(data + host_index + 1, "]:");
1457 if (end_bracket != NULL) {
1458 *end_bracket = ' ';
1459 host_index++;
1460 }
1461 }
1462 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1463 if (bracketed && end_bracket != NULL) {
1464 *end_bracket = ']';
1465 keyfile_port = atoi(end_bracket + 2);
1466 }
1467 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1468 matched = 0;
1469 // �����o�[�W�����`�F�b�N�������� host_index ���i��������������
1470 host_index--;
1471 do {
1472 host_index++;
1473 host_index += eat_to_end_of_pattern(data + host_index);
1474 } while (data[host_index] == ',');
1475 break;
1476 }
1477 }
1478 else {
1479 bracketed = data[host_index] == '[';
1480 if (bracketed) {
1481 end_bracket = strstr(data + host_index + 1, "]:");
1482 if (end_bracket != NULL) {
1483 *end_bracket = ' ';
1484 host_index++;
1485 }
1486 }
1487 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1488 if (bracketed && end_bracket != NULL) {
1489 *end_bracket = ']';
1490 keyfile_port = atoi(end_bracket + 2);
1491 }
1492 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1493 matched = 1;
1494 }
1495 }
1496 host_index += eat_to_end_of_pattern(data + host_index);
1497 } while (data[host_index] == ',');
1498
1499 // �z�X�g������������
1500 if (!matched) {
1501 do_write = 1;
1502 }
1503 // �z�X�g��������
1504 else {
1505 // �����`�������� or ���v�����L�[
1506 if (HOSTS_compare_public_key(&pvar->hosts_state.hostkey, &key) != 0) {
1507 do_write = 1;
1508 }
1509 // �����`�������������v�������L�[���X�L�b�v������
1510 }
1511 }
1512
1513 // ������������
1514 if (do_write) {
1515 length = pvar->hosts_state.file_data_index - data_index;
1516 amount_written =
1517 _write(fd, pvar->hosts_state.file_data + data_index,
1518 length);
1519
1520 if (amount_written != length) {
1521 goto error1;
1522 }
1523 }
1524 data_index = pvar->hosts_state.file_data_index;
1525 } while (1); // ������������
1526
1527 error1:
1528 close_result = _close(fd);
1529 if (amount_written != length || close_result == -1) {
1530 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1531 "An error occurred while trying to write the host key.\n"
1532 "The host key could not be written.");
1533 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1534 goto error2;
1535 }
1536
1537 // �������������t�@�C���������l�[��
1538 buf = get_teraterm_dir_relative_nameW(name);
1539 _wunlink(buf);
1540 filenameW = ToWcharA(filename);
1541 _wrename(filenameW, buf);
1542 free(buf);
1543 free(filenameW);
1544
1545 error2:
1546 _unlink(filename);
1547
1548 finish_read_host_files(pvar, 0);
1549
1550 // ���������������������������B
1551 key_init(&key);
1552 }
1553 }
1554
1555
1556 void HOSTS_delete_all_hostkeys(PTInstVar pvar)
1557 {
1558 wchar_t *name = pvar->hosts_state.file_names[0];
1559 char *hostname;
1560 unsigned short tcpport;
1561
1562 hostname = pvar->ssh_state.hostname;
1563 tcpport = pvar->ssh_state.tcpport;
1564
1565 if (name == NULL || name[0] == 0) {
1566 UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar,
1567 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
1568 "Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
1569 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1570 }
1571 else {
1572 Key key; // known_hosts���o�^������������
1573 int length;
1574 char filename[MAX_PATH];
1575 #if _MSC_VER < 1900 // less than VSC2015(VC14.0)
1576 char tmp[L_tmpnam];
1577 #endif
1578 int fd;
1579 int amount_written = 0;
1580 int close_result;
1581 int data_index = 0;
1582 wchar_t *buf;
1583 wchar_t *filenameW;
1584
1585 // �������������t�@�C�����J��
1586 #if _MSC_VER < 1900 // less than VSC2015(VC14.0)
1587 _getcwd(filename, sizeof(filename));
1588 tmpnam_s(tmp, sizeof(tmp));
1589 strcat_s(filename, sizeof(filename), tmp);
1590 #else // VSC2015(VC14.0) or later
1591 tmpnam_s(filename, sizeof(filename));
1592 #endif
1593 fd = _open(filename,
1594 _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY | _O_TRUNC,
1595 _S_IREAD | _S_IWRITE);
1596
1597 if (fd == -1) {
1598 if (errno == EACCES) {
1599 UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar,
1600 "An error occurred while trying to write the host key.\n"
1601 "You do not have permission to write to the known-hosts file.");
1602 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1603 }
1604 else {
1605 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1606 "An error occurred while trying to write the host key.\n"
1607 "The host key could not be written.");
1608 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1609 }
1610 return;
1611 }
1612
1613 // �t�@�C��������������
1614 memset(&key, 0, sizeof(key));
1615 begin_read_host_files(pvar, 0);
1616 do {
1617 int host_index = 0;
1618 int matched = 0;
1619 int keybits = 0;
1620 char *data;
1621 int do_write = 0;
1622 length = amount_written = 0;
1623
1624 if (!read_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, 0, 1, &key)) {
1625 break;
1626 }
1627
1628 if (data_index == pvar->hosts_state.file_data_index) {
1629 // index ���i������ == ��������������
1630 break;
1631 }
1632
1633 data = pvar->hosts_state.file_data + data_index;
1634 host_index = eat_spaces(data);
1635
1636 if (data[host_index] == '#') {
1637 do_write = 1;
1638 }
1639 else {
1640 // �z�X�g������
1641 host_index--;
1642 do {
1643 int negated;
1644 int bracketed;
1645 char *end_bracket;
1646 int host_matched = 0;
1647 unsigned short keyfile_port = 22;
1648
1649 host_index++;
1650 negated = data[host_index] == '!';
1651
1652 if (negated) {
1653 host_index++;
1654 bracketed = data[host_index] == '[';
1655 if (bracketed) {
1656 end_bracket = strstr(data + host_index + 1, "]:");
1657 if (end_bracket != NULL) {
1658 *end_bracket = ' ';
1659 host_index++;
1660 }
1661 }
1662 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1663 if (bracketed && end_bracket != NULL) {
1664 *end_bracket = ']';
1665 keyfile_port = atoi(end_bracket + 2);
1666 }
1667 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1668 matched = 0;
1669 // �����o�[�W�����`�F�b�N�������� host_index ���i��������������
1670 host_index--;
1671 do {
1672 host_index++;
1673 host_index += eat_to_end_of_pattern(data + host_index);
1674 } while (data[host_index] == ',');
1675 break;
1676 }
1677 }
1678 else {
1679 bracketed = data[host_index] == '[';
1680 if (bracketed) {
1681 end_bracket = strstr(data + host_index + 1, "]:");
1682 if (end_bracket != NULL) {
1683 *end_bracket = ' ';
1684 host_index++;
1685 }
1686 }
1687 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1688 if (bracketed && end_bracket != NULL) {
1689 *end_bracket = ']';
1690 keyfile_port = atoi(end_bracket + 2);
1691 }
1692 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1693 matched = 1;
1694 }
1695 }
1696 host_index += eat_to_end_of_pattern(data + host_index);
1697 } while (data[host_index] == ',');
1698
1699 // �z�X�g������������
1700 if (!matched) {
1701 do_write = 1;
1702 }
1703 // �z�X�g��������
1704 else {
1705 // ���������������������B
1706
1707 }
1708 }
1709
1710 // ������������
1711 if (do_write) {
1712 length = pvar->hosts_state.file_data_index - data_index;
1713 amount_written =
1714 _write(fd, pvar->hosts_state.file_data + data_index,
1715 length);
1716
1717 if (amount_written != length) {
1718 goto error1;
1719 }
1720 }
1721 data_index = pvar->hosts_state.file_data_index;
1722 } while (1); // ������������
1723
1724 error1:
1725 close_result = _close(fd);
1726 if (amount_written != length || close_result == -1) {
1727 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1728 "An error occurred while trying to write the host key.\n"
1729 "The host key could not be written.");
1730 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1731 goto error2;
1732 }
1733
1734 // �������������t�@�C���������l�[��
1735 buf = get_teraterm_dir_relative_nameW(name);
1736 _wunlink(buf);
1737 filenameW = ToWcharA(filename);
1738 _wrename(filenameW, buf);
1739 free(filenameW);
1740 free(buf);
1741
1742 error2:
1743 _unlink(filename);
1744
1745 finish_read_host_files(pvar, 0);
1746
1747 // ���������������������������B
1748 key_init(&key);
1749 }
1750 }
1751
1752
1753 //
1754 // Unknown host���z�X�g���J���� known_hosts �t�@�C����������������������
1755 // ���[�U���m�F�������B
1756 // TODO: finger print���\�����s���B
1757 // (2006.3.25 yutaka)
1758 //
1759 static INT_PTR CALLBACK hosts_add_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1760 LPARAM lParam)
1761 {
1762 static const DlgTextInfo text_info[] = {
1763 { 0, "DLG_UNKNOWNHOST_TITLE" },
1764 { IDC_HOSTWARNING, "DLG_UNKNOWNHOST_WARNING" },
1765 { IDC_HOSTWARNING2, "DLG_UNKNOWNHOST_WARNING2" },
1766 { IDC_HOSTFINGERPRINT, "DLG_UNKNOWNHOST_FINGERPRINT" },
1767 { IDC_FP_HASH_ALG, "DLG_UNKNOWNHOST_FP_HASH_ALGORITHM" },
1768 { IDC_ADDTOKNOWNHOSTS, "DLG_UNKNOWNHOST_ADD" },
1769 { IDC_CONTINUE, "BTN_CONTINUE" },
1770 { IDCANCEL, "BTN_DISCONNECT" },
1771 };
1772 PTInstVar pvar;
1773
1774 switch (msg) {
1775 case WM_INITDIALOG:
1776 pvar = (PTInstVar) lParam;
1777 pvar->hosts_state.hosts_dialog = dlg;
1778 SetWindowLongPtr(dlg, DWLP_USER, lParam);
1779
1780 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
1781 SetI18nDlgStrsW(dlg, "TTSSH", text_info, _countof(text_info), pvar->ts->UILanguageFileW);
1782
1783 switch (pvar->dns_key_check) {
1784 case DNS_VERIFY_NOTFOUND:
1785 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_NOTFOUND", pvar, "No host key fingerprint found in DNS.");
1786 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1787 break;
1788 case DNS_VERIFY_MATCH:
1789 case DNS_VERIFY_AUTH_MATCH:
1790 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MATCH", pvar, "Matching host key fingerprint found in DNS.");
1791 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1792 break;
1793 case DNS_VERIFY_MISMATCH:
1794 case DNS_VERIFY_AUTH_MISMATCH:
1795 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MISMATCH", pvar, "Mismatching host key fingerprint found in DNS.");
1796 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1797 break;
1798 case DNS_VERIFY_DIFFERENTTYPE:
1799 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
1800 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_DIFFTYPE", pvar, "Mismatching host key type found in DNS.");
1801 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1802 break;
1803 }
1804
1805 switch (pvar->dns_key_check) {
1806 case DNS_VERIFY_MATCH:
1807 case DNS_VERIFY_MISMATCH:
1808 case DNS_VERIFY_DIFFERENTTYPE:
1809 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_NG", pvar, "Found insecure fingerprint in DNS.");
1810 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
1811 break;
1812 case DNS_VERIFY_AUTH_MATCH:
1813 case DNS_VERIFY_AUTH_MISMATCH:
1814 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
1815 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_OK", pvar, "Found secure fingerprint in DNS.");
1816 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
1817 break;
1818 }
1819
1820 init_hosts_dlg(pvar, dlg);
1821 // add host check box���`�F�b�N���f�t�H���g������������
1822 SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
1823
1824 CenterWindow(dlg, GetParent(dlg));
1825
1826 return TRUE; /* because we do not set the focus */
1827
1828 case WM_COMMAND:
1829 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
1830
1831 switch (LOWORD(wParam)) {
1832 case IDC_CONTINUE:
1833 // �F�������T�[�o�������f�������������A�L�����Z�������������B(2014.3.31 yutaka)
1834 if (!pvar->cv->Ready) {
1835 goto canceled;
1836 }
1837
1838 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1839 add_host_key(pvar);
1840 }
1841
1842 /*
1843 * known_hosts�_�C�A���O���������������~��������
1844 * SSH�T�[�o�����l�S�V�G�[�V���������J�������B
1845 */
1846 HOSTS_resume_session_after_known_hosts(pvar);
1847
1848 pvar->hosts_state.hosts_dialog = NULL;
1849
1850 EndDialog(dlg, 1);
1851 return TRUE;
1852
1853 case IDCANCEL: /* kill the connection */
1854 canceled:
1855 /*
1856 * known_hosts���L�����Z�����������A���J�p�����\�[�X���j�����������B
1857 */
1858 HOSTS_cancel_session_after_known_hosts(pvar);
1859
1860 pvar->hosts_state.hosts_dialog = NULL;
1861 notify_closed_connection(pvar, "authentication cancelled");
1862 EndDialog(dlg, 0);
1863 return TRUE;
1864
1865 case IDCLOSE:
1866 /*
1867 * known_hosts�����T�[�o�������l�b�g���[�N���f�����������A
1868 * �_�C�A���O�������������B
1869 */
1870 HOSTS_cancel_session_after_known_hosts(pvar);
1871
1872 pvar->hosts_state.hosts_dialog = NULL;
1873 EndDialog(dlg, 0);
1874 return TRUE;
1875
1876 case IDC_FP_HASH_ALG_MD5:
1877 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_MD5);
1878 return TRUE;
1879
1880 case IDC_FP_HASH_ALG_SHA256:
1881 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_SHA256);
1882 return TRUE;
1883
1884 default:
1885 return FALSE;
1886 }
1887
1888 case WM_DPICHANGED:
1889 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
1890 if (pvar->hFontFixed != NULL) {
1891 DeleteObject(pvar->hFontFixed);
1892 }
1893 pvar->hFontFixed = UTIL_get_lang_fixedfont(dlg, pvar->ts->UILanguageFile);
1894 if (pvar->hFontFixed != NULL) {
1895 SendDlgItemMessage(dlg, IDC_FP_RANDOMART, WM_SETFONT,
1896 (WPARAM)pvar->hFontFixed, MAKELPARAM(TRUE,0));
1897 }
1898 return FALSE;
1899
1900 case WM_DESTROY:
1901 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
1902 if (pvar->hFontFixed != NULL) {
1903 DeleteObject(pvar->hFontFixed);
1904 pvar->hFontFixed = NULL;
1905 }
1906 return FALSE;
1907
1908 default:
1909 return FALSE;
1910 }
1911 }
1912
1913 //
1914 // �u�����������m�F�_�C�A���O������
1915 //
1916 static INT_PTR CALLBACK hosts_replace_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1917 LPARAM lParam)
1918 {
1919 static const DlgTextInfo text_info[] = {
1920 { 0, "DLG_UNKNOWNHOST_TITLE" },
1921 { IDC_HOSTWARNING, "DLG_DIFFERENTKEY_WARNING" },
1922 { IDC_HOSTWARNING2, "DLG_DIFFERENTKEY_WARNING2" },
1923 { IDC_HOSTFINGERPRINT, "DLG_DIFFERENTKEY_FINGERPRINT" },
1924 { IDC_FP_HASH_ALG, "DLG_DIFFERENTKEY_FP_HASH_ALGORITHM" },
1925 { IDC_ADDTOKNOWNHOSTS, "DLG_DIFFERENTKEY_REPLACE" },
1926 { IDC_CONTINUE, "BTN_CONTINUE" },
1927 { IDCANCEL, "BTN_DISCONNECT" },
1928 };
1929 PTInstVar pvar;
1930
1931 switch (msg) {
1932 case WM_INITDIALOG:
1933 pvar = (PTInstVar) lParam;
1934 pvar->hosts_state.hosts_dialog = dlg;
1935 SetWindowLongPtr(dlg, DWLP_USER, lParam);
1936
1937 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
1938 SetI18nDlgStrsW(dlg, "TTSSH", text_info, _countof(text_info), pvar->ts->UILanguageFileW);
1939
1940 switch (pvar->dns_key_check) {
1941 case DNS_VERIFY_NOTFOUND:
1942 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_NOTFOUND", pvar, "No host key fingerprint found in DNS.");
1943 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1944 break;
1945 case DNS_VERIFY_MATCH:
1946 case DNS_VERIFY_AUTH_MATCH:
1947 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MATCH", pvar, "Matching host key fingerprint found in DNS.");
1948 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1949 break;
1950 case DNS_VERIFY_MISMATCH:
1951 case DNS_VERIFY_AUTH_MISMATCH:
1952 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MISMATCH", pvar, "Mismatching host key fingerprint found in DNS.");
1953 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1954 break;
1955 case DNS_VERIFY_DIFFERENTTYPE:
1956 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
1957 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_DIFFTYPE", pvar, "Mismatching host key type found in DNS.");
1958 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
1959 break;
1960 }
1961
1962 switch (pvar->dns_key_check) {
1963 case DNS_VERIFY_MATCH:
1964 case DNS_VERIFY_MISMATCH:
1965 case DNS_VERIFY_DIFFERENTTYPE:
1966 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_NG", pvar, "Found insecure fingerprint in DNS.");
1967 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
1968 break;
1969 case DNS_VERIFY_AUTH_MATCH:
1970 case DNS_VERIFY_AUTH_MISMATCH:
1971 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
1972 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_OK", pvar, "Found secure fingerprint in DNS.");
1973 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
1974 break;
1975 }
1976
1977 init_hosts_dlg(pvar, dlg);
1978 CenterWindow(dlg, GetParent(dlg));
1979 // �f�t�H���g���`�F�b�N����������
1980 return TRUE; /* because we do not set the focus */
1981
1982 case WM_COMMAND:
1983 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
1984
1985 switch (LOWORD(wParam)) {
1986 case IDC_CONTINUE:
1987 // �F�������T�[�o�������f�������������A�L�����Z�������������B(2014.3.31 yutaka)
1988 if (!pvar->cv->Ready) {
1989 goto canceled;
1990 }
1991
1992 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1993 add_host_key(pvar);
1994 delete_different_key(pvar);
1995 }
1996
1997 /*
1998 * known_hosts�_�C�A���O���������������~��������
1999 * SSH�T�[�o�����l�S�V�G�[�V���������J�������B
2000 */
2001 HOSTS_resume_session_after_known_hosts(pvar);
2002
2003 pvar->hosts_state.hosts_dialog = NULL;
2004
2005 EndDialog(dlg, 1);
2006 return TRUE;
2007
2008 case IDCANCEL: /* kill the connection */
2009 canceled:
2010 /*
2011 * known_hosts���L�����Z�����������A���J�p�����\�[�X���j�����������B
2012 */
2013 HOSTS_cancel_session_after_known_hosts(pvar);
2014
2015 pvar->hosts_state.hosts_dialog = NULL;
2016 notify_closed_connection(pvar, "authentication cancelled");
2017 EndDialog(dlg, 0);
2018 return TRUE;
2019
2020 case IDCLOSE:
2021 /*
2022 * known_hosts�����T�[�o�������l�b�g���[�N���f�����������A
2023 * �_�C�A���O�������������B
2024 */
2025 HOSTS_cancel_session_after_known_hosts(pvar);
2026
2027 pvar->hosts_state.hosts_dialog = NULL;
2028 EndDialog(dlg, 0);
2029 return TRUE;
2030
2031 case IDC_FP_HASH_ALG_MD5:
2032 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_MD5);
2033 return TRUE;
2034
2035 case IDC_FP_HASH_ALG_SHA256:
2036 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_SHA256);
2037 return TRUE;
2038
2039 default:
2040 return FALSE;
2041 }
2042
2043 case WM_DPICHANGED:
2044 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2045 if (pvar->hFontFixed != NULL) {
2046 DeleteObject(pvar->hFontFixed);
2047 }
2048 pvar->hFontFixed = UTIL_get_lang_fixedfont(dlg, pvar->ts->UILanguageFile);
2049 if (pvar->hFontFixed != NULL) {
2050 SendDlgItemMessage(dlg, IDC_FP_RANDOMART, WM_SETFONT,
2051 (WPARAM)pvar->hFontFixed, MAKELPARAM(TRUE,0));
2052 }
2053 return FALSE;
2054
2055 case WM_DESTROY:
2056 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2057 if (pvar->hFontFixed != NULL) {
2058 DeleteObject(pvar->hFontFixed);
2059 pvar->hFontFixed = NULL;
2060 }
2061 return FALSE;
2062
2063 default:
2064 return FALSE;
2065 }
2066 }
2067
2068 //
2069 // �����z�X�g�����`�����������������m�F�_�C�A���O������
2070 //
2071 static INT_PTR CALLBACK hosts_add2_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
2072 LPARAM lParam)
2073 {
2074 static const DlgTextInfo text_info[] = {
2075 { 0, "DLG_DIFFERENTTYPEKEY_TITLE" },
2076 { IDC_HOSTWARNING, "DLG_DIFFERENTTYPEKEY_WARNING" },
2077 { IDC_HOSTWARNING2, "DLG_DIFFERENTTYPEKEY_WARNING2" },
2078 { IDC_HOSTFINGERPRINT, "DLG_DIFFERENTTYPEKEY_FINGERPRINT" },
2079 { IDC_FP_HASH_ALG, "DLG_DIFFERENTTYPEKEY_FP_HASH_ALGORITHM" },
2080 { IDC_ADDTOKNOWNHOSTS, "DLG_DIFFERENTTYPEKEY_ADD" },
2081 { IDC_CONTINUE, "BTN_CONTINUE" },
2082 { IDCANCEL, "BTN_DISCONNECT" },
2083 };
2084 PTInstVar pvar;
2085
2086 switch (msg) {
2087 case WM_INITDIALOG:
2088 pvar = (PTInstVar) lParam;
2089 pvar->hosts_state.hosts_dialog = dlg;
2090 SetWindowLongPtr(dlg, DWLP_USER, lParam);
2091
2092 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
2093 SetI18nDlgStrsW(dlg, "TTSSH", text_info, _countof(text_info), pvar->ts->UILanguageFileW);
2094
2095 switch (pvar->dns_key_check) {
2096 case DNS_VERIFY_NOTFOUND:
2097 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_NOTFOUND", pvar, "No host key fingerprint found in DNS.");
2098 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
2099 break;
2100 case DNS_VERIFY_MATCH:
2101 case DNS_VERIFY_AUTH_MATCH:
2102 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MATCH", pvar, "Matching host key fingerprint found in DNS.");
2103 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
2104 break;
2105 case DNS_VERIFY_MISMATCH:
2106 case DNS_VERIFY_AUTH_MISMATCH:
2107 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_MISMATCH", pvar, "Mismatching host key fingerprint found in DNS.");
2108 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
2109 break;
2110 case DNS_VERIFY_DIFFERENTTYPE:
2111 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
2112 UTIL_get_lang_msg("DLG_HOSTKEY_SSHFP_DIFFTYPE", pvar, "Mismatching host key type found in DNS.");
2113 SetDlgItemText(dlg, IDC_HOSTSSHFPCHECK, pvar->ts->UIMsg);
2114 break;
2115 }
2116
2117 switch (pvar->dns_key_check) {
2118 case DNS_VERIFY_MATCH:
2119 case DNS_VERIFY_MISMATCH:
2120 case DNS_VERIFY_DIFFERENTTYPE:
2121 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_NG", pvar, "Found insecure fingerprint in DNS.");
2122 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
2123 break;
2124 case DNS_VERIFY_AUTH_MATCH:
2125 case DNS_VERIFY_AUTH_MISMATCH:
2126 case DNS_VERIFY_AUTH_DIFFERENTTYPE:
2127 UTIL_get_lang_msg("DLG_HOSTKEY_DNSSEC_OK", pvar, "Found secure fingerprint in DNS.");
2128 SetDlgItemText(dlg, IDC_HOSTSSHFPDNSSEC, pvar->ts->UIMsg);
2129 break;
2130 }
2131
2132 init_hosts_dlg(pvar, dlg);
2133 CenterWindow(dlg, GetParent(dlg));
2134 // add host check box ���f�t�H���g�� off ������
2135 // SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
2136
2137 return TRUE; /* because we do not set the focus */
2138
2139 case WM_COMMAND:
2140 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2141
2142 switch (LOWORD(wParam)) {
2143 case IDC_CONTINUE:
2144 // �F�������T�[�o�������f�������������A�L�����Z�������������B(2014.3.31 yutaka)
2145 if (!pvar->cv->Ready) {
2146 goto canceled;
2147 }
2148
2149 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
2150 add_host_key(pvar);
2151 }
2152
2153 /*
2154 * known_hosts�_�C�A���O���������������~��������
2155 * SSH�T�[�o�����l�S�V�G�[�V���������J�������B
2156 */
2157 HOSTS_resume_session_after_known_hosts(pvar);
2158
2159 pvar->hosts_state.hosts_dialog = NULL;
2160
2161 EndDialog(dlg, 1);
2162 return TRUE;
2163
2164 case IDCANCEL: /* kill the connection */
2165 canceled:
2166 /*
2167 * known_hosts���L�����Z�����������A���J�p�����\�[�X���j�����������B
2168 */
2169 HOSTS_cancel_session_after_known_hosts(pvar);
2170
2171 pvar->hosts_state.hosts_dialog = NULL;
2172 notify_closed_connection(pvar, "authentication cancelled");
2173 EndDialog(dlg, 0);
2174 return TRUE;
2175
2176 case IDCLOSE:
2177 /*
2178 * known_hosts�����T�[�o�������l�b�g���[�N���f�����������A
2179 * �_�C�A���O�������������B
2180 */
2181 HOSTS_cancel_session_after_known_hosts(pvar);
2182
2183 pvar->hosts_state.hosts_dialog = NULL;
2184 EndDialog(dlg, 0);
2185 return TRUE;
2186
2187 case IDC_FP_HASH_ALG_MD5:
2188 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_MD5);
2189 return TRUE;
2190
2191 case IDC_FP_HASH_ALG_SHA256:
2192 hosts_dlg_set_fingerprint(pvar, dlg, SSH_DIGEST_SHA256);
2193 return TRUE;
2194
2195 default:
2196 return FALSE;
2197 }
2198
2199 case WM_DPICHANGED:
2200 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2201 if (pvar->hFontFixed != NULL) {
2202 DeleteObject(pvar->hFontFixed);
2203 }
2204 pvar->hFontFixed = UTIL_get_lang_fixedfont(dlg, pvar->ts->UILanguageFile);
2205 if (pvar->hFontFixed != NULL) {
2206 SendDlgItemMessage(dlg, IDC_FP_RANDOMART, WM_SETFONT,
2207 (WPARAM)pvar->hFontFixed, MAKELPARAM(TRUE,0));
2208 }
2209 return FALSE;
2210
2211 case WM_DESTROY:
2212 pvar = (PTInstVar) GetWindowLongPtr(dlg, DWLP_USER);
2213 if (pvar->hFontFixed != NULL) {
2214 DeleteObject(pvar->hFontFixed);
2215 pvar->hFontFixed = NULL;
2216 }
2217 return FALSE;
2218
2219 default:
2220 return FALSE;
2221 }
2222 }
2223
2224 void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar)
2225 {
2226 if (pvar->hosts_state.hosts_dialog == NULL) {
2227 /* known_hosts�������������AID_SSHASYNCMESSAGEBOX ���g����
2228 * MessageBox ���\�������������A�I�[�i�[����(no owner)�����������A
2229 * MessageBox ��Tera Term�������B���������������B
2230 * ���������� GetActiveWindow() �������o�����Aknown_hosts�_�C�A���O��
2231 * �I�[�i�[�� MessageBox ���������ATera Term�������B�����������B
2232 * �������Aknown_hosts�_�C�A���O���I�[�i�[������ Tera Term ���w������
2233 * �����������B
2234 */
2235 HWND cur_active = NULL;
2236
2237 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST),
2238 cur_active != NULL ? cur_active : wnd,
2239 hosts_add_dlg_proc, (LPARAM) pvar);
2240 }
2241 }
2242
2243 void HOSTS_do_different_key_dialog(HWND wnd, PTInstVar pvar)
2244 {
2245 if (pvar->hosts_state.hosts_dialog == NULL) {
2246 /* known_hosts�������������AID_SSHASYNCMESSAGEBOX ���g����
2247 * MessageBox ���\�������������A�I�[�i�[����(no owner)�����������A
2248 * MessageBox ��Tera Term�������B���������������B
2249 * ���������� GetActiveWindow() �������o�����Aknown_hosts�_�C�A���O��
2250 * �I�[�i�[�� MessageBox ���������ATera Term�������B�����������B
2251 * �������Aknown_hosts�_�C�A���O���I�[�i�[������ Tera Term ���w������
2252 * �����������B
2253 */
2254 HWND cur_active = NULL;
2255
2256 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTKEY),
2257 cur_active != NULL ? cur_active : wnd,
2258 hosts_replace_dlg_proc, (LPARAM) pvar);
2259 }
2260 }
2261
2262 void HOSTS_do_different_type_key_dialog(HWND wnd, PTInstVar pvar)
2263 {
2264 if (pvar->hosts_state.hosts_dialog == NULL) {
2265 /* known_hosts�������������AID_SSHASYNCMESSAGEBOX ���g����
2266 * MessageBox ���\�������������A�I�[�i�[����(no owner)�����������A
2267 * MessageBox ��Tera Term�������B���������������B
2268 * ���������� GetActiveWindow() �������o�����Aknown_hosts�_�C�A���O��
2269 * �I�[�i�[�� MessageBox ���������ATera Term�������B�����������B
2270 * �������Aknown_hosts�_�C�A���O���I�[�i�[������ Tera Term ���w������
2271 * �����������B
2272 */
2273 HWND cur_active = NULL;
2274
2275 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTTYPEKEY),
2276 cur_active != NULL ? cur_active : wnd,
2277 hosts_add2_dlg_proc, (LPARAM) pvar);
2278 }
2279 }
2280
2281 /*
2282 * �T�[�o�����������������z�X�g���J�������������`�F�b�N���A
2283 * �K�v�������� known_hosts �_�C�A���O�������o���B
2284 *
2285 * hostname: ���������z�X�g��
2286 * tcpport: �������|�[�g����
2287 * key: �T�[�o���������J��
2288 *
2289 * return:
2290 * TRUE: known_hosts�_�C�A���O�������o�����s�v
2291 * FALSE: known_hosts�_�C�A���O�������o����
2292 *
2293 */
2294 BOOL HOSTS_check_host_key(PTInstVar pvar, char *hostname, unsigned short tcpport, Key *key)
2295 {
2296 int found_different_key = 0, found_different_type_key = 0;
2297 Key key2; // known_hosts���o�^������������
2298 DWORD id;
2299
2300 pvar->dns_key_check = DNS_VERIFY_NONE;
2301
2302 // ������ known_hosts �t�@�C�������z�X�g���J�����������������������A���������r�����B
2303 if (pvar->hosts_state.prefetched_hostname != NULL
2304 && _stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0
2305 && HOSTS_compare_public_key(&pvar->hosts_state.hostkey, key) == 1) {
2306
2307 // ���������������B
2308 return TRUE;
2309 }
2310
2311 // �������������������������A�������_���t�@�C��������������
2312 memset(&key2, 0, sizeof(key2));
2313 if (begin_read_host_files(pvar, 0)) {
2314 do {
2315 if (!read_host_key(pvar, hostname, tcpport, 0, 0, &key2)) {
2316 break;
2317 }
2318
2319 if (key2.type != KEY_UNSPEC) {
2320 int match = HOSTS_compare_public_key(&key2, key);
2321 if (match == 1) {
2322 finish_read_host_files(pvar, 0);
2323 // ���������G���g�����Q�������A���v�����L�[�������������������B
2324 // About TTSSH �_�C�A���O�����\�����������A�������������������B
2325 key_copy(&pvar->hosts_state.hostkey, key);
2326
2327 return TRUE;
2328 }
2329 else if (match == 0) {
2330 // �L�[�� known_hosts ���������������A�L�[�����e���������B
2331 found_different_key = 1;
2332 }
2333 else {
2334 // �L�[���`������������
2335 found_different_type_key = 1;
2336 }
2337 }
2338 } while (key2.type != KEY_UNSPEC); // �L�[�����������������������[�v����
2339
2340 key_init(&key2);
2341 finish_read_host_files(pvar, 0);
2342 }
2343
2344 // known_hosts �������������L�[���������t�@�C�������������������A�������������������B
2345 key_copy(&pvar->hosts_state.hostkey, key);
2346
2347 free(pvar->hosts_state.prefetched_hostname);
2348 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
2349
2350 // "/nosecuritywarning"���w�����������������A�_�C�A���O���\���������� return success �����B
2351 if (pvar->nocheck_known_hosts == TRUE) {
2352 // ���������������B
2353 return TRUE;
2354 }
2355
2356 if (pvar->settings.VerifyHostKeyDNS && !is_numeric_hostname(hostname)) {
2357 pvar->dns_key_check = verify_hostkey_dns(pvar, hostname, key);
2358 }
2359
2360 // known_hosts�_�C�A���O�������I���\�������A�������_�����������[�U���m�F
2361 // �������K�v�����������A�����R�[�������X�����B
2362 // ����������known_hosts���m�F�����������A�T�[�o�����[�U���������������������������������B
2363 // (2007.10.1 yutaka)
2364 /*
2365 * known_hosts�_�C�A���O�����������\�����������������������B
2366 * known_hosts�_�C�A���O���\�������������������A�T�[�o�������f���s�����A
2367 * TTXCloseTCP�������o�����ATTSSH�����\�[�X�������������������B
2368 * SSH�n���h����������known_hosts�_�C�A���O���o�����~���������������A
2369 * �������J�����s���A�N�Z�X���������B
2370 * (2019.9.3 yutaka)
2371 */
2372 if (found_different_key) {
2373 // TTXProcessCommand ���� HOSTS_do_different_key_dialog() �������o���B
2374 id = ID_SSHDIFFERENTKEY;
2375 }
2376 else if (found_different_type_key) {
2377 // TTXProcessCommand ���� HOSTS_do_different_type_key_dialog() �������o���B
2378 id = ID_SSHDIFFERENT_TYPE_KEY;
2379 }
2380 else {
2381 // TTXProcessCommand ���� HOSTS_do_unknown_host_dialog() �������o���B
2382 id = ID_SSHUNKNOWNHOST;
2383 }
2384
2385 PostMessage(pvar->NotificationWindow, WM_COMMAND, id, 0);
2386
2387 logprintf(LOG_LEVEL_INFO, "Calling known_hosts dialog...(%s)",
2388 id == ID_SSHDIFFERENTKEY ? "SSHDIFFERENTKEY" :
2389 id == ID_SSHDIFFERENT_TYPE_KEY ? "SSHDIFFERENT_TYPE_KEY" : "SSHUNKNOWNHOST"
2390 );
2391
2392 return FALSE;
2393 }
2394
2395 /*
2396 * known_hosts�_�C�A���O�����[�U���F���ASSH�T�[�o�����l�S�V�G�[�V���������J�����B
2397 */
2398 BOOL HOSTS_resume_session_after_known_hosts(PTInstVar pvar)
2399 {
2400 enum ssh_kex_known_hosts type;
2401 int ret = FALSE;
2402
2403 type = pvar->contents_after_known_hosts.kex_type;
2404 if (type == SSH1_PUBLIC_KEY_KNOWN_HOSTS) {
2405 ret = handle_server_public_key_after_known_hosts(pvar);
2406
2407 } else if (type == SSH2_DH_KEX_REPLY_KNOWN_HOSTS) {
2408 ret = handle_SSH2_dh_kex_reply_after_known_hosts(pvar);
2409
2410 } else if (type == SSH2_DH_GEX_REPLY_KNOWN_HOSTS) {
2411 ret = handle_SSH2_dh_gex_reply_after_known_hosts(pvar);
2412
2413 } else if (type == SSH2_ECDH_KEX_REPLY_KNOWN_HOSTS) {
2414 ret = handle_SSH2_ecdh_kex_reply_after_known_hosts(pvar);
2415
2416 }
2417
2418 return (ret);
2419 }
2420
2421 /*
2422 * known_hosts�_�C�A���O��SSH�������L�����Z������
2423 */
2424 void HOSTS_cancel_session_after_known_hosts(PTInstVar pvar)
2425 {
2426 enum ssh_kex_known_hosts type;
2427
2428 type = pvar->contents_after_known_hosts.kex_type;
2429 if (type != NONE_KNOWN_HOSTS) {
2430 handle_SSH2_canel_reply_after_known_hosts(pvar);
2431 }
2432
2433 return;
2434 }
2435
2436
2437 void HOSTS_notify_disconnecting(PTInstVar pvar)
2438 {
2439 if (pvar->hosts_state.hosts_dialog != NULL) {
2440 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL, 0);
2441 /* the main window might not go away if it's not enabled. (see vtwin.cpp) */
2442 EnableWindow(pvar->NotificationWindow, TRUE);
2443 }
2444 }
2445
2446 // TCP�Z�b�V�������N���[�Y�����������Aknown_hosts�_�C�A���O���������������w�����o���B
2447 // HOSTS_notify_disconnecting()�����������A�_�C�A���O���������������A
2448 // SSH�T�[�o�����m���o�������B
2449 void HOSTS_notify_closing_on_exit(PTInstVar pvar)
2450 {
2451 if (pvar->hosts_state.hosts_dialog != NULL) {
2452 logprintf(LOG_LEVEL_INFO, "%s: Notify closing message to the known_hosts dialog.", __FUNCTION__);
2453 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCLOSE, 0);
2454 }
2455 }
2456
2457 void HOSTS_end(PTInstVar pvar)
2458 {
2459 int i;
2460
2461 free(pvar->hosts_state.prefetched_hostname);
2462 key_init(&pvar->hosts_state.hostkey);
2463
2464 if (pvar->hosts_state.file_names != NULL) {
2465 for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {
2466 free(pvar->hosts_state.file_names[i]);
2467 }
2468 free(pvar->hosts_state.file_names);
2469 }
2470 }
2471
2472 /* vim: set ts=4 sw=4 ff=dos : */

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