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 4542 - (show annotations) (download) (as text)
Wed Jul 27 14:25:26 2011 UTC (12 years, 8 months ago) by doda
File MIME type: text/x-csrc
File size: 51743 byte(s)
/nosecuritywarning 時は SSHFP 検証をしても無駄なので、検証するタイミングを変更。

1 /*
2 Copyright (c) 1998-2001, Robert O'Callahan
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 Redistributions of source code must retain the above copyright notice, this list of
9 conditions and the following disclaimer.
10
11 Redistributions in binary form must reproduce the above copyright notice, this list
12 of conditions and the following disclaimer in the documentation and/or other materials
13 provided with the distribution.
14
15 The name of Robert O'Callahan may not be used to endorse or promote products derived from
16 this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21 THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /*
30 This code is copyright (C) 1998-1999 Robert O'Callahan.
31 See LICENSE.TXT for the license.
32 */
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
42 #include <openssl/bn.h>
43 #include <openssl/evp.h>
44 #include <openssl/rsa.h>
45 #include <openssl/dsa.h>
46
47 #include <fcntl.h>
48 #include <io.h>
49 #include <errno.h>
50 #include <sys/stat.h>
51 #include <direct.h>
52 #include <memory.h>
53
54 #include <windns.h>
55
56 static HFONT DlgHostsAddFont;
57 static HFONT DlgHostsReplaceFont;
58
59 // BASE64�\���������i��������'='�����������������j
60 static char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
61
62
63 // �z�X�g�L�[�������� (2006.3.21 yutaka)
64 static void init_hostkey(Key *key)
65 {
66 key->type = KEY_UNSPEC;
67
68 // SSH1
69 key->bits = 0;
70 if (key->exp != NULL) {
71 free(key->exp);
72 key->exp = NULL;
73 }
74 if (key->mod != NULL) {
75 free(key->mod);
76 key->mod = NULL;
77 }
78
79 // SSH2
80 if (key->dsa != NULL) {
81 DSA_free(key->dsa);
82 key->dsa = NULL;
83 }
84 if (key->rsa != NULL) {
85 RSA_free(key->rsa);
86 key->rsa = NULL;
87 }
88 if (key->ecdsa != NULL) {
89 EC_KEY_free(key->ecdsa);
90 key->ecdsa = NULL;
91 }
92 }
93
94
95 static char FAR *FAR * parse_multi_path(char FAR * buf)
96 {
97 int i;
98 int ch;
99 int num_paths = 1;
100 char FAR *FAR * result;
101 int last_path_index;
102
103 for (i = 0; (ch = buf[i]) != 0; i++) {
104 if (ch == ';') {
105 num_paths++;
106 }
107 }
108
109 result =
110 (char FAR * FAR *) malloc(sizeof(char FAR *) * (num_paths + 1));
111
112 last_path_index = 0;
113 num_paths = 0;
114 for (i = 0; (ch = buf[i]) != 0; i++) {
115 if (ch == ';') {
116 buf[i] = 0;
117 result[num_paths] = _strdup(buf + last_path_index);
118 num_paths++;
119 buf[i] = ch;
120 last_path_index = i + 1;
121 }
122 }
123 if (i > last_path_index) {
124 result[num_paths] = _strdup(buf + last_path_index);
125 num_paths++;
126 }
127 result[num_paths] = NULL;
128 return result;
129 }
130
131 void HOSTS_init(PTInstVar pvar)
132 {
133 pvar->hosts_state.prefetched_hostname = NULL;
134 init_hostkey(&pvar->hosts_state.hostkey);
135 pvar->hosts_state.hosts_dialog = NULL;
136 pvar->hosts_state.file_names = NULL;
137 }
138
139 void HOSTS_open(PTInstVar pvar)
140 {
141 pvar->hosts_state.file_names =
142 parse_multi_path(pvar->session_settings.KnownHostsFiles);
143 }
144
145 //
146 // known_hosts�t�@�C�������e�������� pvar->hosts_state.file_data ����������
147 //
148 static int begin_read_file(PTInstVar pvar, char FAR * name,
149 int suppress_errors)
150 {
151 int fd;
152 int length;
153 int amount_read;
154 char buf[2048];
155
156 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
157 fd = _open(buf, _O_RDONLY | _O_SEQUENTIAL | _O_BINARY);
158 if (fd == -1) {
159 if (!suppress_errors) {
160 if (errno == ENOENT) {
161 UTIL_get_lang_msg("MSG_HOSTS_READ_ENOENT_ERROR", pvar,
162 "An error occurred while trying to read a known_hosts file.\n"
163 "The specified filename does not exist.");
164 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
165 } else {
166 UTIL_get_lang_msg("MSG_HOSTS_READ_ERROR", pvar,
167 "An error occurred while trying to read a known_hosts file.");
168 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
169 }
170 }
171 return 0;
172 }
173
174 length = (int) _lseek(fd, 0, SEEK_END);
175 _lseek(fd, 0, SEEK_SET);
176
177 if (length >= 0 && length < 0x7FFFFFFF) {
178 pvar->hosts_state.file_data = malloc(length + 1);
179 if (pvar->hosts_state.file_data == NULL) {
180 if (!suppress_errors) {
181 UTIL_get_lang_msg("MSG_HOSTS_ALLOC_ERROR", pvar,
182 "Memory ran out while trying to allocate space to read a known_hosts file.");
183 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
184 }
185 _close(fd);
186 return 0;
187 }
188 } else {
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 _close(fd);
195 return 0;
196 }
197
198 amount_read = _read(fd, pvar->hosts_state.file_data, length);
199 pvar->hosts_state.file_data[length] = 0;
200
201 _close(fd);
202
203 if (amount_read != length) {
204 if (!suppress_errors) {
205 UTIL_get_lang_msg("MSG_HOSTS_READ_ERROR", pvar,
206 "An error occurred while trying to read a known_hosts file.");
207 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
208 }
209 free(pvar->hosts_state.file_data);
210 pvar->hosts_state.file_data = NULL;
211 return 0;
212 } else {
213 return 1;
214 }
215 }
216
217 static int end_read_file(PTInstVar pvar, int suppress_errors)
218 {
219 free(pvar->hosts_state.file_data);
220 pvar->hosts_state.file_data = NULL;
221 return 1;
222 }
223
224 static int begin_read_host_files(PTInstVar pvar, int suppress_errors)
225 {
226 pvar->hosts_state.file_num = 0;
227 pvar->hosts_state.file_data = NULL;
228 return 1;
229 }
230
231 // MIME64�����������X�L�b�v����
232 static int eat_base64(char FAR * data)
233 {
234 int index = 0;
235 int ch;
236
237 for (;;) {
238 ch = data[index];
239 if (ch == '=' || strchr(base64, ch)) {
240 // BASE64���\�������������������� index ���i����
241 index++;
242 } else {
243 break;
244 }
245 }
246
247 return index;
248 }
249
250 static int eat_spaces(char FAR * data)
251 {
252 int index = 0;
253 int ch;
254
255 while ((ch = data[index]) == ' ' || ch == '\t') {
256 index++;
257 }
258 return index;
259 }
260
261 static int eat_digits(char FAR * data)
262 {
263 int index = 0;
264 int ch;
265
266 while ((ch = data[index]) >= '0' && ch <= '9') {
267 index++;
268 }
269 return index;
270 }
271
272 static int eat_to_end_of_line(char FAR * data)
273 {
274 int index = 0;
275 int ch;
276
277 while ((ch = data[index]) != '\n' && ch != '\r' && ch != 0) {
278 index++;
279 }
280
281 while ((ch = data[index]) == '\n' || ch == '\r') {
282 index++;
283 }
284
285 return index;
286 }
287
288 static int eat_to_end_of_pattern(char FAR * data)
289 {
290 int index = 0;
291 int ch;
292
293 while (ch = data[index], is_pattern_char(ch)) {
294 index++;
295 }
296
297 return index;
298 }
299
300 //
301 // BASE64�f�R�[�h�������s���B(rfc1521)
302 // src�o�b�t�@�� null-terminate ���������K�v�����B
303 //
304 static int uudecode(unsigned char *src, int srclen, unsigned char *target, int targsize)
305 {
306 char pad = '=';
307 int tarindex, state, ch;
308 char *pos;
309
310 state = 0;
311 tarindex = 0;
312
313 while ((ch = *src++) != '\0') {
314 if (isspace(ch)) /* Skip whitespace anywhere. */
315 continue;
316
317 if (ch == pad)
318 break;
319
320 pos = strchr(base64, ch);
321 if (pos == 0) /* A non-base64 character. */
322 return (-1);
323
324 switch (state) {
325 case 0:
326 if (target) {
327 if (tarindex >= targsize)
328 return (-1);
329 target[tarindex] = (pos - base64) << 2;
330 }
331 state = 1;
332 break;
333 case 1:
334 if (target) {
335 if (tarindex + 1 >= targsize)
336 return (-1);
337 target[tarindex] |= (pos - base64) >> 4;
338 target[tarindex+1] = ((pos - base64) & 0x0f) << 4 ;
339 }
340 tarindex++;
341 state = 2;
342 break;
343 case 2:
344 if (target) {
345 if (tarindex + 1 >= targsize)
346 return (-1);
347 target[tarindex] |= (pos - base64) >> 2;
348 target[tarindex+1] = ((pos - base64) & 0x03) << 6;
349 }
350 tarindex++;
351 state = 3;
352 break;
353 case 3:
354 if (target) {
355 if (tarindex >= targsize)
356 return (-1);
357 target[tarindex] |= (pos - base64);
358 }
359 tarindex++;
360 state = 0;
361 break;
362 }
363 }
364
365 /*
366 * We are done decoding Base-64 chars. Let's see if we ended
367 * on a byte boundary, and/or with erroneous trailing characters.
368 */
369
370 if (ch == pad) { /* We got a pad char. */
371 ch = *src++; /* Skip it, get next. */
372 switch (state) {
373 case 0: /* Invalid = in first position */
374 case 1: /* Invalid = in second position */
375 return (-1);
376
377 case 2: /* Valid, means one byte of info */
378 /* Skip any number of spaces. */
379 for (; ch != '\0'; ch = *src++)
380 if (!isspace(ch))
381 break;
382 /* Make sure there is another trailing = sign. */
383 if (ch != pad)
384 return (-1);
385 ch = *src++; /* Skip the = */
386 /* Fall through to "single trailing =" case. */
387 /* FALLTHROUGH */
388
389 case 3: /* Valid, means two bytes of info */
390 /*
391 * We know this char is an =. Is there anything but
392 * whitespace after it?
393 */
394 for (; ch != '\0'; ch = *src++)
395 if (!isspace(ch))
396 return (-1);
397
398 /*
399 * Now make sure for cases 2 and 3 that the "extra"
400 * bits that slopped past the last full byte were
401 * zeros. If we don't check them, they become a
402 * subliminal channel.
403 */
404 if (target && target[tarindex] != 0)
405 return (-1);
406 }
407 } else {
408 /*
409 * We ended by seeing the end of the string. Make sure we
410 * have no partial bytes lying around.
411 */
412 if (state != 0)
413 return (-1);
414 }
415
416 return (tarindex);
417 }
418
419
420 // SSH2���� BASE64 �`�����i�[����������
421 static Key *parse_uudecode(char *data)
422 {
423 int count;
424 unsigned char *blob = NULL;
425 int len, n;
426 Key *key = NULL;
427 char ch;
428
429 // BASE64���������T�C�Y������
430 count = eat_base64(data);
431 len = 2 * count;
432 blob = malloc(len);
433 if (blob == NULL)
434 goto error;
435
436 // BASE64�f�R�[�h
437 ch = data[count];
438 data[count] = '\0'; // ���������s�R�[�h������������������������������������
439 n = uudecode(data, count, blob, len);
440 data[count] = ch;
441 if (n < 0) {
442 goto error;
443 }
444
445 key = key_from_blob(blob, n);
446 if (key == NULL)
447 goto error;
448
449 error:
450 if (blob != NULL)
451 free(blob);
452
453 return (key);
454 }
455
456
457 static char FAR *parse_bignum(char FAR * data)
458 {
459 uint32 digits = 0;
460 BIGNUM *num = BN_new();
461 BIGNUM *billion = BN_new();
462 BIGNUM *digits_num = BN_new();
463 BN_CTX *ctx = BN_CTX_new();
464 char FAR *result;
465 int ch;
466 int leftover_digits = 1;
467
468 BN_CTX_init(ctx);
469 BN_set_word(num, 0);
470 BN_set_word(billion, 1000000000L);
471
472 while ((ch = *data) >= '0' && ch <= '9') {
473 if (leftover_digits == 1000000000L) {
474 BN_set_word(digits_num, digits);
475 BN_mul(num, num, billion, ctx);
476 BN_add(num, num, digits_num);
477 leftover_digits = 1;
478 digits = 0;
479 }
480
481 digits = digits * 10 + ch - '0';
482 leftover_digits *= 10;
483 data++;
484 }
485
486 BN_set_word(digits_num, digits);
487 BN_set_word(billion, leftover_digits);
488 BN_mul(num, num, billion, ctx);
489 BN_add(num, num, digits_num);
490
491 result = (char FAR *) malloc(2 + BN_num_bytes(num));
492 set_ushort16_MSBfirst(result, BN_num_bits(num));
493 BN_bn2bin(num, result + 2);
494
495 BN_CTX_free(ctx);
496 BN_free(digits_num);
497 BN_free(num);
498 BN_free(billion);
499
500 return result;
501 }
502
503 //
504 // known_hosts�t�@�C�������e���������A�w�������z�X�g�����J�����T���B
505 //
506 static int check_host_key(PTInstVar pvar, char FAR * hostname,
507 unsigned short tcpport, char FAR * data)
508 {
509 int index = eat_spaces(data);
510 int matched = 0;
511 int keybits = 0;
512
513 if (data[index] == '#') {
514 return index + eat_to_end_of_line(data + index);
515 }
516
517 /* if we find an empty line, then it won't have any patterns matching the hostname
518 and so we skip it */
519 index--;
520 do {
521 int negated;
522 int bracketed;
523 char *end_bracket;
524 int host_matched = 0;
525 unsigned short keyfile_port = 22;
526
527 index++;
528 negated = data[index] == '!';
529
530 if (negated) {
531 index++;
532 bracketed = data[index] == '[';
533 if (bracketed) {
534 end_bracket = strstr(data + index + 1, "]:");
535 if (end_bracket != NULL) {
536 *end_bracket = ' ';
537 index++;
538 }
539 }
540 host_matched = match_pattern(data + index, hostname);
541 if (bracketed && end_bracket != NULL) {
542 *end_bracket = ']';
543 keyfile_port = atoi(end_bracket + 2);
544 }
545 if (host_matched && keyfile_port == tcpport) {
546 return index + eat_to_end_of_line(data + index);
547 }
548 } else {
549 bracketed = data[index] == '[';
550 if (bracketed) {
551 end_bracket = strstr(data + index + 1, "]:");
552 if (end_bracket != NULL) {
553 *end_bracket = ' ';
554 index++;
555 }
556 }
557 host_matched = match_pattern(data + index, hostname);
558 if (bracketed && end_bracket != NULL) {
559 *end_bracket = ']';
560 keyfile_port = atoi(end_bracket + 2);
561 }
562 if (host_matched && keyfile_port == tcpport) {
563 matched = 1;
564 }
565 }
566
567 index += eat_to_end_of_pattern(data + index);
568 } while (data[index] == ',');
569
570 if (!matched) {
571 return index + eat_to_end_of_line(data + index);
572 } else {
573 // ���������������t�H�[�}�b�g��������
574 // �����A���������v�����G���g�����������������������B
575 /*
576 [SSH1]
577 192.168.1.2 1024 35 13032....
578
579 [SSH2]
580 192.168.1.2 ssh-rsa AAAAB3NzaC1....
581 192.168.1.2 ssh-dss AAAAB3NzaC1....
582 192.168.1.2 rsa AAAAB3NzaC1....
583 192.168.1.2 dsa AAAAB3NzaC1....
584 192.168.1.2 rsa1 AAAAB3NzaC1....
585 */
586 int rsa1_key_bits;
587
588 index += eat_spaces(data + index);
589
590 rsa1_key_bits = atoi(data + index);
591 if (rsa1_key_bits > 0) { // RSA1������
592 if (!SSHv1(pvar)) { // SSH2��������������������
593 return index + eat_to_end_of_line(data + index);
594 }
595
596 pvar->hosts_state.hostkey.type = KEY_RSA1;
597
598 pvar->hosts_state.hostkey.bits = rsa1_key_bits;
599 index += eat_digits(data + index);
600 index += eat_spaces(data + index);
601
602 pvar->hosts_state.hostkey.exp = parse_bignum(data + index);
603 index += eat_digits(data + index);
604 index += eat_spaces(data + index);
605
606 pvar->hosts_state.hostkey.mod = parse_bignum(data + index);
607
608 /*
609 if (pvar->hosts_state.key_bits < 0
610 || pvar->hosts_state.key_exp == NULL
611 || pvar->hosts_state.key_mod == NULL) {
612 pvar->hosts_state.key_bits = 0;
613 free(pvar->hosts_state.key_exp);
614 free(pvar->hosts_state.key_mod);
615 }*/
616
617 } else {
618 char *cp, *p;
619 Key *key;
620
621 if (!SSHv2(pvar)) { // SSH1��������������������
622 return index + eat_to_end_of_line(data + index);
623 }
624
625 cp = data + index;
626 p = strchr(cp, ' ');
627 if (p == NULL) {
628 return index + eat_to_end_of_line(data + index);
629 }
630 index += (p - cp); // setup index
631 *p = '\0';
632 pvar->hosts_state.hostkey.type = get_keytype_from_name(cp);
633 *p = ' ';
634
635 index += eat_spaces(data + index); // update index
636
637 // uudecode
638 key = parse_uudecode(data + index);
639 if (key == NULL) {
640 return index + eat_to_end_of_line(data + index);
641 }
642
643 // setup
644 pvar->hosts_state.hostkey.type = key->type;
645 pvar->hosts_state.hostkey.dsa = key->dsa;
646 pvar->hosts_state.hostkey.rsa = key->rsa;
647 pvar->hosts_state.hostkey.ecdsa = key->ecdsa;
648
649 index += eat_base64(data + index);
650 index += eat_spaces(data + index);
651
652 // Key�\�������g���������� (2008.3.2 yutaka)
653 free(key);
654 }
655
656 return index + eat_to_end_of_line(data + index);
657 }
658 }
659
660 //
661 // known_hosts�t�@�C�������z�X�g�������v�����s������
662 //
663 static int read_host_key(PTInstVar pvar,
664 char FAR * hostname, unsigned short tcpport,
665 int suppress_errors, int return_always)
666 {
667 int i;
668 int while_flg;
669
670 for (i = 0; hostname[i] != 0; i++) {
671 int ch = hostname[i];
672
673 if (!is_pattern_char(ch) || ch == '*' || ch == '?') {
674 if (!suppress_errors) {
675 UTIL_get_lang_msg("MSG_HOSTS_HOSTNAME_INVALID_ERROR", pvar,
676 "The host name contains an invalid character.\n"
677 "This session will be terminated.");
678 notify_fatal_error(pvar, pvar->ts->UIMsg);
679 }
680 return 0;
681 }
682 }
683
684 if (i == 0) {
685 if (!suppress_errors) {
686 UTIL_get_lang_msg("MSG_HOSTS_HOSTNAME_EMPTY_ERROR", pvar,
687 "The host name should not be empty.\n"
688 "This session will be terminated.");
689 notify_fatal_error(pvar, pvar->ts->UIMsg);
690 }
691 return 0;
692 }
693
694 // hostkey type is KEY_UNSPEC.
695 init_hostkey(&pvar->hosts_state.hostkey);
696
697 do {
698 if (pvar->hosts_state.file_data == NULL
699 || pvar->hosts_state.file_data[pvar->hosts_state.file_data_index] == 0) {
700 char FAR *filename;
701 int keep_going = 1;
702
703 if (pvar->hosts_state.file_data != NULL) {
704 end_read_file(pvar, suppress_errors);
705 }
706
707 do {
708 filename =
709 pvar->hosts_state.file_names[pvar->hosts_state.file_num];
710
711 if (filename == NULL) {
712 return 1;
713 } else {
714 pvar->hosts_state.file_num++;
715
716 if (filename[0] != 0) {
717 if (begin_read_file(pvar, filename, suppress_errors)) {
718 pvar->hosts_state.file_data_index = 0;
719 keep_going = 0;
720 }
721 }
722 }
723 } while (keep_going);
724 }
725
726 pvar->hosts_state.file_data_index +=
727 check_host_key(pvar, hostname, tcpport,
728 pvar->hosts_state.file_data +
729 pvar->hosts_state.file_data_index);
730
731 if (!return_always) {
732 // �L�����L�[��������������
733 while_flg = (pvar->hosts_state.hostkey.type == KEY_UNSPEC);
734 }
735 else {
736 while_flg = 0;
737 }
738 } while (while_flg);
739
740 return 1;
741 }
742
743 static void finish_read_host_files(PTInstVar pvar, int suppress_errors)
744 {
745 if (pvar->hosts_state.file_data != NULL) {
746 end_read_file(pvar, suppress_errors);
747 }
748 }
749
750 // �T�[�o�����������O���Aknown_hosts�t�@�C�������z�X�g���J�������������������B
751 void HOSTS_prefetch_host_key(PTInstVar pvar, char FAR * hostname, unsigned short tcpport)
752 {
753 if (!begin_read_host_files(pvar, 1)) {
754 return;
755 }
756
757 if (!read_host_key(pvar, hostname, tcpport, 1, 0)) {
758 return;
759 }
760
761 free(pvar->hosts_state.prefetched_hostname);
762 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
763
764 finish_read_host_files(pvar, 1);
765 }
766
767 static BOOL equal_mp_ints(unsigned char FAR * num1,
768 unsigned char FAR * num2)
769 {
770 if (num1 == NULL || num2 == NULL) {
771 return FALSE;
772 } else {
773 uint32 bytes = (get_ushort16_MSBfirst(num1) + 7) / 8;
774
775 if (bytes != (get_ushort16_MSBfirst(num2) + 7) / 8) {
776 return FALSE; /* different byte lengths */
777 } else {
778 return memcmp(num1 + 2, num2 + 2, bytes) == 0;
779 }
780 }
781 }
782
783 // ���J����������������������
784 // -1 ... �����^������
785 // 0 ... ����������
786 // 1 ... ������
787 static int match_key(PTInstVar pvar, Key *key)
788 {
789 int bits;
790 unsigned char FAR * exp;
791 unsigned char FAR * mod;
792 const EC_GROUP *group;
793 const EC_POINT *pa, *pb;
794
795 if (pvar->hosts_state.hostkey.type != key->type) {
796 return -1;
797 }
798
799 switch (key->type) {
800 case KEY_RSA1: // SSH1 host public key
801 bits = key->bits;
802 exp = key->exp;
803 mod = key->mod;
804
805 /* just check for equal exponent and modulus */
806 return equal_mp_ints(exp, pvar->hosts_state.hostkey.exp)
807 && equal_mp_ints(mod, pvar->hosts_state.hostkey.mod);
808 /*
809 return equal_mp_ints(exp, pvar->hosts_state.key_exp)
810 && equal_mp_ints(mod, pvar->hosts_state.key_mod);
811 */
812
813 case KEY_RSA: // SSH2 RSA host public key
814 return key->rsa != NULL && pvar->hosts_state.hostkey.rsa != NULL &&
815 BN_cmp(key->rsa->e, pvar->hosts_state.hostkey.rsa->e) == 0 &&
816 BN_cmp(key->rsa->n, pvar->hosts_state.hostkey.rsa->n) == 0;
817
818 case KEY_DSA: // SSH2 DSA host public key
819 return key->dsa != NULL && pvar->hosts_state.hostkey.dsa &&
820 BN_cmp(key->dsa->p, pvar->hosts_state.hostkey.dsa->p) == 0 &&
821 BN_cmp(key->dsa->q, pvar->hosts_state.hostkey.dsa->q) == 0 &&
822 BN_cmp(key->dsa->g, pvar->hosts_state.hostkey.dsa->g) == 0 &&
823 BN_cmp(key->dsa->pub_key, pvar->hosts_state.hostkey.dsa->pub_key) == 0;
824
825 case KEY_ECDSA256:
826 case KEY_ECDSA384:
827 case KEY_ECDSA521:
828 if (key->ecdsa == NULL || pvar->hosts_state.hostkey.ecdsa == NULL) {
829 return FALSE;
830 }
831 group = EC_KEY_get0_group(key->ecdsa);
832 pa = EC_KEY_get0_public_key(key->ecdsa),
833 pb = EC_KEY_get0_public_key(pvar->hosts_state.hostkey.ecdsa);
834 return EC_POINT_cmp(group, pa, pb, NULL) == 0;
835
836 default:
837 return FALSE;
838 }
839
840 }
841
842 static void init_hosts_dlg(PTInstVar pvar, HWND dlg)
843 {
844 char buf[1024];
845 char buf2[2048];
846 int i, j;
847 int ch;
848 char *fp = NULL;
849
850 // static text�� # �������z�X�g�����u������
851 GetDlgItemText(dlg, IDC_HOSTWARNING, buf, sizeof(buf));
852 for (i = 0; (ch = buf[i]) != 0 && ch != '#'; i++) {
853 buf2[i] = ch;
854 }
855 strncpy_s(buf2 + i, sizeof(buf2) - i,
856 pvar->hosts_state.prefetched_hostname, _TRUNCATE);
857 j = i + strlen(buf2 + i);
858 for (; buf[i] == '#'; i++) {
859 }
860 strncpy_s(buf2 + j, sizeof(buf2) - j, buf + i, _TRUNCATE);
861
862 SetDlgItemText(dlg, IDC_HOSTWARNING, buf2);
863
864 // fingerprint����������
865 fp = key_fingerprint(&pvar->hosts_state.hostkey, SSH_FP_HEX);
866 SendMessage(GetDlgItem(dlg, IDC_FINGER_PRINT), WM_SETTEXT, 0, (LPARAM)fp);
867 free(fp);
868
869 // �r�W���A����fingerprint���\������
870 fp = key_fingerprint(&pvar->hosts_state.hostkey, SSH_FP_RANDOMART);
871 SendMessage(GetDlgItem(dlg, IDC_FP_RANDOMART), WM_SETTEXT, 0, (LPARAM)fp);
872 SendMessage(GetDlgItem(dlg, IDC_FP_RANDOMART), WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), TRUE);
873 free(fp);
874 }
875
876 static int print_mp_int(char FAR * buf, unsigned char FAR * mp)
877 {
878 int i = 0, j, k;
879 BIGNUM *num = BN_new();
880 int ch;
881
882 BN_bin2bn(mp + 2, (get_ushort16_MSBfirst(mp) + 7) / 8, num);
883
884 do {
885 buf[i] = (char) ((BN_div_word(num, 10)) + '0');
886 i++;
887 } while (!BN_is_zero(num));
888
889 /* we need to reverse the digits */
890 for (j = 0, k = i - 1; j < k; j++, k--) {
891 ch = buf[j];
892 buf[j] = buf[k];
893 buf[k] = ch;
894 }
895
896 buf[i] = 0;
897 return i;
898 }
899
900 //
901 // known_hosts �t�@�C�������������G���g�������������B
902 //
903 static char FAR *format_host_key(PTInstVar pvar)
904 {
905 int host_len = strlen(pvar->hosts_state.prefetched_hostname);
906 char *result = NULL;
907 int index;
908 ssh_keytype type = pvar->hosts_state.hostkey.type;
909
910 switch (type) {
911 case KEY_RSA1:
912 {
913 int result_len = host_len + 50 + 8 +
914 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.exp) / 3 +
915 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.mod) / 3;
916 result = (char FAR *) malloc(result_len);
917
918 if (pvar->ssh_state.tcpport == 22) {
919 strncpy_s(result, result_len, pvar->hosts_state.prefetched_hostname, _TRUNCATE);
920 index = host_len;
921 }
922 else {
923 _snprintf_s(result, result_len, _TRUNCATE, "[%s]:%d",
924 pvar->hosts_state.prefetched_hostname,
925 pvar->ssh_state.tcpport);
926 index = strlen(result);
927 }
928
929 _snprintf_s(result + index, result_len - host_len, _TRUNCATE,
930 " %d ", pvar->hosts_state.hostkey.bits);
931 index += strlen(result + index);
932 index += print_mp_int(result + index, pvar->hosts_state.hostkey.exp);
933 result[index] = ' ';
934 index++;
935 index += print_mp_int(result + index, pvar->hosts_state.hostkey.mod);
936 strncpy_s(result + index, result_len - index, " \r\n", _TRUNCATE);
937
938 break;
939 }
940
941 case KEY_RSA:
942 case KEY_DSA:
943 case KEY_ECDSA256:
944 case KEY_ECDSA384:
945 case KEY_ECDSA521:
946 {
947 Key *key = &pvar->hosts_state.hostkey;
948 char *blob = NULL;
949 int blen, uulen, msize;
950 char *uu = NULL;
951 int n;
952
953 key_to_blob(key, &blob, &blen);
954 uulen = 2 * blen;
955 uu = malloc(uulen);
956 if (uu == NULL) {
957 goto error;
958 }
959 n = uuencode(blob, blen, uu, uulen);
960 if (n > 0) {
961 msize = host_len + 50 + uulen;
962 result = malloc(msize);
963 if (result == NULL) {
964 goto error;
965 }
966
967 // setup
968 if (pvar->ssh_state.tcpport == 22) {
969 _snprintf_s(result, msize, _TRUNCATE, "%s %s %s\r\n",
970 pvar->hosts_state.prefetched_hostname,
971 get_sshname_from_key(key),
972 uu);
973 } else {
974 _snprintf_s(result, msize, _TRUNCATE, "[%s]:%d %s %s\r\n",
975 pvar->hosts_state.prefetched_hostname,
976 pvar->ssh_state.tcpport,
977 get_sshname_from_key(key),
978 uu);
979 }
980 }
981 error:
982 if (blob != NULL)
983 free(blob);
984 if (uu != NULL)
985 free(uu);
986
987 break;
988 }
989
990 default:
991 return NULL;
992
993 }
994
995 return result;
996 }
997
998 static void add_host_key(PTInstVar pvar)
999 {
1000 char FAR *name = NULL;
1001
1002 if ( pvar->hosts_state.file_names != NULL)
1003 name = pvar->hosts_state.file_names[0];
1004
1005 if (name == NULL || name[0] == 0) {
1006 UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar,
1007 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
1008 "Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
1009 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1010 } else {
1011 char FAR *keydata = format_host_key(pvar);
1012 int length = strlen(keydata);
1013 int fd;
1014 int amount_written;
1015 int close_result;
1016 char buf[FILENAME_MAX];
1017
1018 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
1019 fd = _open(buf,
1020 _O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY,
1021 _S_IREAD | _S_IWRITE);
1022 if (fd == -1) {
1023 if (errno == EACCES) {
1024 UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar,
1025 "An error occurred while trying to write the host key.\n"
1026 "You do not have permission to write to the known-hosts file.");
1027 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1028 } else {
1029 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1030 "An error occurred while trying to write the host key.\n"
1031 "The host key could not be written.");
1032 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1033 }
1034 return;
1035 }
1036
1037 amount_written = _write(fd, keydata, length);
1038 free(keydata);
1039 close_result = _close(fd);
1040
1041 if (amount_written != length || close_result == -1) {
1042 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1043 "An error occurred while trying to write the host key.\n"
1044 "The host key could not be written.");
1045 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1046 }
1047 }
1048 }
1049
1050 static char FAR *copy_mp_int(char FAR * num)
1051 {
1052 int len = (get_ushort16_MSBfirst(num) + 7) / 8 + 2;
1053 char FAR *result = (char FAR *) malloc(len);
1054
1055 if (result != NULL) {
1056 memcpy(result, num, len);
1057 }
1058
1059 return result;
1060 }
1061
1062 //
1063 // �����z�X�g�����e���������L�[����������
1064 // add_host_key ����������������
1065 //
1066 static void delete_different_key(PTInstVar pvar)
1067 {
1068 char FAR *name = pvar->hosts_state.file_names[0];
1069
1070 if (name == NULL || name[0] == 0) {
1071 UTIL_get_lang_msg("MSG_HOSTS_FILE_UNSPECIFY_ERROR", pvar,
1072 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
1073 "Restart Tera Term and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
1074 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1075 }
1076 else {
1077 Key key; // ���������z�X�g���L�[
1078 int length;
1079 char filename[MAX_PATH];
1080 char tmp[L_tmpnam];
1081 int fd;
1082 int amount_written = 0;
1083 int close_result;
1084 int data_index = 0;
1085 char buf[FILENAME_MAX];
1086
1087 // �������������t�@�C�����J��
1088 _getcwd(filename, sizeof(filename));
1089 tmpnam_s(tmp,sizeof(tmp));
1090 strcat_s(filename, sizeof(filename), tmp);
1091 fd = _open(filename,
1092 _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY | _O_TRUNC,
1093 _S_IREAD | _S_IWRITE);
1094
1095 if (fd == -1) {
1096 if (errno == EACCES) {
1097 UTIL_get_lang_msg("MSG_HOSTS_WRITE_EACCES_ERROR", pvar,
1098 "An error occurred while trying to write the host key.\n"
1099 "You do not have permission to write to the known-hosts file.");
1100 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1101 } else {
1102 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1103 "An error occurred while trying to write the host key.\n"
1104 "The host key could not be written.");
1105 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1106 }
1107 return;
1108 }
1109
1110 // ���������T�[�o���L�[����������
1111 switch (pvar->hosts_state.hostkey.type) {
1112 case KEY_RSA1: // SSH1
1113 key.type = KEY_RSA1;
1114 key.bits = pvar->hosts_state.hostkey.bits;
1115 key.exp = copy_mp_int(pvar->hosts_state.hostkey.exp);
1116 key.mod = copy_mp_int(pvar->hosts_state.hostkey.mod);
1117 break;
1118 case KEY_RSA: // SSH2 RSA
1119 key.type = KEY_RSA;
1120 key.rsa = duplicate_RSA(pvar->hosts_state.hostkey.rsa);
1121 break;
1122 case KEY_DSA: // SSH2 DSA
1123 key.type = KEY_DSA;
1124 key.dsa = duplicate_DSA(pvar->hosts_state.hostkey.dsa);
1125 break;
1126 case KEY_ECDSA256:
1127 case KEY_ECDSA384:
1128 case KEY_ECDSA521:
1129 key.type = pvar->hosts_state.hostkey.type;
1130 key.ecdsa = EC_KEY_dup(pvar->hosts_state.hostkey.ecdsa);
1131 break;
1132 }
1133
1134 // �t�@�C��������������
1135 begin_read_host_files(pvar, 0);
1136 do {
1137 int host_index = 0;
1138 int matched = 0;
1139 int keybits = 0;
1140 char FAR *data;
1141 int do_write = 0;
1142 length = amount_written = 0;
1143
1144 if (!read_host_key(pvar, pvar->ssh_state.hostname, pvar->ssh_state.tcpport, 0, 1)) {
1145 break;
1146 }
1147
1148 if (data_index == pvar->hosts_state.file_data_index) {
1149 // index ���i������ == ��������������
1150 break;
1151 }
1152
1153 data = pvar->hosts_state.file_data + data_index;
1154 host_index = eat_spaces(data);
1155
1156 if (data[host_index] == '#') {
1157 do_write = 1;
1158 }
1159 else {
1160 // �z�X�g������
1161 host_index--;
1162 do {
1163 int negated;
1164 int bracketed;
1165 char *end_bracket;
1166 int host_matched = 0;
1167 unsigned short keyfile_port = 22;
1168
1169 host_index++;
1170 negated = data[host_index] == '!';
1171
1172 if (negated) {
1173 host_index++;
1174 bracketed = data[host_index] == '[';
1175 if (bracketed) {
1176 end_bracket = strstr(data + host_index + 1, "]:");
1177 if (end_bracket != NULL) {
1178 *end_bracket = ' ';
1179 host_index++;
1180 }
1181 }
1182 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1183 if (bracketed && end_bracket != NULL) {
1184 *end_bracket = ']';
1185 keyfile_port = atoi(end_bracket + 2);
1186 }
1187 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1188 matched = 0;
1189 // �����o�[�W�����`�F�b�N�������� host_index ���i��������������
1190 host_index--;
1191 do {
1192 host_index++;
1193 host_index += eat_to_end_of_pattern(data + host_index);
1194 } while (data[host_index] == ',');
1195 break;
1196 }
1197 }
1198 else {
1199 bracketed = data[host_index] == '[';
1200 if (bracketed) {
1201 end_bracket = strstr(data + host_index + 1, "]:");
1202 if (end_bracket != NULL) {
1203 *end_bracket = ' ';
1204 host_index++;
1205 }
1206 }
1207 host_matched = match_pattern(data + host_index, pvar->ssh_state.hostname);
1208 if (bracketed && end_bracket != NULL) {
1209 *end_bracket = ']';
1210 keyfile_port = atoi(end_bracket + 2);
1211 }
1212 if (host_matched && keyfile_port == pvar->ssh_state.tcpport) {
1213 matched = 1;
1214 }
1215 }
1216 host_index += eat_to_end_of_pattern(data + host_index);
1217 } while (data[host_index] == ',');
1218
1219 // �z�X�g������������
1220 if (!matched) {
1221 do_write = 1;
1222 }
1223 // �z�X�g��������
1224 else {
1225 // �����`�������� or ���v�����L�[
1226 if (match_key(pvar, &key) != 0) {
1227 do_write = 1;
1228 }
1229 // �����`�������������v�������L�[���X�L�b�v������
1230 }
1231 }
1232
1233 // ������������
1234 if (do_write) {
1235 length = pvar->hosts_state.file_data_index - data_index;
1236 amount_written =
1237 _write(fd, pvar->hosts_state.file_data + data_index,
1238 length);
1239
1240 if (amount_written != length) {
1241 goto error1;
1242 }
1243 }
1244 data_index = pvar->hosts_state.file_data_index;
1245 } while (1); // ������������
1246
1247 error1:
1248 close_result = _close(fd);
1249 if (amount_written != length || close_result == -1) {
1250 UTIL_get_lang_msg("MSG_HOSTS_WRITE_ERROR", pvar,
1251 "An error occurred while trying to write the host key.\n"
1252 "The host key could not be written.");
1253 notify_nonfatal_error(pvar, pvar->ts->UIMsg);
1254 goto error2;
1255 }
1256
1257 // �������������t�@�C���������l�[��
1258 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
1259 _unlink(buf);
1260 rename(filename, buf);
1261
1262 error2:
1263 _unlink(filename);
1264
1265 finish_read_host_files(pvar, 0);
1266 }
1267 }
1268
1269 //
1270 // Unknown host���z�X�g���J���� known_hosts �t�@�C����������������������
1271 // ���[�U���m�F�������B
1272 // TODO: finger print���\�����s���B
1273 // (2006.3.25 yutaka)
1274 //
1275 static BOOL CALLBACK hosts_add_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1276 LPARAM lParam)
1277 {
1278 PTInstVar pvar;
1279 LOGFONT logfont;
1280 HFONT font;
1281 char uimsg[MAX_UIMSG];
1282
1283 switch (msg) {
1284 case WM_INITDIALOG:
1285 pvar = (PTInstVar) lParam;
1286 pvar->hosts_state.hosts_dialog = dlg;
1287 SetWindowLong(dlg, DWL_USER, lParam);
1288
1289 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
1290 GetWindowText(dlg, uimsg, sizeof(uimsg));
1291 UTIL_get_lang_msg("DLG_UNKNONWHOST_TITLE", pvar, uimsg);
1292 SetWindowText(dlg, pvar->ts->UIMsg);
1293 GetDlgItemText(dlg, IDC_HOSTWARNING, uimsg, sizeof(uimsg));
1294 UTIL_get_lang_msg("DLG_UNKNOWNHOST_WARNING", pvar, uimsg);
1295 SetDlgItemText(dlg, IDC_HOSTWARNING, pvar->ts->UIMsg);
1296 GetDlgItemText(dlg, IDC_HOSTWARNING2, uimsg, sizeof(uimsg));
1297 UTIL_get_lang_msg("DLG_UNKNOWNHOST_WARNING2", pvar, uimsg);
1298 SetDlgItemText(dlg, IDC_HOSTWARNING2, pvar->ts->UIMsg);
1299 GetDlgItemText(dlg, IDC_HOSTFINGERPRINT, uimsg, sizeof(uimsg));
1300 UTIL_get_lang_msg("DLG_UNKNOWNHOST_FINGERPRINT", pvar, uimsg);
1301 SetDlgItemText(dlg, IDC_HOSTFINGERPRINT, pvar->ts->UIMsg);
1302 GetDlgItemText(dlg, IDC_ADDTOKNOWNHOSTS, uimsg, sizeof(uimsg));
1303 UTIL_get_lang_msg("DLG_UNKNOWNHOST_ADD", pvar, uimsg);
1304 SetDlgItemText(dlg, IDC_ADDTOKNOWNHOSTS, pvar->ts->UIMsg);
1305 GetDlgItemText(dlg, IDC_CONTINUE, uimsg, sizeof(uimsg));
1306 UTIL_get_lang_msg("BTN_CONTINUE", pvar, uimsg);
1307 SetDlgItemText(dlg, IDC_CONTINUE, pvar->ts->UIMsg);
1308 GetDlgItemText(dlg, IDCANCEL, uimsg, sizeof(uimsg));
1309 UTIL_get_lang_msg("BTN_DISCONNECT", pvar, uimsg);
1310 SetDlgItemText(dlg, IDCANCEL, pvar->ts->UIMsg);
1311
1312 init_hosts_dlg(pvar, dlg);
1313
1314 font = (HFONT)SendMessage(dlg, WM_GETFONT, 0, 0);
1315 GetObject(font, sizeof(LOGFONT), &logfont);
1316 if (UTIL_get_lang_font("DLG_TAHOMA_FONT", dlg, &logfont, &DlgHostsAddFont, pvar)) {
1317 SendDlgItemMessage(dlg, IDC_HOSTWARNING, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1318 SendDlgItemMessage(dlg, IDC_HOSTWARNING2, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1319 SendDlgItemMessage(dlg, IDC_HOSTFINGERPRINT, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1320 SendDlgItemMessage(dlg, IDC_FINGER_PRINT, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1321 SendDlgItemMessage(dlg, IDC_ADDTOKNOWNHOSTS, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1322 SendDlgItemMessage(dlg, IDC_CONTINUE, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1323 SendDlgItemMessage(dlg, IDCANCEL, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1324 }
1325 else {
1326 DlgHostsAddFont = NULL;
1327 }
1328
1329 // add host check box���`�F�b�N���f�t�H���g������������
1330 SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
1331
1332 return TRUE; /* because we do not set the focus */
1333
1334 case WM_COMMAND:
1335 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
1336
1337 switch (LOWORD(wParam)) {
1338 case IDC_CONTINUE:
1339 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1340 add_host_key(pvar);
1341 }
1342
1343 if (SSHv1(pvar)) {
1344 SSH_notify_host_OK(pvar);
1345 } else { // SSH2
1346 // SSH2���������� SSH_notify_host_OK() �������B
1347 }
1348
1349 pvar->hosts_state.hosts_dialog = NULL;
1350
1351 EndDialog(dlg, 1);
1352
1353 if (DlgHostsAddFont != NULL) {
1354 DeleteObject(DlgHostsAddFont);
1355 }
1356
1357 return TRUE;
1358
1359 case IDCANCEL: /* kill the connection */
1360 pvar->hosts_state.hosts_dialog = NULL;
1361 notify_closed_connection(pvar);
1362 EndDialog(dlg, 0);
1363
1364 if (DlgHostsAddFont != NULL) {
1365 DeleteObject(DlgHostsAddFont);
1366 }
1367
1368 return TRUE;
1369
1370 default:
1371 return FALSE;
1372 }
1373
1374 default:
1375 return FALSE;
1376 }
1377 }
1378
1379 //
1380 // �u�����������m�F�_�C�A���O������
1381 //
1382 static BOOL CALLBACK hosts_replace_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1383 LPARAM lParam)
1384 {
1385 PTInstVar pvar;
1386 LOGFONT logfont;
1387 HFONT font;
1388 char uimsg[MAX_UIMSG];
1389
1390 switch (msg) {
1391 case WM_INITDIALOG:
1392 pvar = (PTInstVar) lParam;
1393 pvar->hosts_state.hosts_dialog = dlg;
1394 SetWindowLong(dlg, DWL_USER, lParam);
1395
1396 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
1397 GetWindowText(dlg, uimsg, sizeof(uimsg));
1398 UTIL_get_lang_msg("DLG_DIFFERENTKEY_TITLE", pvar, uimsg);
1399 SetWindowText(dlg, pvar->ts->UIMsg);
1400 GetDlgItemText(dlg, IDC_HOSTWARNING, uimsg, sizeof(uimsg));
1401 UTIL_get_lang_msg("DLG_DIFFERENTKEY_WARNING", pvar, uimsg);
1402 SetDlgItemText(dlg, IDC_HOSTWARNING, pvar->ts->UIMsg);
1403 GetDlgItemText(dlg, IDC_HOSTWARNING2, uimsg, sizeof(uimsg));
1404 UTIL_get_lang_msg("DLG_DIFFERENTKEY_WARNING2", pvar, uimsg);
1405 SetDlgItemText(dlg, IDC_HOSTWARNING2, pvar->ts->UIMsg);
1406 GetDlgItemText(dlg, IDC_HOSTFINGERPRINT, uimsg, sizeof(uimsg));
1407 UTIL_get_lang_msg("DLG_DIFFERENTKEY_FINGERPRINT", pvar, uimsg);
1408 SetDlgItemText(dlg, IDC_HOSTFINGERPRINT, pvar->ts->UIMsg);
1409 GetDlgItemText(dlg, IDC_ADDTOKNOWNHOSTS, uimsg, sizeof(uimsg));
1410 UTIL_get_lang_msg("DLG_DIFFERENTKEY_REPLACE", pvar, uimsg);
1411 SetDlgItemText(dlg, IDC_ADDTOKNOWNHOSTS, pvar->ts->UIMsg);
1412 GetDlgItemText(dlg, IDC_CONTINUE, uimsg, sizeof(uimsg));
1413 UTIL_get_lang_msg("BTN_CONTINUE", pvar, uimsg);
1414 SetDlgItemText(dlg, IDC_CONTINUE, pvar->ts->UIMsg);
1415 GetDlgItemText(dlg, IDCANCEL, uimsg, sizeof(uimsg));
1416 UTIL_get_lang_msg("BTN_DISCONNECT", pvar, uimsg);
1417 SetDlgItemText(dlg, IDCANCEL, pvar->ts->UIMsg);
1418
1419 init_hosts_dlg(pvar, dlg);
1420
1421 font = (HFONT)SendMessage(dlg, WM_GETFONT, 0, 0);
1422 GetObject(font, sizeof(LOGFONT), &logfont);
1423 if (UTIL_get_lang_font("DLG_TAHOMA_FONT", dlg, &logfont, &DlgHostsReplaceFont, pvar)) {
1424 SendDlgItemMessage(dlg, IDC_HOSTWARNING, WM_SETFONT, (WPARAM)DlgHostsReplaceFont, MAKELPARAM(TRUE,0));
1425 SendDlgItemMessage(dlg, IDC_HOSTWARNING2, WM_SETFONT, (WPARAM)DlgHostsReplaceFont, MAKELPARAM(TRUE,0));
1426 SendDlgItemMessage(dlg, IDC_HOSTFINGERPRINT, WM_SETFONT, (WPARAM)DlgHostsReplaceFont, MAKELPARAM(TRUE,0));
1427 SendDlgItemMessage(dlg, IDC_ADDTOKNOWNHOSTS, WM_SETFONT, (WPARAM)DlgHostsReplaceFont, MAKELPARAM(TRUE,0));
1428 SendDlgItemMessage(dlg, IDC_CONTINUE, WM_SETFONT, (WPARAM)DlgHostsReplaceFont, MAKELPARAM(TRUE,0));
1429 SendDlgItemMessage(dlg, IDCANCEL, WM_SETFONT, (WPARAM)DlgHostsReplaceFont, MAKELPARAM(TRUE,0));
1430 }
1431 else {
1432 DlgHostsReplaceFont = NULL;
1433 }
1434
1435 // �f�t�H���g���`�F�b�N����������
1436 return TRUE; /* because we do not set the focus */
1437
1438 case WM_COMMAND:
1439 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
1440
1441 switch (LOWORD(wParam)) {
1442 case IDC_CONTINUE:
1443 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1444 add_host_key(pvar);
1445 delete_different_key(pvar);
1446 }
1447
1448 if (SSHv1(pvar)) {
1449 SSH_notify_host_OK(pvar);
1450 } else { // SSH2
1451 // SSH2���������� SSH_notify_host_OK() �������B
1452 }
1453
1454 pvar->hosts_state.hosts_dialog = NULL;
1455
1456 EndDialog(dlg, 1);
1457
1458 if (DlgHostsReplaceFont != NULL) {
1459 DeleteObject(DlgHostsReplaceFont);
1460 }
1461
1462 return TRUE;
1463
1464 case IDCANCEL: /* kill the connection */
1465 pvar->hosts_state.hosts_dialog = NULL;
1466 notify_closed_connection(pvar);
1467 EndDialog(dlg, 0);
1468
1469 if (DlgHostsReplaceFont != NULL) {
1470 DeleteObject(DlgHostsReplaceFont);
1471 }
1472
1473 return TRUE;
1474
1475 default:
1476 return FALSE;
1477 }
1478
1479 default:
1480 return FALSE;
1481 }
1482 }
1483
1484 //
1485 // �����z�X�g�����`�����������������m�F�_�C�A���O������
1486 //
1487 static BOOL CALLBACK hosts_add2_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1488 LPARAM lParam)
1489 {
1490 PTInstVar pvar;
1491 LOGFONT logfont;
1492 HFONT font;
1493 char uimsg[MAX_UIMSG];
1494
1495 switch (msg) {
1496 case WM_INITDIALOG:
1497 pvar = (PTInstVar) lParam;
1498 pvar->hosts_state.hosts_dialog = dlg;
1499 SetWindowLong(dlg, DWL_USER, lParam);
1500
1501 // �����E�u���������� init_hosts_dlg �����������������A�����O���Z�b�g�����K�v������
1502 GetWindowText(dlg, uimsg, sizeof(uimsg));
1503 UTIL_get_lang_msg("DLG_DIFFERENTTYPEKEY_TITLE", pvar, uimsg);
1504 SetWindowText(dlg, pvar->ts->UIMsg);
1505 GetDlgItemText(dlg, IDC_HOSTWARNING, uimsg, sizeof(uimsg));
1506 UTIL_get_lang_msg("DLG_DIFFERENTTYPEKEY_WARNING", pvar, uimsg);
1507 SetDlgItemText(dlg, IDC_HOSTWARNING, pvar->ts->UIMsg);
1508 GetDlgItemText(dlg, IDC_HOSTWARNING2, uimsg, sizeof(uimsg));
1509 UTIL_get_lang_msg("DLG_DIFFERENTTYPEKEY_WARNING2", pvar, uimsg);
1510 SetDlgItemText(dlg, IDC_HOSTWARNING2, pvar->ts->UIMsg);
1511 GetDlgItemText(dlg, IDC_HOSTFINGERPRINT, uimsg, sizeof(uimsg));
1512 UTIL_get_lang_msg("DLG_DIFFERENTTYPEKEY_FINGERPRINT", pvar, uimsg);
1513 SetDlgItemText(dlg, IDC_HOSTFINGERPRINT, pvar->ts->UIMsg);
1514 GetDlgItemText(dlg, IDC_ADDTOKNOWNHOSTS, uimsg, sizeof(uimsg));
1515 UTIL_get_lang_msg("DLG_DIFFERENTTYPEKEY_ADD", pvar, uimsg);
1516 SetDlgItemText(dlg, IDC_ADDTOKNOWNHOSTS, pvar->ts->UIMsg);
1517 GetDlgItemText(dlg, IDC_CONTINUE, uimsg, sizeof(uimsg));
1518 UTIL_get_lang_msg("BTN_CONTINUE", pvar, uimsg);
1519 SetDlgItemText(dlg, IDC_CONTINUE, pvar->ts->UIMsg);
1520 GetDlgItemText(dlg, IDCANCEL, uimsg, sizeof(uimsg));
1521 UTIL_get_lang_msg("BTN_DISCONNECT", pvar, uimsg);
1522 SetDlgItemText(dlg, IDCANCEL, pvar->ts->UIMsg);
1523
1524 init_hosts_dlg(pvar, dlg);
1525
1526 font = (HFONT)SendMessage(dlg, WM_GETFONT, 0, 0);
1527 GetObject(font, sizeof(LOGFONT), &logfont);
1528 if (UTIL_get_lang_font("DLG_TAHOMA_FONT", dlg, &logfont, &DlgHostsAddFont, pvar)) {
1529 SendDlgItemMessage(dlg, IDC_HOSTWARNING, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1530 SendDlgItemMessage(dlg, IDC_HOSTWARNING2, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1531 SendDlgItemMessage(dlg, IDC_HOSTFINGERPRINT, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1532 SendDlgItemMessage(dlg, IDC_FINGER_PRINT, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1533 SendDlgItemMessage(dlg, IDC_ADDTOKNOWNHOSTS, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1534 SendDlgItemMessage(dlg, IDC_CONTINUE, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1535 SendDlgItemMessage(dlg, IDCANCEL, WM_SETFONT, (WPARAM)DlgHostsAddFont, MAKELPARAM(TRUE,0));
1536 }
1537 else {
1538 DlgHostsAddFont = NULL;
1539 }
1540
1541 // add host check box ���f�t�H���g�� off ������
1542 // SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
1543
1544 return TRUE; /* because we do not set the focus */
1545
1546 case WM_COMMAND:
1547 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
1548
1549 switch (LOWORD(wParam)) {
1550 case IDC_CONTINUE:
1551 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1552 add_host_key(pvar);
1553 }
1554
1555 if (SSHv1(pvar)) {
1556 SSH_notify_host_OK(pvar);
1557 } else { // SSH2
1558 // SSH2���������� SSH_notify_host_OK() �������B
1559 }
1560
1561 pvar->hosts_state.hosts_dialog = NULL;
1562
1563 EndDialog(dlg, 1);
1564
1565 if (DlgHostsAddFont != NULL) {
1566 DeleteObject(DlgHostsAddFont);
1567 }
1568
1569 return TRUE;
1570
1571 case IDCANCEL: /* kill the connection */
1572 pvar->hosts_state.hosts_dialog = NULL;
1573 notify_closed_connection(pvar);
1574 EndDialog(dlg, 0);
1575
1576 if (DlgHostsAddFont != NULL) {
1577 DeleteObject(DlgHostsAddFont);
1578 }
1579
1580 return TRUE;
1581
1582 default:
1583 return FALSE;
1584 }
1585
1586 default:
1587 return FALSE;
1588 }
1589 }
1590
1591 void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar)
1592 {
1593 if (pvar->hosts_state.hosts_dialog == NULL) {
1594 HWND cur_active = GetActiveWindow();
1595
1596 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST),
1597 cur_active != NULL ? cur_active : wnd,
1598 hosts_add_dlg_proc, (LPARAM) pvar);
1599 }
1600 }
1601
1602 void HOSTS_do_different_key_dialog(HWND wnd, PTInstVar pvar)
1603 {
1604 if (pvar->hosts_state.hosts_dialog == NULL) {
1605 HWND cur_active = GetActiveWindow();
1606
1607 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTKEY),
1608 cur_active != NULL ? cur_active : wnd,
1609 hosts_replace_dlg_proc, (LPARAM) pvar);
1610 }
1611 }
1612
1613 void HOSTS_do_different_type_key_dialog(HWND wnd, PTInstVar pvar)
1614 {
1615 if (pvar->hosts_state.hosts_dialog == NULL) {
1616 HWND cur_active = GetActiveWindow();
1617
1618 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTTYPEKEY),
1619 cur_active != NULL ? cur_active : wnd,
1620 hosts_add2_dlg_proc, (LPARAM) pvar);
1621 }
1622 }
1623
1624 int is_numeric_hostname(const char *hostname)
1625 {
1626 struct addrinfo hints, *ai;
1627
1628 if (hostname == NULL) {
1629 return -1;
1630 }
1631
1632 memset(&hints, 0, sizeof(hints));
1633 hints.ai_socktype = SOCK_DGRAM;
1634 hints.ai_flags = AI_NUMERICHOST;
1635
1636 if (getaddrinfo(hostname, NULL, &hints, &ai) == 0) {
1637 freeaddrinfo(ai);
1638 return 1;
1639 }
1640
1641 return 0;
1642 }
1643
1644 #define DNS_TYPE_SSHFP 44
1645 typedef struct {
1646 BYTE Algorithm;
1647 BYTE DigestType;
1648 BYTE Digest[1];
1649 } DNS_SSHFP_DATA, *PDNS_SSHFP_DATA;
1650 enum verifydns_result {
1651 DNS_VERIFY_NONE,
1652 DNS_VERIFY_MATCH,
1653 DNS_VERIFY_MISMATCH,
1654 DNS_VERIFY_DIFFERENTTYPE,
1655 DNS_VERIFY_AUTH_MATCH,
1656 DNS_VERIFY_AUTH_MISMATCH,
1657 DNS_VERIFY_AUTH_DIFFERENTTYPE
1658 };
1659
1660 int verify_hostkey_dns(char FAR *hostname, Key *key)
1661 {
1662 DNS_STATUS status;
1663 PDNS_RECORD rec, p;
1664 PDNS_SSHFP_DATA t;
1665 int hostkey_alg, hostkey_dtype, hostkey_dlen;
1666 BYTE *hostkey_digest;
1667 int found = DNS_VERIFY_NONE;
1668
1669 switch (key->type) {
1670 case KEY_RSA:
1671 hostkey_alg = SSHFP_KEY_RSA;
1672 hostkey_dtype = SSHFP_HASH_SHA1;
1673 break;
1674 case KEY_DSA:
1675 hostkey_alg = SSHFP_KEY_DSA;
1676 hostkey_dtype = SSHFP_HASH_SHA1;
1677 break;
1678 case KEY_ECDSA256:
1679 case KEY_ECDSA384:
1680 case KEY_ECDSA521:
1681 hostkey_alg = SSHFP_KEY_ECDSA;
1682 hostkey_dtype = SSHFP_HASH_SHA256;
1683 break;
1684 default: // Un-supported algorithm
1685 hostkey_alg = SSHFP_KEY_RESERVED;
1686 hostkey_dtype = SSHFP_HASH_RESERVED;
1687 }
1688
1689 if (hostkey_alg) {
1690 hostkey_digest = key_fingerprint_raw(key, hostkey_dtype, &hostkey_dlen);
1691 }
1692 else {
1693 hostkey_digest = NULL;
1694 }
1695
1696 status = DnsQuery(hostname, DNS_TYPE_SSHFP, DNS_QUERY_STANDARD, NULL, &rec, NULL);
1697
1698 if (status == 0) {
1699 for (p=rec; p!=NULL; p=p->pNext) {
1700 if (p->wType == DNS_TYPE_SSHFP) {
1701 t = (PDNS_SSHFP_DATA)&(p->Data.Null);
1702 if (t->Algorithm == hostkey_alg && t->DigestType == hostkey_dtype) {
1703 if (hostkey_dlen == p->wDataLength-2 && memcmp(hostkey_digest, t->Digest, hostkey_dlen) == 0) {
1704 found = DNS_VERIFY_MATCH;
1705 break;
1706 }
1707 else {
1708 found = DNS_VERIFY_MISMATCH;
1709 break;
1710 }
1711 }
1712 else {
1713 found = DNS_VERIFY_DIFFERENTTYPE;
1714 }
1715 }
1716 }
1717 }
1718
1719 free(hostkey_digest);
1720 DnsRecordListFree(rec, DnsFreeRecordList);
1721 return found;
1722 }
1723
1724 //
1725 // �T�[�o�����������������z�X�g���J�������������`�F�b�N����
1726 //
1727 // SSH2���������� (2006.3.24 yutaka)
1728 //
1729 BOOL HOSTS_check_host_key(PTInstVar pvar, char FAR * hostname, unsigned short tcpport, Key *key)
1730 {
1731 int found_different_key = 0, found_different_type_key = 0, dns_sshfp_check = 0;
1732
1733 // ������ known_hosts �t�@�C�������z�X�g���J�����������������������A���������r�����B
1734 if (pvar->hosts_state.prefetched_hostname != NULL
1735 && _stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0
1736 && match_key(pvar, key) == 1) {
1737
1738 if (SSHv1(pvar)) {
1739 SSH_notify_host_OK(pvar);
1740 } else {
1741 // SSH2���������� SSH_notify_host_OK() �������B
1742 }
1743 return TRUE;
1744 }
1745
1746 // �������������������������A�������_���t�@�C��������������
1747 if (begin_read_host_files(pvar, 0)) {
1748 do {
1749 if (!read_host_key(pvar, hostname, tcpport, 0, 0)) {
1750 break;
1751 }
1752
1753 if (pvar->hosts_state.hostkey.type != KEY_UNSPEC) {
1754 int match = match_key(pvar, key);
1755 if (match == 1) {
1756 finish_read_host_files(pvar, 0);
1757 // ���������G���g�����Q�������A���v�����L�[�������������������B
1758 // SSH2���������������������������B(2006.3.29 yutaka)
1759 if (SSHv1(pvar)) {
1760 SSH_notify_host_OK(pvar);
1761 } else {
1762 // SSH2���������� SSH_notify_host_OK() �������B
1763 }
1764 return TRUE;
1765 }
1766 else if (match == 0) {
1767 // �L�[�� known_hosts ���������������A�L�[�����e���������B
1768 found_different_key = 1;
1769 }
1770 else {
1771 // �L�[���`������������
1772 found_different_type_key = 1;
1773 }
1774 }
1775 } while (pvar->hosts_state.hostkey.type != KEY_UNSPEC); // �L�[�����������������������[�v����
1776
1777 finish_read_host_files(pvar, 0);
1778 }
1779
1780 // known_hosts �������������L�[���������t�@�C�������������������A�������������������B
1781 pvar->hosts_state.hostkey.type = key->type;
1782 switch (key->type) {
1783 case KEY_RSA1: // SSH1
1784 pvar->hosts_state.hostkey.bits = key->bits;
1785 pvar->hosts_state.hostkey.exp = copy_mp_int(key->exp);
1786 pvar->hosts_state.hostkey.mod = copy_mp_int(key->mod);
1787 break;
1788 case KEY_RSA: // SSH2 RSA
1789 pvar->hosts_state.hostkey.rsa = duplicate_RSA(key->rsa);
1790 break;
1791 case KEY_DSA: // SSH2 DSA
1792 pvar->hosts_state.hostkey.dsa = duplicate_DSA(key->dsa);
1793 break;
1794 case KEY_ECDSA256: // SSH2 ECDSA
1795 case KEY_ECDSA384:
1796 case KEY_ECDSA521:
1797 pvar->hosts_state.hostkey.ecdsa = EC_KEY_dup(key->ecdsa);
1798 break;
1799 }
1800 free(pvar->hosts_state.prefetched_hostname);
1801 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
1802
1803 // "/nosecuritywarning"���w�����������������A�_�C�A���O���\���������� return success �����B
1804 if (pvar->nocheck_known_hosts == TRUE) {
1805 return TRUE;
1806 }
1807
1808 if (pvar->settings.VerifyHostKeyDNS && !is_numeric_hostname(hostname)) {
1809 dns_sshfp_check = verify_hostkey_dns(hostname, key);
1810 }
1811
1812 // known_hosts�_�C�A���O�������I���\�������A�������_�����������[�U���m�F
1813 // �������K�v�����������A�����R�[�������X�����B
1814 // ����������known_hosts���m�F�����������A�T�[�o�����[�U���������������������������������B
1815 // (2007.10.1 yutaka)
1816 if (found_different_key) {
1817 HOSTS_do_different_key_dialog(pvar->NotificationWindow, pvar);
1818 }
1819 else if (found_different_type_key) {
1820 HOSTS_do_different_type_key_dialog(pvar->NotificationWindow, pvar);
1821 }
1822 else {
1823 HOSTS_do_unknown_host_dialog(pvar->NotificationWindow, pvar);
1824 }
1825
1826 return TRUE;
1827 }
1828
1829 void HOSTS_notify_disconnecting(PTInstVar pvar)
1830 {
1831 if (pvar->hosts_state.hosts_dialog != NULL) {
1832 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL, 0);
1833 /* the main window might not go away if it's not enabled. (see vtwin.cpp) */
1834 EnableWindow(pvar->NotificationWindow, TRUE);
1835 }
1836 }
1837
1838 void HOSTS_end(PTInstVar pvar)
1839 {
1840 int i;
1841
1842 free(pvar->hosts_state.prefetched_hostname);
1843 init_hostkey(&pvar->hosts_state.hostkey);
1844
1845 if (pvar->hosts_state.file_names != NULL) {
1846 for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {
1847 free(pvar->hosts_state.file_names[i]);
1848 }
1849 free(pvar->hosts_state.file_names);
1850 }
1851 }

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