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 8542 - (show annotations) (download) (as text)
Sun Feb 16 14:55:30 2020 UTC (4 years, 1 month ago) by zmatsuo
File MIME type: text/x-csrc
File size: 68385 byte(s)
ttxsshの鍵確認ダイアログの文字化けしないようにした

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

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