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 2876 - (show annotations) (download) (as text)
Thu Jun 29 15:27:00 2006 UTC (17 years, 9 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/hosts.c
File MIME type: text/x-csrc
File size: 33633 byte(s)
ssh_known_filesファイルを常にTeraTermインストールディレクトリへ保存するようにした。

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 buf[FILENAME_MAX];
910 char FAR *name = pvar->hosts_state.file_names[0];
911 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
912
913 if (buf == NULL || buf[0] == 0) {
914 notify_nonfatal_error(pvar,
915 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
916 "Restart Teraterm and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
917 } else {
918 char FAR *keydata = format_host_key(pvar);
919 int length = strlen(keydata);
920 int fd =
921 _open(buf,
922 _O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL |
923 _O_BINARY,
924 _S_IREAD | _S_IWRITE);
925 int amount_written;
926 int close_result;
927
928 if (fd == -1) {
929 if (errno == EACCES) {
930 notify_nonfatal_error(pvar,
931 "An error occurred while trying to write the host key.\n"
932 "You do not have permission to write to the known-hosts file.");
933 } else {
934 notify_nonfatal_error(pvar,
935 "An error occurred while trying to write the host key.\n"
936 "The host key could not be written.");
937 }
938 return;
939 }
940
941 amount_written = _write(fd, keydata, length);
942 free(keydata);
943 close_result = _close(fd);
944
945 if (amount_written != length || close_result == -1) {
946 notify_nonfatal_error(pvar,
947 "An error occurred while trying to write the host key.\n"
948 "The host key could not be written.");
949 }
950 }
951 }
952
953 static char FAR *copy_mp_int(char FAR * num)
954 {
955 int len = (get_ushort16_MSBfirst(num) + 7) / 8 + 2;
956 char FAR *result = (char FAR *) malloc(len);
957
958 if (result != NULL) {
959 memcpy(result, num, len);
960 }
961
962 return result;
963 }
964
965 //
966 // �����z�X�g�����e���������L�[����������
967 // add_host_key ����������������
968 //
969 static void delete_different_key(PTInstVar pvar)
970 {
971 char buf[FILENAME_MAX];
972 char FAR *name = pvar->hosts_state.file_names[0];
973 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
974
975 if (buf == NULL || buf[0] == 0) {
976 notify_nonfatal_error(pvar,
977 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
978 "Restart Teraterm and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
979 }
980 else {
981 Key key; // ���������z�X�g���L�[
982 int length;
983 char filename[L_tmpnam];
984 int fd;
985 int amount_written = 0;
986 int close_result;
987 int data_index = 0;
988
989 // �������������t�@�C�����J��
990 tmpnam(filename);
991 fd =
992 _open(filename,
993 _O_CREAT | _O_WRONLY | _O_SEQUENTIAL | _O_BINARY |
994 _O_TRUNC,
995 _S_IREAD | _S_IWRITE);
996
997 if (fd == -1) {
998 if (errno == EACCES) {
999 notify_nonfatal_error(pvar,
1000 "An error occurred while trying to write the host key.\n"
1001 "You do not have permission to write to the known-hosts file.");
1002 } else {
1003 notify_nonfatal_error(pvar,
1004 "An error occurred while trying to write the host key.\n"
1005 "The host key could not be written.");
1006 }
1007 free(filename);
1008 return;
1009 }
1010
1011 // ���������T�[�o���L�[����������
1012 if (pvar->hosts_state.hostkey.type == KEY_RSA1) { // SSH1
1013 key.type = KEY_RSA1;
1014 key.bits = pvar->hosts_state.hostkey.bits;
1015 key.exp = copy_mp_int(pvar->hosts_state.hostkey.exp);
1016 key.mod = copy_mp_int(pvar->hosts_state.hostkey.mod);
1017 } else if (pvar->hosts_state.hostkey.type == KEY_RSA) { // SSH2 RSA
1018 key.type = KEY_RSA;
1019 key.rsa = duplicate_RSA(pvar->hosts_state.hostkey.rsa);
1020 } else { // SSH2 DSA
1021 key.type = KEY_DSA;
1022 key.dsa = duplicate_DSA(pvar->hosts_state.hostkey.dsa);
1023 }
1024
1025 // �t�@�C��������������
1026 begin_read_host_files(pvar, 0);
1027 do {
1028 int host_index = 0;
1029 int matched = 0;
1030 int keybits = 0;
1031 char FAR *data;
1032 int do_write = 0;
1033 length = amount_written = 0;
1034
1035 if (!read_host_key(pvar, pvar->ssh_state.hostname, 0, 1)) {
1036 break;
1037 }
1038
1039 if (data_index == pvar->hosts_state.file_data_index) {
1040 // index ���i������ == ��������������
1041 break;
1042 }
1043
1044 data = pvar->hosts_state.file_data + data_index;
1045 host_index = eat_spaces(data);
1046
1047 if (data[host_index] == '#') {
1048 do_write = 1;
1049 }
1050 else {
1051 // �z�X�g������
1052 host_index--;
1053 do {
1054 int negated;
1055
1056 host_index++;
1057 negated = data[host_index] == '!';
1058
1059 if (negated) {
1060 host_index++;
1061 if (match_pattern(data + host_index,
1062 pvar->ssh_state.hostname)) {
1063 matched = 0;
1064 // �����o�[�W�����`�F�b�N�������� host_index ���i��������������
1065 host_index--;
1066 do {
1067 host_index++;
1068 host_index += eat_to_end_of_pattern(data + host_index);
1069 } while (data[host_index] == ',');
1070 break;
1071 }
1072 }
1073 else if (match_pattern(data + host_index,
1074 pvar->ssh_state.hostname)) {
1075 matched = 1;
1076 }
1077 host_index += eat_to_end_of_pattern(data + host_index);
1078 } while (data[host_index] == ',');
1079
1080 // �z�X�g�������������v�����L�[����������
1081 if (match_key(pvar, &key)) {
1082 do_write = 1;
1083 }
1084 // �z�X�g������������
1085 else if (!matched) {
1086 do_write = 1;
1087 }
1088 // �z�X�g�������� and �������o�[�W����������
1089 else {
1090 int rsa1_key_bits=0;
1091 rsa1_key_bits = atoi(data + host_index + eat_spaces(data + host_index));
1092
1093 if (rsa1_key_bits > 0) { // �t�@�C�����L�[�� ssh1
1094 if (!SSHv1(pvar)) {
1095 do_write = 1;
1096 }
1097 }
1098 else { // �t�@�C�����L�[�� ssh2
1099 if (!SSHv2(pvar)) {
1100 do_write = 1;
1101 }
1102 }
1103 }
1104 }
1105
1106 // ������������
1107 if (do_write) {
1108 length = pvar->hosts_state.file_data_index - data_index;
1109 amount_written =
1110 _write(fd, pvar->hosts_state.file_data + data_index,
1111 length);
1112
1113 if (amount_written != length) {
1114 goto error1;
1115 }
1116 }
1117 data_index = pvar->hosts_state.file_data_index;
1118 } while (1); // ������������
1119
1120 error1:
1121 close_result = _close(fd);
1122 if (amount_written != length || close_result == -1) {
1123 notify_nonfatal_error(pvar,
1124 "An error occurred while trying to write the host key.\n"
1125 "The host key could not be written.");
1126 goto error2;
1127 }
1128
1129 // �������������t�@�C���������l�[��
1130 _unlink(buf);
1131 rename(filename, buf);
1132
1133 error2:
1134 _unlink(filename);
1135
1136 finish_read_host_files(pvar, 0);
1137 }
1138 }
1139
1140 //
1141 // Unknown host���z�X�g���J���� known_hosts �t�@�C����������������������
1142 // ���[�U���m�F�������B
1143 // TODO: finger print���\�����s���B
1144 // (2006.3.25 yutaka)
1145 //
1146 static BOOL CALLBACK hosts_add_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1147 LPARAM lParam)
1148 {
1149 PTInstVar pvar;
1150
1151 switch (msg) {
1152 case WM_INITDIALOG:
1153 pvar = (PTInstVar) lParam;
1154 pvar->hosts_state.hosts_dialog = dlg;
1155 SetWindowLong(dlg, DWL_USER, lParam);
1156
1157 init_hosts_dlg(pvar, dlg);
1158
1159 // add host check box���`�F�b�N���f�t�H���g������������
1160 SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
1161
1162 return TRUE; /* because we do not set the focus */
1163
1164 case WM_COMMAND:
1165 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
1166
1167 switch (LOWORD(wParam)) {
1168 case IDC_CONTINUE:
1169 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1170 add_host_key(pvar);
1171 }
1172
1173 if (SSHv1(pvar)) {
1174 SSH_notify_host_OK(pvar);
1175 } else { // SSH2
1176 // SSH2���������� SSH_notify_host_OK() �������B
1177 }
1178
1179 pvar->hosts_state.hosts_dialog = NULL;
1180
1181 EndDialog(dlg, 1);
1182 return TRUE;
1183
1184 case IDCANCEL: /* kill the connection */
1185 pvar->hosts_state.hosts_dialog = NULL;
1186 notify_closed_connection(pvar);
1187 EndDialog(dlg, 0);
1188 return TRUE;
1189
1190 default:
1191 return FALSE;
1192 }
1193
1194 default:
1195 return FALSE;
1196 }
1197 }
1198
1199 //
1200 // �u�����������m�F�_�C�A���O������
1201 //
1202 static BOOL CALLBACK hosts_replace_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
1203 LPARAM lParam)
1204 {
1205 PTInstVar pvar;
1206
1207 switch (msg) {
1208 case WM_INITDIALOG:
1209 pvar = (PTInstVar) lParam;
1210 pvar->hosts_state.hosts_dialog = dlg;
1211 SetWindowLong(dlg, DWL_USER, lParam);
1212
1213 init_hosts_dlg(pvar, dlg);
1214
1215 // �f�t�H���g���`�F�b�N����������
1216 return TRUE; /* because we do not set the focus */
1217
1218 case WM_COMMAND:
1219 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
1220
1221 switch (LOWORD(wParam)) {
1222 case IDC_CONTINUE:
1223 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
1224 add_host_key(pvar);
1225 delete_different_key(pvar);
1226 }
1227
1228 if (SSHv1(pvar)) {
1229 SSH_notify_host_OK(pvar);
1230 } else { // SSH2
1231 // SSH2���������� SSH_notify_host_OK() �������B
1232 }
1233
1234 pvar->hosts_state.hosts_dialog = NULL;
1235
1236 EndDialog(dlg, 1);
1237 return TRUE;
1238
1239 case IDCANCEL: /* kill the connection */
1240 pvar->hosts_state.hosts_dialog = NULL;
1241 notify_closed_connection(pvar);
1242 EndDialog(dlg, 0);
1243 return TRUE;
1244
1245 default:
1246 return FALSE;
1247 }
1248
1249 default:
1250 return FALSE;
1251 }
1252 }
1253
1254 void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar)
1255 {
1256 if (pvar->hosts_state.hosts_dialog == NULL) {
1257 HWND cur_active = GetActiveWindow();
1258
1259 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST),
1260 cur_active != NULL ? cur_active : wnd,
1261 hosts_add_dlg_proc, (LPARAM) pvar);
1262 }
1263 }
1264
1265 void HOSTS_do_different_host_dialog(HWND wnd, PTInstVar pvar)
1266 {
1267 if (pvar->hosts_state.hosts_dialog == NULL) {
1268 HWND cur_active = GetActiveWindow();
1269
1270 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTHOST),
1271 cur_active != NULL ? cur_active : wnd,
1272 hosts_replace_dlg_proc, (LPARAM) pvar);
1273 }
1274 }
1275
1276 //
1277 // �T�[�o�����������������z�X�g���J�������������`�F�b�N����
1278 //
1279 // SSH2���������� (2006.3.24 yutaka)
1280 //
1281 BOOL HOSTS_check_host_key(PTInstVar pvar, char FAR * hostname, Key *key)
1282 {
1283 int found_different_key = 0;
1284
1285 // ������ known_hosts �t�@�C�������z�X�g���J�����������������������A���������r�����B
1286 if (pvar->hosts_state.prefetched_hostname != NULL
1287 && _stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0
1288 && match_key(pvar, key)) {
1289
1290 if (SSHv1(pvar)) {
1291 SSH_notify_host_OK(pvar);
1292 } else {
1293 // SSH2���������� SSH_notify_host_OK() �������B
1294 }
1295 return TRUE;
1296 }
1297
1298 // �������������������������A�������_���t�@�C��������������
1299 if (begin_read_host_files(pvar, 0)) {
1300 do {
1301 if (!read_host_key(pvar, hostname, 0, 0)) {
1302 break;
1303 }
1304
1305 if (pvar->hosts_state.hostkey.type != KEY_UNSPEC) {
1306 if (match_key(pvar, key)) {
1307 finish_read_host_files(pvar, 0);
1308 // ���������G���g�����Q�������A���v�����L�[�������������������B
1309 // SSH2���������������������������B(2006.3.29 yutaka)
1310 if (SSHv1(pvar)) {
1311 SSH_notify_host_OK(pvar);
1312 } else {
1313 // SSH2���������� SSH_notify_host_OK() �������B
1314 }
1315 return TRUE;
1316 } else {
1317 // �L�[�� known_hosts ���������������A�L�[�����e���������B
1318 found_different_key = 1;
1319 }
1320 }
1321 } while (pvar->hosts_state.hostkey.type != KEY_UNSPEC); // �L�[�����������������������[�v����
1322
1323 finish_read_host_files(pvar, 0);
1324 }
1325
1326
1327 // known_hosts �������������L�[���������t�@�C�������������������A�������������������B
1328 pvar->hosts_state.hostkey.type = key->type;
1329 if (key->type == KEY_RSA1) { // SSH1
1330 pvar->hosts_state.hostkey.bits = key->bits;
1331 pvar->hosts_state.hostkey.exp = copy_mp_int(key->exp);
1332 pvar->hosts_state.hostkey.mod = copy_mp_int(key->mod);
1333
1334 } else if (key->type == KEY_RSA) { // SSH2 RSA
1335 pvar->hosts_state.hostkey.rsa = duplicate_RSA(key->rsa);
1336
1337 } else { // SSH2 DSA
1338 pvar->hosts_state.hostkey.dsa = duplicate_DSA(key->dsa);
1339
1340 }
1341 free(pvar->hosts_state.prefetched_hostname);
1342 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
1343
1344 if (found_different_key) {
1345 PostMessage(pvar->NotificationWindow, WM_COMMAND,
1346 ID_SSHDIFFERENTHOST, 0);
1347 } else {
1348 PostMessage(pvar->NotificationWindow, WM_COMMAND,
1349 ID_SSHUNKNOWNHOST, 0);
1350 }
1351
1352 return TRUE;
1353 }
1354
1355 void HOSTS_notify_disconnecting(PTInstVar pvar)
1356 {
1357 if (pvar->hosts_state.hosts_dialog != NULL) {
1358 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL,
1359 0);
1360 /* the main window might not go away if it's not enabled. (see vtwin.cpp) */
1361 EnableWindow(pvar->NotificationWindow, TRUE);
1362 }
1363 }
1364
1365 void HOSTS_end(PTInstVar pvar)
1366 {
1367 int i;
1368
1369 free(pvar->hosts_state.prefetched_hostname);
1370 #if 0
1371 free(pvar->hosts_state.key_exp);
1372 free(pvar->hosts_state.key_mod);
1373 #else
1374 init_hostkey(&pvar->hosts_state.hostkey);
1375 #endif
1376
1377 if (pvar->hosts_state.file_names != NULL) {
1378 for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {
1379 free(pvar->hosts_state.file_names[i]);
1380 }
1381 free(pvar->hosts_state.file_names);
1382 }
1383 }
1384
1385 /*
1386 * $Log: not supported by cvs2svn $
1387 * Revision 1.7 2006/04/04 13:52:52 yutakakn
1388 * known_hosts�t�@�C�����������L�[�����������������z�X�g���G���g���������������A�����L�[�����������@�\�����������B
1389 *
1390 * Revision 1.6 2006/03/29 14:56:52 yutakakn
1391 * known_hosts�t�@�C�����L�[�����������������z�X�g���G���g�����������A�A�v���P�[�V�����G���[�������o�O���C�������B
1392 *
1393 * Revision 1.5 2006/03/26 17:07:17 yutakakn
1394 * fingerprint�\��������
1395 *
1396 * Revision 1.4 2006/03/26 15:43:58 yutakakn
1397 * SSH2��known_hosts���������������B
1398 *
1399 * Revision 1.3 2006/02/18 07:37:02 yutakakn
1400 * �E�R���p�C���� Visual Studio 2005 Standard Edition �������������B
1401 * �Estricmp()��_stricmp()���u������
1402 * �Estrdup()��_strdup()���u������
1403 *
1404 * Revision 1.2 2004/12/19 15:39:42 yutakakn
1405 * CVS LogID������
1406 *
1407 */

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