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 2859 - (show annotations) (download) (as text)
Wed Mar 29 14:56:52 2006 UTC (18 years ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/hosts.c
File MIME type: text/x-csrc
File size: 27485 byte(s)
known_hostsファイルにキー種別の異なる同一ホストのエントリがあると、アプリケーションエラーとなるバグを修正した。

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 "hosts.h"
40
41 #include <openssl/bn.h>
42 #include <openssl/evp.h>
43 #include <openssl/rsa.h>
44 #include <openssl/dsa.h>
45
46 #include <fcntl.h>
47 #include <io.h>
48 #include <errno.h>
49 #include <sys/stat.h>
50
51
52 // BASE64�\���������i��������'='�����������������j
53 static char base64[] ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
54
55
56 // �z�X�g�L�[�������� (2006.3.21 yutaka)
57 static void init_hostkey(Key *key)
58 {
59 key->type = KEY_UNSPEC;
60
61 // SSH1
62 key->bits = 0;
63 if (key->exp != NULL) {
64 free(key->exp);
65 key->exp = NULL;
66 }
67 if (key->mod != NULL) {
68 free(key->mod);
69 key->mod = NULL;
70 }
71
72 // SSH2
73 if (key->dsa != NULL) {
74 DSA_free(key->dsa);
75 key->dsa = NULL;
76 }
77 if (key->rsa != NULL) {
78 RSA_free(key->rsa);
79 key->rsa = NULL;
80 }
81 }
82
83
84 static char FAR *FAR * parse_multi_path(char FAR * buf)
85 {
86 int i;
87 int ch;
88 int num_paths = 1;
89 char FAR *FAR * result;
90 int last_path_index;
91
92 for (i = 0; (ch = buf[i]) != 0; i++) {
93 if (ch == ';') {
94 num_paths++;
95 }
96 }
97
98 result =
99 (char FAR * FAR *) malloc(sizeof(char FAR *) * (num_paths + 1));
100
101 last_path_index = 0;
102 num_paths = 0;
103 for (i = 0; (ch = buf[i]) != 0; i++) {
104 if (ch == ';') {
105 buf[i] = 0;
106 result[num_paths] = _strdup(buf + last_path_index);
107 num_paths++;
108 buf[i] = ch;
109 last_path_index = i + 1;
110 }
111 }
112 if (i > last_path_index) {
113 result[num_paths] = _strdup(buf + last_path_index);
114 num_paths++;
115 }
116 result[num_paths] = NULL;
117 return result;
118 }
119
120 void HOSTS_init(PTInstVar pvar)
121 {
122 pvar->hosts_state.prefetched_hostname = NULL;
123 #if 0
124 pvar->hosts_state.key_exp = NULL;
125 pvar->hosts_state.key_mod = NULL;
126 #else
127 init_hostkey(&pvar->hosts_state.hostkey);
128 #endif
129 pvar->hosts_state.hosts_dialog = NULL;
130 pvar->hosts_state.file_names = NULL;
131 }
132
133 void HOSTS_open(PTInstVar pvar)
134 {
135 pvar->hosts_state.file_names =
136 parse_multi_path(pvar->session_settings.KnownHostsFiles);
137 }
138
139 //
140 // known_hosts�t�@�C�������e�������� pvar->hosts_state.file_data ����������
141 //
142 static int begin_read_file(PTInstVar pvar, char FAR * name,
143 int suppress_errors)
144 {
145 int fd;
146 int length;
147 int amount_read;
148 char buf[2048];
149
150 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
151 fd = _open(buf, _O_RDONLY | _O_SEQUENTIAL | _O_BINARY);
152 if (fd == -1) {
153 if (!suppress_errors) {
154 if (errno == ENOENT) {
155 notify_nonfatal_error(pvar,
156 "An error occurred while trying to read a known_hosts file.\n"
157 "The specified filename does not exist.");
158 } else {
159 notify_nonfatal_error(pvar,
160 "An error occurred while trying to read a known_hosts file.");
161 }
162 }
163 return 0;
164 }
165
166 length = (int) _lseek(fd, 0, SEEK_END);
167 _lseek(fd, 0, SEEK_SET);
168
169 if (length >= 0 && length < 0x7FFFFFFF) {
170 pvar->hosts_state.file_data = malloc(length + 1);
171 if (pvar->hosts_state.file_data == NULL) {
172 if (!suppress_errors) {
173 notify_nonfatal_error(pvar,
174 "Memory ran out while trying to allocate space to read a known_hosts file.");
175 }
176 _close(fd);
177 return 0;
178 }
179 } else {
180 if (!suppress_errors) {
181 notify_nonfatal_error(pvar,
182 "An error occurred while trying to read a known_hosts file.");
183 }
184 _close(fd);
185 return 0;
186 }
187
188 amount_read = _read(fd, pvar->hosts_state.file_data, length);
189 pvar->hosts_state.file_data[length] = 0;
190
191 _close(fd);
192
193 if (amount_read != length) {
194 if (!suppress_errors) {
195 notify_nonfatal_error(pvar,
196 "An error occurred while trying to read a known_hosts file.");
197 }
198 free(pvar->hosts_state.file_data);
199 pvar->hosts_state.file_data = NULL;
200 return 0;
201 } else {
202 return 1;
203 }
204 }
205
206 static int end_read_file(PTInstVar pvar, int suppress_errors)
207 {
208 free(pvar->hosts_state.file_data);
209 pvar->hosts_state.file_data = NULL;
210 return 1;
211 }
212
213 static int begin_read_host_files(PTInstVar pvar, int suppress_errors)
214 {
215 pvar->hosts_state.file_num = 0;
216 pvar->hosts_state.file_data = NULL;
217 return 1;
218 }
219
220 // MIME64�����������X�L�b�v����
221 static int eat_base64(char FAR * data)
222 {
223 int index = 0;
224 int ch;
225
226 for (;;) {
227 ch = data[index];
228 if (ch == '=' || strchr(base64, ch)) {
229 // BASE64���\�������������������� index ���i����
230 index++;
231 } else {
232 break;
233 }
234 }
235
236 return index;
237 }
238
239 static int eat_spaces(char FAR * data)
240 {
241 int index = 0;
242 int ch;
243
244 while ((ch = data[index]) == ' ' || ch == '\t') {
245 index++;
246 }
247 return index;
248 }
249
250 static int eat_digits(char FAR * data)
251 {
252 int index = 0;
253 int ch;
254
255 while ((ch = data[index]) >= '0' && ch <= '9') {
256 index++;
257 }
258 return index;
259 }
260
261 static int eat_to_end_of_line(char FAR * data)
262 {
263 int index = 0;
264 int ch;
265
266 while ((ch = data[index]) != '\n' && ch != '\r' && ch != 0) {
267 index++;
268 }
269
270 while ((ch = data[index]) == '\n' || ch == '\r') {
271 index++;
272 }
273
274 return index;
275 }
276
277 static int eat_to_end_of_pattern(char FAR * data)
278 {
279 int index = 0;
280 int ch;
281
282 while (ch = data[index], is_pattern_char(ch)) {
283 index++;
284 }
285
286 return index;
287 }
288
289 //
290 // BASE64�f�R�[�h�������s���B(rfc1521)
291 // src�o�b�t�@�� null-terminate ���������K�v�����B
292 //
293 static int uudecode(unsigned char *src, int srclen, unsigned char *target, int targsize)
294 {
295 char pad = '=';
296 int tarindex, state, ch;
297 char *pos;
298
299 state = 0;
300 tarindex = 0;
301
302 while ((ch = *src++) != '\0') {
303 if (isspace(ch)) /* Skip whitespace anywhere. */
304 continue;
305
306 if (ch == pad)
307 break;
308
309 pos = strchr(base64, ch);
310 if (pos == 0) /* A non-base64 character. */
311 return (-1);
312
313 switch (state) {
314 case 0:
315 if (target) {
316 if (tarindex >= targsize)
317 return (-1);
318 target[tarindex] = (pos - base64) << 2;
319 }
320 state = 1;
321 break;
322 case 1:
323 if (target) {
324 if (tarindex + 1 >= targsize)
325 return (-1);
326 target[tarindex] |= (pos - base64) >> 4;
327 target[tarindex+1] = ((pos - base64) & 0x0f) << 4 ;
328 }
329 tarindex++;
330 state = 2;
331 break;
332 case 2:
333 if (target) {
334 if (tarindex + 1 >= targsize)
335 return (-1);
336 target[tarindex] |= (pos - base64) >> 2;
337 target[tarindex+1] = ((pos - base64) & 0x03) << 6;
338 }
339 tarindex++;
340 state = 3;
341 break;
342 case 3:
343 if (target) {
344 if (tarindex >= targsize)
345 return (-1);
346 target[tarindex] |= (pos - base64);
347 }
348 tarindex++;
349 state = 0;
350 break;
351 }
352 }
353
354 /*
355 * We are done decoding Base-64 chars. Let's see if we ended
356 * on a byte boundary, and/or with erroneous trailing characters.
357 */
358
359 if (ch == pad) { /* We got a pad char. */
360 ch = *src++; /* Skip it, get next. */
361 switch (state) {
362 case 0: /* Invalid = in first position */
363 case 1: /* Invalid = in second position */
364 return (-1);
365
366 case 2: /* Valid, means one byte of info */
367 /* Skip any number of spaces. */
368 for (; ch != '\0'; ch = *src++)
369 if (!isspace(ch))
370 break;
371 /* Make sure there is another trailing = sign. */
372 if (ch != pad)
373 return (-1);
374 ch = *src++; /* Skip the = */
375 /* Fall through to "single trailing =" case. */
376 /* FALLTHROUGH */
377
378 case 3: /* Valid, means two bytes of info */
379 /*
380 * We know this char is an =. Is there anything but
381 * whitespace after it?
382 */
383 for (; ch != '\0'; ch = *src++)
384 if (!isspace(ch))
385 return (-1);
386
387 /*
388 * Now make sure for cases 2 and 3 that the "extra"
389 * bits that slopped past the last full byte were
390 * zeros. If we don't check them, they become a
391 * subliminal channel.
392 */
393 if (target && target[tarindex] != 0)
394 return (-1);
395 }
396 } else {
397 /*
398 * We ended by seeing the end of the string. Make sure we
399 * have no partial bytes lying around.
400 */
401 if (state != 0)
402 return (-1);
403 }
404
405 return (tarindex);
406 }
407
408
409 // SSH2���� BASE64 �`�����i�[����������
410 static Key *parse_uudecode(char *data)
411 {
412 int count;
413 unsigned char *blob = NULL;
414 int len, n;
415 Key *key = NULL;
416 char ch;
417
418 // BASE64���������T�C�Y������
419 count = eat_base64(data);
420 len = 2 * count;
421 blob = malloc(len);
422 if (blob == NULL)
423 goto error;
424
425 // BASE64�f�R�[�h
426 ch = data[count];
427 data[count] = '\0'; // ���������s�R�[�h������������������������������������
428 n = uudecode(data, count, blob, len);
429 data[count] = ch;
430 if (n < 0) {
431 goto error;
432 }
433
434 key = key_from_blob(blob, n);
435 if (key == NULL)
436 goto error;
437
438 error:
439 if (blob != NULL)
440 free(blob);
441
442 return (key);
443 }
444
445
446 static char FAR *parse_bignum(char FAR * data)
447 {
448 uint32 digits = 0;
449 BIGNUM *num = BN_new();
450 BIGNUM *billion = BN_new();
451 BIGNUM *digits_num = BN_new();
452 BN_CTX *ctx = BN_CTX_new();
453 char FAR *result;
454 int ch;
455 int leftover_digits = 1;
456
457 BN_CTX_init(ctx);
458 BN_set_word(num, 0);
459 BN_set_word(billion, 1000000000L);
460
461 while ((ch = *data) >= '0' && ch <= '9') {
462 if (leftover_digits == 1000000000L) {
463 BN_set_word(digits_num, digits);
464 BN_mul(num, num, billion, ctx);
465 BN_add(num, num, digits_num);
466 leftover_digits = 1;
467 digits = 0;
468 }
469
470 digits = digits * 10 + ch - '0';
471 leftover_digits *= 10;
472 data++;
473 }
474
475 BN_set_word(digits_num, digits);
476 BN_set_word(billion, leftover_digits);
477 BN_mul(num, num, billion, ctx);
478 BN_add(num, num, digits_num);
479
480 result = (char FAR *) malloc(2 + BN_num_bytes(num));
481 set_ushort16_MSBfirst(result, BN_num_bits(num));
482 BN_bn2bin(num, result + 2);
483
484 BN_CTX_free(ctx);
485 BN_free(digits_num);
486 BN_free(num);
487 BN_free(billion);
488
489 return result;
490 }
491
492 //
493 // known_hosts�t�@�C�������e���������A�w�������z�X�g�����J�����T���B
494 //
495 static int check_host_key(PTInstVar pvar, char FAR * hostname,
496 char FAR * data)
497 {
498 int index = eat_spaces(data);
499 int matched = 0;
500 int keybits = 0;
501
502 if (data[index] == '#') {
503 return index + eat_to_end_of_line(data + index);
504 }
505
506 /* if we find an empty line, then it won't have any patterns matching the hostname
507 and so we skip it */
508 index--;
509 do {
510 int negated;
511
512 index++;
513 negated = data[index] == '!';
514
515 if (negated) {
516 index++;
517 if (match_pattern(data + index, hostname)) {
518 return index + eat_to_end_of_line(data + index);
519 }
520 } else if (match_pattern(data + index, hostname)) {
521 matched = 1;
522 }
523
524 index += eat_to_end_of_pattern(data + index);
525 } while (data[index] == ',');
526
527 if (!matched) {
528 return index + eat_to_end_of_line(data + index);
529 } else {
530 // ���������������t�H�[�}�b�g��������
531 // �����A���������v�����G���g�����������������������B
532 /*
533 [SSH1]
534 192.168.1.2 1024 35 13032....
535
536 [SSH2]
537 192.168.1.2 ssh-rsa AAAAB3NzaC1....
538 192.168.1.2 ssh-dss AAAAB3NzaC1....
539 192.168.1.2 rsa AAAAB3NzaC1....
540 192.168.1.2 dsa AAAAB3NzaC1....
541 192.168.1.2 rsa1 AAAAB3NzaC1....
542 */
543 int rsa1_key_bits;
544
545 index += eat_spaces(data + index);
546
547 rsa1_key_bits = atoi(data + index);
548 if (rsa1_key_bits > 0) { // RSA1������
549 if (!SSHv1(pvar)) { // SSH2��������������������
550 return index + eat_to_end_of_line(data + index);
551 }
552
553 pvar->hosts_state.hostkey.type = KEY_RSA1;
554
555 pvar->hosts_state.hostkey.bits = rsa1_key_bits;
556 index += eat_digits(data + index);
557 index += eat_spaces(data + index);
558
559 pvar->hosts_state.hostkey.exp = parse_bignum(data + index);
560 index += eat_digits(data + index);
561 index += eat_spaces(data + index);
562
563 pvar->hosts_state.hostkey.mod = parse_bignum(data + index);
564
565 /*
566 if (pvar->hosts_state.key_bits < 0
567 || pvar->hosts_state.key_exp == NULL
568 || pvar->hosts_state.key_mod == NULL) {
569 pvar->hosts_state.key_bits = 0;
570 free(pvar->hosts_state.key_exp);
571 free(pvar->hosts_state.key_mod);
572 }*/
573
574 } else {
575 char *cp, *p;
576 Key *key;
577
578 if (!SSHv2(pvar)) { // SSH1��������������������
579 return index + eat_to_end_of_line(data + index);
580 }
581
582 cp = data + index;
583 p = strchr(cp, ' ');
584 if (p == NULL) {
585 return index + eat_to_end_of_line(data + index);
586 }
587 index += (p - cp); // setup index
588 *p = '\0';
589 pvar->hosts_state.hostkey.type = get_keytype_from_name(cp);
590 *p = ' ';
591
592 index += eat_spaces(data + index); // update index
593
594 // uudecode
595 key = parse_uudecode(data + index);
596 if (key == NULL) {
597 return index + eat_to_end_of_line(data + index);
598 }
599
600 // setup
601 pvar->hosts_state.hostkey.type = key->type;
602 pvar->hosts_state.hostkey.dsa = key->dsa;
603 pvar->hosts_state.hostkey.rsa = key->rsa;
604
605 index += eat_base64(data + index);
606 index += eat_spaces(data + index);
607 }
608
609 return index + eat_to_end_of_line(data + index);
610 }
611 }
612
613 //
614 // known_hosts�t�@�C�������z�X�g�������v�����s������
615 //
616 static int read_host_key(PTInstVar pvar, char FAR * hostname,
617 int suppress_errors)
618 {
619 int i;
620
621 for (i = 0; hostname[i] != 0; i++) {
622 int ch = hostname[i];
623
624 if (!is_pattern_char(ch) || ch == '*' || ch == '?') {
625 if (!suppress_errors) {
626 notify_fatal_error(pvar,
627 "The host name contains an invalid character.\n"
628 "This session will be terminated.");
629 }
630 return 0;
631 }
632 }
633
634 if (i == 0) {
635 if (!suppress_errors) {
636 notify_fatal_error(pvar, "The host name should not be empty.\n"
637 "This session will be terminated.");
638 }
639 return 0;
640 }
641
642 #if 0
643 pvar->hosts_state.key_bits = 0;
644 free(pvar->hosts_state.key_exp);
645 pvar->hosts_state.key_exp = NULL;
646 free(pvar->hosts_state.key_mod);
647 pvar->hosts_state.key_mod = NULL;
648 #else
649 // hostkey type is KEY_UNSPEC.
650 init_hostkey(&pvar->hosts_state.hostkey);
651 #endif
652
653 do {
654 if (pvar->hosts_state.file_data == NULL
655 || pvar->hosts_state.file_data[pvar->hosts_state.
656 file_data_index] == 0) {
657 char FAR *filename;
658 int keep_going = 1;
659
660 if (pvar->hosts_state.file_data != NULL) {
661 end_read_file(pvar, suppress_errors);
662 }
663
664 do {
665 filename =
666 pvar->hosts_state.file_names[pvar->hosts_state.
667 file_num];
668
669 if (filename == NULL) {
670 return 1;
671 } else {
672 pvar->hosts_state.file_num++;
673
674 if (filename[0] != 0) {
675 if (begin_read_file
676 (pvar, filename, suppress_errors)) {
677 pvar->hosts_state.file_data_index = 0;
678 keep_going = 0;
679 }
680 }
681 }
682 } while (keep_going);
683 }
684
685 pvar->hosts_state.file_data_index +=
686 check_host_key(pvar, hostname,
687 pvar->hosts_state.file_data +
688 pvar->hosts_state.file_data_index);
689 } while (pvar->hosts_state.hostkey.type == KEY_UNSPEC); // �L�����L�[��������������
690
691 return 1;
692 }
693
694 static void finish_read_host_files(PTInstVar pvar, int suppress_errors)
695 {
696 if (pvar->hosts_state.file_data != NULL) {
697 end_read_file(pvar, suppress_errors);
698 }
699 }
700
701 // �T�[�o�����������O���Aknown_hosts�t�@�C�������z�X�g���J�������������������B
702 void HOSTS_prefetch_host_key(PTInstVar pvar, char FAR * hostname)
703 {
704 if (!begin_read_host_files(pvar, 1)) {
705 return;
706 }
707
708 if (!read_host_key(pvar, hostname, 1)) {
709 return;
710 }
711
712 free(pvar->hosts_state.prefetched_hostname);
713 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
714
715 finish_read_host_files(pvar, 1);
716 }
717
718 static BOOL equal_mp_ints(unsigned char FAR * num1,
719 unsigned char FAR * num2)
720 {
721 if (num1 == NULL || num2 == NULL) {
722 return FALSE;
723 } else {
724 uint32 bytes = (get_ushort16_MSBfirst(num1) + 7) / 8;
725
726 if (bytes != (get_ushort16_MSBfirst(num2) + 7) / 8) {
727 return FALSE; /* different byte lengths */
728 } else {
729 return memcmp(num1 + 2, num2 + 2, bytes) == 0;
730 }
731 }
732 }
733
734 // ���J����������������������
735 static BOOL match_key(PTInstVar pvar, Key *key)
736 {
737 int bits;
738 unsigned char FAR * exp;
739 unsigned char FAR * mod;
740
741 if (key->type == KEY_RSA1) { // SSH1 host public key
742 bits = key->bits;
743 exp = key->exp;
744 mod = key->mod;
745
746 /* just check for equal exponent and modulus */
747 return equal_mp_ints(exp, pvar->hosts_state.hostkey.exp)
748 && equal_mp_ints(mod, pvar->hosts_state.hostkey.mod);
749 /*
750 return equal_mp_ints(exp, pvar->hosts_state.key_exp)
751 && equal_mp_ints(mod, pvar->hosts_state.key_mod);
752 */
753
754 } else if (key->type == KEY_RSA) { // SSH2 RSA host public key
755
756 return key->rsa != NULL && pvar->hosts_state.hostkey.rsa != NULL &&
757 BN_cmp(key->rsa->e, pvar->hosts_state.hostkey.rsa->e) == 0 &&
758 BN_cmp(key->rsa->n, pvar->hosts_state.hostkey.rsa->n) == 0;
759
760 } else { // // SSH2 DSA host public key
761
762 return key->dsa != NULL && pvar->hosts_state.hostkey.dsa &&
763 BN_cmp(key->dsa->p, pvar->hosts_state.hostkey.dsa->p) == 0 &&
764 BN_cmp(key->dsa->q, pvar->hosts_state.hostkey.dsa->q) == 0 &&
765 BN_cmp(key->dsa->g, pvar->hosts_state.hostkey.dsa->g) == 0 &&
766 BN_cmp(key->dsa->pub_key, pvar->hosts_state.hostkey.dsa->pub_key) == 0;
767
768 }
769
770 }
771
772 static void init_hosts_dlg(PTInstVar pvar, HWND dlg)
773 {
774 char buf[1024];
775 char buf2[2048];
776 int i, j;
777 int ch;
778 char *fp;
779
780 // static text�� # �������z�X�g�����u������
781 GetDlgItemText(dlg, IDC_HOSTWARNING, buf, sizeof(buf));
782 for (i = 0; (ch = buf[i]) != 0 && ch != '#'; i++) {
783 buf2[i] = ch;
784 }
785 if (sizeof(buf2) - i - 1 > 0) {
786 strncpy(buf2 + i, pvar->hosts_state.prefetched_hostname,
787 sizeof(buf2) - i - 1);
788 }
789 j = i + strlen(buf2 + i);
790 for (; buf[i] == '#'; i++) {
791 }
792 if (sizeof(buf2) - j - 1 > 0) {
793 strncpy(buf2 + j, buf + i, sizeof(buf2) - j - 1);
794 }
795 buf2[sizeof(buf2) - 1] = 0;
796
797 SetDlgItemText(dlg, IDC_HOSTWARNING, buf2);
798
799 // fingerprint����������
800 fp = key_fingerprint(&pvar->hosts_state.hostkey);
801 SendMessage(GetDlgItem(dlg, IDC_FINGER_PRINT), WM_SETTEXT, 0, (LPARAM)fp);
802 }
803
804 static int print_mp_int(char FAR * buf, unsigned char FAR * mp)
805 {
806 int i = 0, j, k;
807 BIGNUM *num = BN_new();
808 int ch;
809
810 BN_bin2bn(mp + 2, (get_ushort16_MSBfirst(mp) + 7) / 8, num);
811
812 do {
813 buf[i] = (char) ((BN_div_word(num, 10)) + '0');
814 i++;
815 } while (!BN_is_zero(num));
816
817 /* we need to reverse the digits */
818 for (j = 0, k = i - 1; j < k; j++, k--) {
819 ch = buf[j];
820 buf[j] = buf[k];
821 buf[k] = ch;
822 }
823
824 buf[i] = 0;
825 return i;
826 }
827
828 //
829 // known_hosts �t�@�C�������������G���g�������������B
830 //
831 static char FAR *format_host_key(PTInstVar pvar)
832 {
833 int host_len = strlen(pvar->hosts_state.prefetched_hostname);
834 char *result = NULL;
835 int index;
836 enum hostkey_type type = pvar->hosts_state.hostkey.type;
837
838 if (type == KEY_RSA1) {
839 result = (char FAR *) malloc(host_len
840 + 50 +
841 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.exp) /
842 3 +
843 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.mod) /
844 3);
845
846 strcpy(result, pvar->hosts_state.prefetched_hostname);
847 index = host_len;
848
849 sprintf(result + index, " %d ", pvar->hosts_state.hostkey.bits);
850 index += strlen(result + index);
851 index += print_mp_int(result + index, pvar->hosts_state.hostkey.exp);
852 result[index] = ' ';
853 index++;
854 index += print_mp_int(result + index, pvar->hosts_state.hostkey.mod);
855 strcpy(result + index, " \r\n");
856
857 } else if (type == KEY_RSA || type == KEY_DSA) {
858 Key *key = &pvar->hosts_state.hostkey;
859 char *blob = NULL;
860 int blen, uulen, msize;
861 char *uu = NULL;
862 int n;
863
864 key_to_blob(key, &blob, &blen);
865 uulen = 2 * blen;
866 uu = malloc(uulen);
867 if (uu == NULL) {
868 goto error;
869 }
870 n = uuencode(blob, blen, uu, uulen);
871 if (n > 0) {
872 msize = host_len + 50 + uulen;
873 result = malloc(msize);
874 if (result == NULL) {
875 goto error;
876 }
877
878 // setup
879 _snprintf(result, msize, "%s %s %s\r\n",
880 pvar->hosts_state.prefetched_hostname,
881 get_sshname_from_key(key),
882 uu);
883 }
884 error:
885 if (blob != NULL)
886 free(blob);
887 if (uu != NULL)
888 free(uu);
889
890 } else {
891 return NULL;
892
893 }
894
895 return result;
896 }
897
898 static void add_host_key(PTInstVar pvar)
899 {
900 char FAR *name = pvar->hosts_state.file_names[0];
901
902 if (name == NULL || name[0] == 0) {
903 notify_nonfatal_error(pvar,
904 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
905 "Restart Teraterm and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
906 } else {
907 char FAR *keydata = format_host_key(pvar);
908 int length = strlen(keydata);
909 int fd =
910 _open(name,
911 _O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL |
912 _O_BINARY,
913 _S_IREAD | _S_IWRITE);
914 int amount_written;
915 int close_result;
916
917 if (fd == -1) {
918 if (errno == EACCES) {
919 notify_nonfatal_error(pvar,
920 "An error occurred while trying to write the host key.\n"
921 "You do not have permission to write to the known-hosts file.");
922 } else {
923 notify_nonfatal_error(pvar,
924 "An error occurred while trying to write the host key.\n"
925 "The host key could not be written.");
926 }
927 return;
928 }
929
930 amount_written = _write(fd, keydata, length);
931 free(keydata);
932 close_result = _close(fd);
933
934 if (amount_written != length || close_result == -1) {
935 notify_nonfatal_error(pvar,
936 "An error occurred while trying to write the host key.\n"
937 "The host key could not be written.");
938 }
939 }
940 }
941
942 //
943 // Unknown host���z�X�g���J���� known_hosts �t�@�C����������������������
944 // ���[�U���m�F�������B
945 // TODO: finger print���\�����s���B
946 // (2006.3.25 yutaka)
947 //
948 static BOOL CALLBACK hosts_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
949 LPARAM lParam)
950 {
951 PTInstVar pvar;
952
953 switch (msg) {
954 case WM_INITDIALOG:
955 pvar = (PTInstVar) lParam;
956 pvar->hosts_state.hosts_dialog = dlg;
957 SetWindowLong(dlg, DWL_USER, lParam);
958
959 init_hosts_dlg(pvar, dlg);
960
961 // add host check box���`�F�b�N���f�t�H���g������������
962 SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
963
964 return TRUE; /* because we do not set the focus */
965
966 case WM_COMMAND:
967 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
968
969 switch (LOWORD(wParam)) {
970 case IDC_CONTINUE:
971 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
972 add_host_key(pvar);
973 }
974
975 if (SSHv1(pvar)) {
976 SSH_notify_host_OK(pvar);
977 } else { // SSH2
978 // SSH2���������� SSH_notify_host_OK() �������B
979 }
980
981 pvar->hosts_state.hosts_dialog = NULL;
982
983 EndDialog(dlg, 1);
984 return TRUE;
985
986 case IDCANCEL: /* kill the connection */
987 pvar->hosts_state.hosts_dialog = NULL;
988 notify_closed_connection(pvar);
989 EndDialog(dlg, 0);
990 return TRUE;
991
992 default:
993 return FALSE;
994 }
995
996 default:
997 return FALSE;
998 }
999 }
1000
1001 static char FAR *copy_mp_int(char FAR * num)
1002 {
1003 int len = (get_ushort16_MSBfirst(num) + 7) / 8 + 2;
1004 char FAR *result = (char FAR *) malloc(len);
1005
1006 if (result != NULL) {
1007 memcpy(result, num, len);
1008 }
1009
1010 return result;
1011 }
1012
1013 void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar)
1014 {
1015 if (pvar->hosts_state.hosts_dialog == NULL) {
1016 HWND cur_active = GetActiveWindow();
1017
1018 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST),
1019 cur_active != NULL ? cur_active : wnd,
1020 hosts_dlg_proc, (LPARAM) pvar);
1021 }
1022 }
1023
1024 void HOSTS_do_different_host_dialog(HWND wnd, PTInstVar pvar)
1025 {
1026 if (pvar->hosts_state.hosts_dialog == NULL) {
1027 HWND cur_active = GetActiveWindow();
1028
1029 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTHOST),
1030 cur_active != NULL ? cur_active : wnd,
1031 hosts_dlg_proc, (LPARAM) pvar);
1032 }
1033 }
1034
1035 //
1036 // �T�[�o�����������������z�X�g���J�������������`�F�b�N����
1037 //
1038 // SSH2���������� (2006.3.24 yutaka)
1039 //
1040 BOOL HOSTS_check_host_key(PTInstVar pvar, char FAR * hostname, Key *key)
1041 {
1042 int found_different_key = 0;
1043
1044 // ������ known_hosts �t�@�C�������z�X�g���J�����������������������A���������r�����B
1045 if (pvar->hosts_state.prefetched_hostname != NULL
1046 && _stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0
1047 && match_key(pvar, key)) {
1048
1049 if (SSHv1(pvar)) {
1050 SSH_notify_host_OK(pvar);
1051 } else {
1052 // SSH2���������� SSH_notify_host_OK() �������B
1053 }
1054 return TRUE;
1055 }
1056
1057 // �������������������������A�������_���t�@�C��������������
1058 if (begin_read_host_files(pvar, 0)) {
1059 do {
1060 if (!read_host_key(pvar, hostname, 0)) {
1061 break;
1062 }
1063
1064 if (pvar->hosts_state.hostkey.type != KEY_UNSPEC) {
1065 if (match_key(pvar, key)) {
1066 finish_read_host_files(pvar, 0);
1067 // ���������G���g�����Q�������A���v�����L�[�������������������B
1068 // SSH2���������������������������B(2006.3.29 yutaka)
1069 if (SSHv1(pvar)) {
1070 SSH_notify_host_OK(pvar);
1071 } else {
1072 // SSH2���������� SSH_notify_host_OK() �������B
1073 }
1074 return TRUE;
1075 } else {
1076 // �L�[�� known_hosts ���������������A�L�[�����e���������B
1077 found_different_key = 1;
1078 }
1079 }
1080 } while (pvar->hosts_state.hostkey.type != KEY_UNSPEC); // �L�[�����������������������[�v����
1081
1082 finish_read_host_files(pvar, 0);
1083 }
1084
1085
1086 // known_hosts �������������L�[���������t�@�C�������������������A�������������������B
1087 pvar->hosts_state.hostkey.type = key->type;
1088 if (key->type == KEY_RSA1) { // SSH1
1089 pvar->hosts_state.hostkey.bits = key->bits;
1090 pvar->hosts_state.hostkey.exp = copy_mp_int(key->exp);
1091 pvar->hosts_state.hostkey.mod = copy_mp_int(key->mod);
1092
1093 } else if (key->type == KEY_RSA) { // SSH2 RSA
1094 pvar->hosts_state.hostkey.rsa = duplicate_RSA(key->rsa);
1095
1096 } else { // SSH2 DSA
1097 pvar->hosts_state.hostkey.dsa = duplicate_DSA(key->dsa);
1098
1099 }
1100 free(pvar->hosts_state.prefetched_hostname);
1101 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
1102
1103 if (found_different_key) {
1104 PostMessage(pvar->NotificationWindow, WM_COMMAND,
1105 ID_SSHDIFFERENTHOST, 0);
1106 } else {
1107 PostMessage(pvar->NotificationWindow, WM_COMMAND,
1108 ID_SSHUNKNOWNHOST, 0);
1109 }
1110
1111 return TRUE;
1112 }
1113
1114 void HOSTS_notify_disconnecting(PTInstVar pvar)
1115 {
1116 if (pvar->hosts_state.hosts_dialog != NULL) {
1117 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL,
1118 0);
1119 /* the main window might not go away if it's not enabled. (see vtwin.cpp) */
1120 EnableWindow(pvar->NotificationWindow, TRUE);
1121 }
1122 }
1123
1124 void HOSTS_end(PTInstVar pvar)
1125 {
1126 int i;
1127
1128 free(pvar->hosts_state.prefetched_hostname);
1129 #if 0
1130 free(pvar->hosts_state.key_exp);
1131 free(pvar->hosts_state.key_mod);
1132 #else
1133 init_hostkey(&pvar->hosts_state.hostkey);
1134 #endif
1135
1136 if (pvar->hosts_state.file_names != NULL) {
1137 for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {
1138 free(pvar->hosts_state.file_names[i]);
1139 }
1140 free(pvar->hosts_state.file_names);
1141 }
1142 }
1143
1144 /*
1145 * $Log: not supported by cvs2svn $
1146 * Revision 1.5 2006/03/26 17:07:17 yutakakn
1147 * fingerprint�\��������
1148 *
1149 * Revision 1.4 2006/03/26 15:43:58 yutakakn
1150 * SSH2��known_hosts���������������B
1151 *
1152 * Revision 1.3 2006/02/18 07:37:02 yutakakn
1153 * �E�R���p�C���� Visual Studio 2005 Standard Edition �������������B
1154 * �Estricmp()��_stricmp()���u������
1155 * �Estrdup()��_strdup()���u������
1156 *
1157 * Revision 1.2 2004/12/19 15:39:42 yutakakn
1158 * CVS LogID������
1159 *
1160 */

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