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 2861 - (show annotations) (download) (as text)
Tue Apr 4 13:52:52 2006 UTC (18 years ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/hosts.c
File MIME type: text/x-csrc
File size: 33380 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, int return_always)
618 {
619 int i;
620 int while_flg;
621
622 for (i = 0; hostname[i] != 0; i++) {
623 int ch = hostname[i];
624
625 if (!is_pattern_char(ch) || ch == '*' || ch == '?') {
626 if (!suppress_errors) {
627 notify_fatal_error(pvar,
628 "The host name contains an invalid character.\n"
629 "This session will be terminated.");
630 }
631 return 0;
632 }
633 }
634
635 if (i == 0) {
636 if (!suppress_errors) {
637 notify_fatal_error(pvar, "The host name should not be empty.\n"
638 "This session will be terminated.");
639 }
640 return 0;
641 }
642
643 #if 0
644 pvar->hosts_state.key_bits = 0;
645 free(pvar->hosts_state.key_exp);
646 pvar->hosts_state.key_exp = NULL;
647 free(pvar->hosts_state.key_mod);
648 pvar->hosts_state.key_mod = NULL;
649 #else
650 // hostkey type is KEY_UNSPEC.
651 init_hostkey(&pvar->hosts_state.hostkey);
652 #endif
653
654 do {
655 if (pvar->hosts_state.file_data == NULL
656 || pvar->hosts_state.file_data[pvar->hosts_state.
657 file_data_index] == 0) {
658 char FAR *filename;
659 int keep_going = 1;
660
661 if (pvar->hosts_state.file_data != NULL) {
662 end_read_file(pvar, suppress_errors);
663 }
664
665 do {
666 filename =
667 pvar->hosts_state.file_names[pvar->hosts_state.
668 file_num];
669
670 if (filename == NULL) {
671 return 1;
672 } else {
673 pvar->hosts_state.file_num++;
674
675 if (filename[0] != 0) {
676 if (begin_read_file
677 (pvar, filename, suppress_errors)) {
678 pvar->hosts_state.file_data_index = 0;
679 keep_going = 0;
680 }
681 }
682 }
683 } while (keep_going);
684 }
685
686 pvar->hosts_state.file_data_index +=
687 check_host_key(pvar, hostname,
688 pvar->hosts_state.file_data +
689 pvar->hosts_state.file_data_index);
690
691 if (!return_always) {
692 // �L�����L�[��������������
693 while_flg = (pvar->hosts_state.hostkey.type == KEY_UNSPEC);
694 }
695 else {
696 while_flg = 0;
697 }
698 } while (while_flg);
699
700 return 1;
701 }
702
703 static void finish_read_host_files(PTInstVar pvar, int suppress_errors)
704 {
705 if (pvar->hosts_state.file_data != NULL) {
706 end_read_file(pvar, suppress_errors);
707 }
708 }
709
710 // �T�[�o�����������O���Aknown_hosts�t�@�C�������z�X�g���J�������������������B
711 void HOSTS_prefetch_host_key(PTInstVar pvar, char FAR * hostname)
712 {
713 if (!begin_read_host_files(pvar, 1)) {
714 return;
715 }
716
717 if (!read_host_key(pvar, hostname, 1, 0)) {
718 return;
719 }
720
721 free(pvar->hosts_state.prefetched_hostname);
722 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
723
724 finish_read_host_files(pvar, 1);
725 }
726
727 static BOOL equal_mp_ints(unsigned char FAR * num1,
728 unsigned char FAR * num2)
729 {
730 if (num1 == NULL || num2 == NULL) {
731 return FALSE;
732 } else {
733 uint32 bytes = (get_ushort16_MSBfirst(num1) + 7) / 8;
734
735 if (bytes != (get_ushort16_MSBfirst(num2) + 7) / 8) {
736 return FALSE; /* different byte lengths */
737 } else {
738 return memcmp(num1 + 2, num2 + 2, bytes) == 0;
739 }
740 }
741 }
742
743 // ���J����������������������
744 static BOOL match_key(PTInstVar pvar, Key *key)
745 {
746 int bits;
747 unsigned char FAR * exp;
748 unsigned char FAR * mod;
749
750 if (key->type == KEY_RSA1) { // SSH1 host public key
751 bits = key->bits;
752 exp = key->exp;
753 mod = key->mod;
754
755 /* just check for equal exponent and modulus */
756 return equal_mp_ints(exp, pvar->hosts_state.hostkey.exp)
757 && equal_mp_ints(mod, pvar->hosts_state.hostkey.mod);
758 /*
759 return equal_mp_ints(exp, pvar->hosts_state.key_exp)
760 && equal_mp_ints(mod, pvar->hosts_state.key_mod);
761 */
762
763 } else if (key->type == KEY_RSA) { // SSH2 RSA host public key
764
765 return key->rsa != NULL && pvar->hosts_state.hostkey.rsa != NULL &&
766 BN_cmp(key->rsa->e, pvar->hosts_state.hostkey.rsa->e) == 0 &&
767 BN_cmp(key->rsa->n, pvar->hosts_state.hostkey.rsa->n) == 0;
768
769 } else { // // SSH2 DSA host public key
770
771 return key->dsa != NULL && pvar->hosts_state.hostkey.dsa &&
772 BN_cmp(key->dsa->p, pvar->hosts_state.hostkey.dsa->p) == 0 &&
773 BN_cmp(key->dsa->q, pvar->hosts_state.hostkey.dsa->q) == 0 &&
774 BN_cmp(key->dsa->g, pvar->hosts_state.hostkey.dsa->g) == 0 &&
775 BN_cmp(key->dsa->pub_key, pvar->hosts_state.hostkey.dsa->pub_key) == 0;
776
777 }
778
779 }
780
781 static void init_hosts_dlg(PTInstVar pvar, HWND dlg)
782 {
783 char buf[1024];
784 char buf2[2048];
785 int i, j;
786 int ch;
787 char *fp;
788
789 // static text�� # �������z�X�g�����u������
790 GetDlgItemText(dlg, IDC_HOSTWARNING, buf, sizeof(buf));
791 for (i = 0; (ch = buf[i]) != 0 && ch != '#'; i++) {
792 buf2[i] = ch;
793 }
794 if (sizeof(buf2) - i - 1 > 0) {
795 strncpy(buf2 + i, pvar->hosts_state.prefetched_hostname,
796 sizeof(buf2) - i - 1);
797 }
798 j = i + strlen(buf2 + i);
799 for (; buf[i] == '#'; i++) {
800 }
801 if (sizeof(buf2) - j - 1 > 0) {
802 strncpy(buf2 + j, buf + i, sizeof(buf2) - j - 1);
803 }
804 buf2[sizeof(buf2) - 1] = 0;
805
806 SetDlgItemText(dlg, IDC_HOSTWARNING, buf2);
807
808 // fingerprint����������
809 fp = key_fingerprint(&pvar->hosts_state.hostkey);
810 SendMessage(GetDlgItem(dlg, IDC_FINGER_PRINT), WM_SETTEXT, 0, (LPARAM)fp);
811 }
812
813 static int print_mp_int(char FAR * buf, unsigned char FAR * mp)
814 {
815 int i = 0, j, k;
816 BIGNUM *num = BN_new();
817 int ch;
818
819 BN_bin2bn(mp + 2, (get_ushort16_MSBfirst(mp) + 7) / 8, num);
820
821 do {
822 buf[i] = (char) ((BN_div_word(num, 10)) + '0');
823 i++;
824 } while (!BN_is_zero(num));
825
826 /* we need to reverse the digits */
827 for (j = 0, k = i - 1; j < k; j++, k--) {
828 ch = buf[j];
829 buf[j] = buf[k];
830 buf[k] = ch;
831 }
832
833 buf[i] = 0;
834 return i;
835 }
836
837 //
838 // known_hosts �t�@�C�������������G���g�������������B
839 //
840 static char FAR *format_host_key(PTInstVar pvar)
841 {
842 int host_len = strlen(pvar->hosts_state.prefetched_hostname);
843 char *result = NULL;
844 int index;
845 enum hostkey_type type = pvar->hosts_state.hostkey.type;
846
847 if (type == KEY_RSA1) {
848 result = (char FAR *) malloc(host_len
849 + 50 +
850 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.exp) /
851 3 +
852 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.mod) /
853 3);
854
855 strcpy(result, pvar->hosts_state.prefetched_hostname);
856 index = host_len;
857
858 sprintf(result + index, " %d ", pvar->hosts_state.hostkey.bits);
859 index += strlen(result + index);
860 index += print_mp_int(result + index, pvar->hosts_state.hostkey.exp);
861 result[index] = ' ';
862 index++;
863 index += print_mp_int(result + index, pvar->hosts_state.hostkey.mod);
864 strcpy(result + index, " \r\n");
865
866 } else if (type == KEY_RSA || type == KEY_DSA) {
867 Key *key = &pvar->hosts_state.hostkey;
868 char *blob = NULL;
869 int blen, uulen, msize;
870 char *uu = NULL;
871 int n;
872
873 key_to_blob(key, &blob, &blen);
874 uulen = 2 * blen;
875 uu = malloc(uulen);
876 if (uu == NULL) {
877 goto error;
878 }
879 n = uuencode(blob, blen, uu, uulen);
880 if (n > 0) {
881 msize = host_len + 50 + uulen;
882 result = malloc(msize);
883 if (result == NULL) {
884 goto error;
885 }
886
887 // setup
888 _snprintf(result, msize, "%s %s %s\r\n",
889 pvar->hosts_state.prefetched_hostname,
890 get_sshname_from_key(key),
891 uu);
892 }
893 error:
894 if (blob != NULL)
895 free(blob);
896 if (uu != NULL)
897 free(uu);
898
899 } else {
900 return NULL;
901
902 }
903
904 return result;
905 }
906
907 static void add_host_key(PTInstVar pvar)
908 {
909 char FAR *name = pvar->hosts_state.file_names[0];
910
911 if (name == NULL || name[0] == 0) {
912 notify_nonfatal_error(pvar,
913 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
914 "Restart Teraterm and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
915 } else {
916 char FAR *keydata = format_host_key(pvar);
917 int length = strlen(keydata);
918 int fd =
919 _open(name,
920 _O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL |
921 _O_BINARY,
922 _S_IREAD | _S_IWRITE);
923 int amount_written;
924 int close_result;
925
926 if (fd == -1) {
927 if (errno == EACCES) {
928 notify_nonfatal_error(pvar,
929 "An error occurred while trying to write the host key.\n"
930 "You do not have permission to write to the known-hosts file.");
931 } else {
932 notify_nonfatal_error(pvar,
933 "An error occurred while trying to write the host key.\n"
934 "The host key could not be written.");
935 }
936 return;
937 }
938
939 amount_written = _write(fd, keydata, length);
940 free(keydata);
941 close_result = _close(fd);
942
943 if (amount_written != length || close_result == -1) {
944 notify_nonfatal_error(pvar,
945 "An error occurred while trying to write the host key.\n"
946 "The host key could not be written.");
947 }
948 }
949 }
950
951 static char FAR *copy_mp_int(char FAR * num)
952 {
953 int len = (get_ushort16_MSBfirst(num) + 7) / 8 + 2;
954 char FAR *result = (char FAR *) malloc(len);
955
956 if (result != NULL) {
957 memcpy(result, num, len);
958 }
959
960 return result;
961 }
962
963 //
964 // �����z�X�g�����e���������L�[����������
965 // add_host_key ����������������
966 //
967 static void delete_different_key(PTInstVar pvar)
968 {
969 char FAR *name = pvar->hosts_state.file_names[0];
970
971 if (name == NULL || name[0] == 0) {
972 notify_nonfatal_error(pvar,
973 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
974 "Restart Teraterm and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
975 }
976 else {
977 Key key; // ���������z�X�g���L�[
978 int length = strlen(name);
979 char filename[L_tmpnam];
980 int fd;
981 int amount_written = 0;
982 int close_result;
983 int data_index = 0;
984
985 // �������������t�@�C�����J��
986 tmpnam(filename);
987 fd =
988 _open(filename,
989 _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY |
990 _O_TRUNC,
991 _S_IREAD | _S_IWRITE);
992
993 if (fd == -1) {
994 if (errno == EACCES) {
995 notify_nonfatal_error(pvar,
996 "An error occurred while trying to write the host key.\n"
997 "You do not have permission to write to the known-hosts file.");
998 } else {
999 notify_nonfatal_error(pvar,
1000 "An error occurred while trying to write the host key.\n"
1001 "The host key could not be written.");
1002 }
1003 free(filename);
1004 return;
1005 }
1006
1007 // ���������T�[�o���L�[����������
1008 if (pvar->hosts_state.hostkey.type == KEY_RSA1) { // SSH1
1009 key.type = KEY_RSA1;
1010 key.bits = pvar->hosts_state.hostkey.bits;
1011 key.exp = copy_mp_int(pvar->hosts_state.hostkey.exp);
1012 key.mod = copy_mp_int(pvar->hosts_state.hostkey.mod);
1013 } else if (pvar->hosts_state.hostkey.type == KEY_RSA) { // SSH2 RSA
1014 key.type = KEY_RSA;
1015 key.rsa = duplicate_RSA(pvar->hosts_state.hostkey.rsa);
1016 } else { // SSH2 DSA
1017 key.type = KEY_DSA;
1018 key.dsa = duplicate_DSA(pvar->hosts_state.hostkey.dsa);
1019 }
1020
1021 // �t�@�C��������������
1022 begin_read_host_files(pvar, 0);
1023 do {
1024 int host_index = 0;
1025 int matched = 0;
1026 int keybits = 0;
1027 char FAR *data;
1028 int do_write = 0;
1029 length = amount_written = 0;
1030
1031 if (!read_host_key(pvar, pvar->ssh_state.hostname, 0, 1)) {
1032 break;
1033 }
1034
1035 if (data_index == pvar->hosts_state.file_data_index) {
1036 // index ���i������ == ��������������
1037 break;
1038 }
1039
1040 data = pvar->hosts_state.file_data + data_index;
1041 host_index = eat_spaces(data);
1042
1043 if (data[host_index] == '#') {
1044 do_write = 1;
1045 }
1046 else {
1047 // �z�X�g������
1048 host_index--;
1049 do {
1050 int negated;
1051
1052 host_index++;
1053 negated = data[host_index] == '!';
1054
1055 if (negated) {
1056 host_index++;
1057 if (match_pattern(data + host_index,
1058 pvar->ssh_state.hostname)) {
1059 matched = 0;
1060 // �����o�[�W�����`�F�b�N�������� host_index ���i��������������
1061 host_index--;
1062 do {
1063 host_index++;
1064 host_index += eat_to_end_of_pattern(data + host_index);
1065 } while (data[host_index] == ',');
1066 break;
1067 }
1068 }
1069 else if (match_pattern(data + host_index,
1070 pvar->ssh_state.hostname)) {
1071 matched = 1;
1072 }
1073 host_index += eat_to_end_of_pattern(data + host_index);
1074 } while (data[host_index] == ',');
1075
1076 // �z�X�g�������������v�����L�[����������
1077 if (match_key(pvar, &key)) {
1078 do_write = 1;
1079 }
1080 // �z�X�g������������
1081 else if (!matched) {
1082 do_write = 1;
1083 }
1084 // �z�X�g�������� and �������o�[�W����������
1085 else {
1086 int rsa1_key_bits=0;
1087 rsa1_key_bits = atoi(data + host_index + eat_spaces(data + host_index));
1088
1089 if (rsa1_key_bits > 0) { // �t�@�C�����L�[�� ssh1
1090 if (!SSHv1(pvar)) {
1091 do_write = 1;
1092 }
1093 }
1094 else { // �t�@�C�����L�[�� ssh2
1095 if (!SSHv2(pvar)) {
1096 do_write = 1;
1097 }
1098 }
1099 }
1100 }
1101
1102 // ������������
1103 if (do_write) {
1104 length = pvar->hosts_state.file_data_index - data_index;
1105 amount_written =
1106 _write(fd, pvar->hosts_state.file_data + data_index,
1107 length);
1108
1109 if (amount_written != length) {
1110 goto error1;
1111 }
1112 }
1113 data_index = pvar->hosts_state.file_data_index;
1114 } while (1); // ������������
1115
1116 error1:
1117 close_result = _close(fd);
1118 if (amount_written != length || close_result == -1) {
1119 notify_nonfatal_error(pvar,
1120 "An error occurred while trying to write the host key.\n"
1121 "The host key could not be written.");
1122 goto error2;
1123 }
1124
1125 // �������������t�@�C���������l�[��
1126 _unlink(pvar->hosts_state.file_names[0]);
1127 rename(filename, pvar->hosts_state.file_names[0]);
1128
1129 error2:
1130 _unlink(filename);
1131
1132 finish_read_host_files(pvar, 0);
1133 }
1134 }
1135
1136 //
1137 // Unknown host���z�X�g���J���� known_hosts �t�@�C����������������������
1138 // ���[�U���m�F�������B
1139 // TODO: finger print���\�����s���B
1140 // (2006.3.25 yutaka)
1141 //
1142 static BOOL CALLBACK hosts_add_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1143 LPARAM lParam)
1144 {
1145 PTInstVar pvar;
1146
1147 switch (msg) {
1148 case WM_INITDIALOG:
1149 pvar = (PTInstVar) lParam;
1150 pvar->hosts_state.hosts_dialog = dlg;
1151 SetWindowLong(dlg, DWL_USER, lParam);
1152
1153 init_hosts_dlg(pvar, dlg);
1154
1155 // add host check box���`�F�b�N���f�t�H���g������������
1156 SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
1157
1158 return TRUE; /* because we do not set the focus */
1159
1160 case WM_COMMAND:
1161 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
1162
1163 switch (LOWORD(wParam)) {
1164 case IDC_CONTINUE:
1165 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1166 add_host_key(pvar);
1167 }
1168
1169 if (SSHv1(pvar)) {
1170 SSH_notify_host_OK(pvar);
1171 } else { // SSH2
1172 // SSH2���������� SSH_notify_host_OK() �������B
1173 }
1174
1175 pvar->hosts_state.hosts_dialog = NULL;
1176
1177 EndDialog(dlg, 1);
1178 return TRUE;
1179
1180 case IDCANCEL: /* kill the connection */
1181 pvar->hosts_state.hosts_dialog = NULL;
1182 notify_closed_connection(pvar);
1183 EndDialog(dlg, 0);
1184 return TRUE;
1185
1186 default:
1187 return FALSE;
1188 }
1189
1190 default:
1191 return FALSE;
1192 }
1193 }
1194
1195 //
1196 // �u�����������m�F�_�C�A���O������
1197 //
1198 static BOOL CALLBACK hosts_replace_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1199 LPARAM lParam)
1200 {
1201 PTInstVar pvar;
1202
1203 switch (msg) {
1204 case WM_INITDIALOG:
1205 pvar = (PTInstVar) lParam;
1206 pvar->hosts_state.hosts_dialog = dlg;
1207 SetWindowLong(dlg, DWL_USER, lParam);
1208
1209 init_hosts_dlg(pvar, dlg);
1210
1211 // �f�t�H���g���`�F�b�N����������
1212 return TRUE; /* because we do not set the focus */
1213
1214 case WM_COMMAND:
1215 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
1216
1217 switch (LOWORD(wParam)) {
1218 case IDC_CONTINUE:
1219 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1220 add_host_key(pvar);
1221 delete_different_key(pvar);
1222 }
1223
1224 if (SSHv1(pvar)) {
1225 SSH_notify_host_OK(pvar);
1226 } else { // SSH2
1227 // SSH2���������� SSH_notify_host_OK() �������B
1228 }
1229
1230 pvar->hosts_state.hosts_dialog = NULL;
1231
1232 EndDialog(dlg, 1);
1233 return TRUE;
1234
1235 case IDCANCEL: /* kill the connection */
1236 pvar->hosts_state.hosts_dialog = NULL;
1237 notify_closed_connection(pvar);
1238 EndDialog(dlg, 0);
1239 return TRUE;
1240
1241 default:
1242 return FALSE;
1243 }
1244
1245 default:
1246 return FALSE;
1247 }
1248 }
1249
1250 void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar)
1251 {
1252 if (pvar->hosts_state.hosts_dialog == NULL) {
1253 HWND cur_active = GetActiveWindow();
1254
1255 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST),
1256 cur_active != NULL ? cur_active : wnd,
1257 hosts_add_dlg_proc, (LPARAM) pvar);
1258 }
1259 }
1260
1261 void HOSTS_do_different_host_dialog(HWND wnd, PTInstVar pvar)
1262 {
1263 if (pvar->hosts_state.hosts_dialog == NULL) {
1264 HWND cur_active = GetActiveWindow();
1265
1266 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTHOST),
1267 cur_active != NULL ? cur_active : wnd,
1268 hosts_replace_dlg_proc, (LPARAM) pvar);
1269 }
1270 }
1271
1272 //
1273 // �T�[�o�����������������z�X�g���J�������������`�F�b�N����
1274 //
1275 // SSH2���������� (2006.3.24 yutaka)
1276 //
1277 BOOL HOSTS_check_host_key(PTInstVar pvar, char FAR * hostname, Key *key)
1278 {
1279 int found_different_key = 0;
1280
1281 // ������ known_hosts �t�@�C�������z�X�g���J�����������������������A���������r�����B
1282 if (pvar->hosts_state.prefetched_hostname != NULL
1283 && _stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0
1284 && match_key(pvar, key)) {
1285
1286 if (SSHv1(pvar)) {
1287 SSH_notify_host_OK(pvar);
1288 } else {
1289 // SSH2���������� SSH_notify_host_OK() �������B
1290 }
1291 return TRUE;
1292 }
1293
1294 // �������������������������A�������_���t�@�C��������������
1295 if (begin_read_host_files(pvar, 0)) {
1296 do {
1297 if (!read_host_key(pvar, hostname, 0, 0)) {
1298 break;
1299 }
1300
1301 if (pvar->hosts_state.hostkey.type != KEY_UNSPEC) {
1302 if (match_key(pvar, key)) {
1303 finish_read_host_files(pvar, 0);
1304 // ���������G���g�����Q�������A���v�����L�[�������������������B
1305 // SSH2���������������������������B(2006.3.29 yutaka)
1306 if (SSHv1(pvar)) {
1307 SSH_notify_host_OK(pvar);
1308 } else {
1309 // SSH2���������� SSH_notify_host_OK() �������B
1310 }
1311 return TRUE;
1312 } else {
1313 // �L�[�� known_hosts ���������������A�L�[�����e���������B
1314 found_different_key = 1;
1315 }
1316 }
1317 } while (pvar->hosts_state.hostkey.type != KEY_UNSPEC); // �L�[�����������������������[�v����
1318
1319 finish_read_host_files(pvar, 0);
1320 }
1321
1322
1323 // known_hosts �������������L�[���������t�@�C�������������������A�������������������B
1324 pvar->hosts_state.hostkey.type = key->type;
1325 if (key->type == KEY_RSA1) { // SSH1
1326 pvar->hosts_state.hostkey.bits = key->bits;
1327 pvar->hosts_state.hostkey.exp = copy_mp_int(key->exp);
1328 pvar->hosts_state.hostkey.mod = copy_mp_int(key->mod);
1329
1330 } else if (key->type == KEY_RSA) { // SSH2 RSA
1331 pvar->hosts_state.hostkey.rsa = duplicate_RSA(key->rsa);
1332
1333 } else { // SSH2 DSA
1334 pvar->hosts_state.hostkey.dsa = duplicate_DSA(key->dsa);
1335
1336 }
1337 free(pvar->hosts_state.prefetched_hostname);
1338 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
1339
1340 if (found_different_key) {
1341 PostMessage(pvar->NotificationWindow, WM_COMMAND,
1342 ID_SSHDIFFERENTHOST, 0);
1343 } else {
1344 PostMessage(pvar->NotificationWindow, WM_COMMAND,
1345 ID_SSHUNKNOWNHOST, 0);
1346 }
1347
1348 return TRUE;
1349 }
1350
1351 void HOSTS_notify_disconnecting(PTInstVar pvar)
1352 {
1353 if (pvar->hosts_state.hosts_dialog != NULL) {
1354 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL,
1355 0);
1356 /* the main window might not go away if it's not enabled. (see vtwin.cpp) */
1357 EnableWindow(pvar->NotificationWindow, TRUE);
1358 }
1359 }
1360
1361 void HOSTS_end(PTInstVar pvar)
1362 {
1363 int i;
1364
1365 free(pvar->hosts_state.prefetched_hostname);
1366 #if 0
1367 free(pvar->hosts_state.key_exp);
1368 free(pvar->hosts_state.key_mod);
1369 #else
1370 init_hostkey(&pvar->hosts_state.hostkey);
1371 #endif
1372
1373 if (pvar->hosts_state.file_names != NULL) {
1374 for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {
1375 free(pvar->hosts_state.file_names[i]);
1376 }
1377 free(pvar->hosts_state.file_names);
1378 }
1379 }
1380
1381 /*
1382 * $Log: not supported by cvs2svn $
1383 * Revision 1.6 2006/03/29 14:56:52 yutakakn
1384 * known_hosts�t�@�C�����L�[�����������������z�X�g���G���g�����������A�A�v���P�[�V�����G���[�������o�O���C�������B
1385 *
1386 * Revision 1.5 2006/03/26 17:07:17 yutakakn
1387 * fingerprint�\��������
1388 *
1389 * Revision 1.4 2006/03/26 15:43:58 yutakakn
1390 * SSH2��known_hosts���������������B
1391 *
1392 * Revision 1.3 2006/02/18 07:37:02 yutakakn
1393 * �E�R���p�C���� Visual Studio 2005 Standard Edition �������������B
1394 * �Estricmp()��_stricmp()���u������
1395 * �Estrdup()��_strdup()���u������
1396 *
1397 * Revision 1.2 2004/12/19 15:39:42 yutakakn
1398 * CVS LogID������
1399 *
1400 */

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