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 2856 - (show annotations) (download) (as text)
Sun Mar 26 15:43:58 2006 UTC (18 years ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/hosts.c
File MIME type: text/x-csrc
File size: 26885 byte(s)
SSH2の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
779 GetDlgItemText(dlg, IDC_HOSTWARNING, buf, sizeof(buf));
780 for (i = 0; (ch = buf[i]) != 0 && ch != '#'; i++) {
781 buf2[i] = ch;
782 }
783 if (sizeof(buf2) - i - 1 > 0) {
784 strncpy(buf2 + i, pvar->hosts_state.prefetched_hostname,
785 sizeof(buf2) - i - 1);
786 }
787 j = i + strlen(buf2 + i);
788 for (; buf[i] == '#'; i++) {
789 }
790 if (sizeof(buf2) - j - 1 > 0) {
791 strncpy(buf2 + j, buf + i, sizeof(buf2) - j - 1);
792 }
793 buf2[sizeof(buf2) - 1] = 0;
794
795 SetDlgItemText(dlg, IDC_HOSTWARNING, buf2);
796 }
797
798 static int print_mp_int(char FAR * buf, unsigned char FAR * mp)
799 {
800 int i = 0, j, k;
801 BIGNUM *num = BN_new();
802 int ch;
803
804 BN_bin2bn(mp + 2, (get_ushort16_MSBfirst(mp) + 7) / 8, num);
805
806 do {
807 buf[i] = (char) ((BN_div_word(num, 10)) + '0');
808 i++;
809 } while (!BN_is_zero(num));
810
811 /* we need to reverse the digits */
812 for (j = 0, k = i - 1; j < k; j++, k--) {
813 ch = buf[j];
814 buf[j] = buf[k];
815 buf[k] = ch;
816 }
817
818 buf[i] = 0;
819 return i;
820 }
821
822 //
823 // known_hosts �t�@�C�������������G���g�������������B
824 //
825 static char FAR *format_host_key(PTInstVar pvar)
826 {
827 int host_len = strlen(pvar->hosts_state.prefetched_hostname);
828 char *result = NULL;
829 int index;
830 enum hostkey_type type = pvar->hosts_state.hostkey.type;
831
832 if (type == KEY_RSA1) {
833 result = (char FAR *) malloc(host_len
834 + 50 +
835 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.exp) /
836 3 +
837 get_ushort16_MSBfirst(pvar->hosts_state.hostkey.mod) /
838 3);
839
840 strcpy(result, pvar->hosts_state.prefetched_hostname);
841 index = host_len;
842
843 sprintf(result + index, " %d ", pvar->hosts_state.hostkey.bits);
844 index += strlen(result + index);
845 index += print_mp_int(result + index, pvar->hosts_state.hostkey.exp);
846 result[index] = ' ';
847 index++;
848 index += print_mp_int(result + index, pvar->hosts_state.hostkey.mod);
849 strcpy(result + index, " \r\n");
850
851 } else if (type == KEY_RSA || type == KEY_DSA) {
852 Key *key = &pvar->hosts_state.hostkey;
853 char *blob = NULL;
854 int blen, uulen, msize;
855 char *uu = NULL;
856 int n;
857
858 key_to_blob(key, &blob, &blen);
859 uulen = 2 * blen;
860 uu = malloc(uulen);
861 if (uu == NULL) {
862 goto error;
863 }
864 n = uuencode(blob, blen, uu, uulen);
865 if (n > 0) {
866 msize = host_len + 50 + uulen;
867 result = malloc(msize);
868 if (result == NULL) {
869 goto error;
870 }
871
872 // setup
873 _snprintf(result, msize, "%s %s %s\r\n",
874 pvar->hosts_state.prefetched_hostname,
875 get_sshname_from_key(key),
876 uu);
877 }
878 error:
879 if (blob != NULL)
880 free(blob);
881 if (uu != NULL)
882 free(uu);
883
884 } else {
885 return NULL;
886
887 }
888
889 return result;
890 }
891
892 static void add_host_key(PTInstVar pvar)
893 {
894 char FAR *name = pvar->hosts_state.file_names[0];
895
896 if (name == NULL || name[0] == 0) {
897 notify_nonfatal_error(pvar,
898 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
899 "Restart Teraterm and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
900 } else {
901 char FAR *keydata = format_host_key(pvar);
902 int length = strlen(keydata);
903 int fd =
904 _open(name,
905 _O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL |
906 _O_BINARY,
907 _S_IREAD | _S_IWRITE);
908 int amount_written;
909 int close_result;
910
911 if (fd == -1) {
912 if (errno == EACCES) {
913 notify_nonfatal_error(pvar,
914 "An error occurred while trying to write the host key.\n"
915 "You do not have permission to write to the known-hosts file.");
916 } else {
917 notify_nonfatal_error(pvar,
918 "An error occurred while trying to write the host key.\n"
919 "The host key could not be written.");
920 }
921 return;
922 }
923
924 amount_written = _write(fd, keydata, length);
925 free(keydata);
926 close_result = _close(fd);
927
928 if (amount_written != length || close_result == -1) {
929 notify_nonfatal_error(pvar,
930 "An error occurred while trying to write the host key.\n"
931 "The host key could not be written.");
932 }
933 }
934 }
935
936 //
937 // Unknown host���z�X�g���J���� known_hosts �t�@�C����������������������
938 // ���[�U���m�F�������B
939 // TODO: finger print���\�����s���B
940 // (2006.3.25 yutaka)
941 //
942 static BOOL CALLBACK hosts_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
943 LPARAM lParam)
944 {
945 PTInstVar pvar;
946
947 switch (msg) {
948 case WM_INITDIALOG:
949 pvar = (PTInstVar) lParam;
950 pvar->hosts_state.hosts_dialog = dlg;
951 SetWindowLong(dlg, DWL_USER, lParam);
952
953 init_hosts_dlg(pvar, dlg);
954
955 // add host check box���`�F�b�N���f�t�H���g������������
956 SendMessage(GetDlgItem(dlg, IDC_ADDTOKNOWNHOSTS), BM_SETCHECK, BST_CHECKED, 0);
957
958 return TRUE; /* because we do not set the focus */
959
960 case WM_COMMAND:
961 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
962
963 switch (LOWORD(wParam)) {
964 case IDC_CONTINUE:
965 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
966 add_host_key(pvar);
967 }
968
969 if (SSHv1(pvar)) {
970 SSH_notify_host_OK(pvar);
971 } else { // SSH2
972 // SSH2���������� SSH_notify_host_OK() �������B
973 }
974
975 pvar->hosts_state.hosts_dialog = NULL;
976
977 EndDialog(dlg, 1);
978 return TRUE;
979
980 case IDCANCEL: /* kill the connection */
981 pvar->hosts_state.hosts_dialog = NULL;
982 notify_closed_connection(pvar);
983 EndDialog(dlg, 0);
984 return TRUE;
985
986 default:
987 return FALSE;
988 }
989
990 default:
991 return FALSE;
992 }
993 }
994
995 static char FAR *copy_mp_int(char FAR * num)
996 {
997 int len = (get_ushort16_MSBfirst(num) + 7) / 8 + 2;
998 char FAR *result = (char FAR *) malloc(len);
999
1000 if (result != NULL) {
1001 memcpy(result, num, len);
1002 }
1003
1004 return result;
1005 }
1006
1007 void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar)
1008 {
1009 if (pvar->hosts_state.hosts_dialog == NULL) {
1010 HWND cur_active = GetActiveWindow();
1011
1012 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST),
1013 cur_active != NULL ? cur_active : wnd,
1014 hosts_dlg_proc, (LPARAM) pvar);
1015 }
1016 }
1017
1018 void HOSTS_do_different_host_dialog(HWND wnd, PTInstVar pvar)
1019 {
1020 if (pvar->hosts_state.hosts_dialog == NULL) {
1021 HWND cur_active = GetActiveWindow();
1022
1023 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTHOST),
1024 cur_active != NULL ? cur_active : wnd,
1025 hosts_dlg_proc, (LPARAM) pvar);
1026 }
1027 }
1028
1029 //
1030 // �T�[�o�����������������z�X�g���J�������������`�F�b�N����
1031 //
1032 // SSH2���������� (2006.3.24 yutaka)
1033 //
1034 BOOL HOSTS_check_host_key(PTInstVar pvar, char FAR * hostname, Key *key)
1035 {
1036 int found_different_key = 0;
1037
1038 // ������ known_hosts �t�@�C�������z�X�g���J�����������������������A���������r�����B
1039 if (pvar->hosts_state.prefetched_hostname != NULL
1040 && _stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0
1041 && match_key(pvar, key)) {
1042
1043 if (SSHv1(pvar)) {
1044 SSH_notify_host_OK(pvar);
1045 } else {
1046 // SSH2���������� SSH_notify_host_OK() �������B
1047 }
1048 return TRUE;
1049 }
1050
1051 // �������������������������A�������_���t�@�C��������������
1052 if (begin_read_host_files(pvar, 0)) {
1053 do {
1054 if (!read_host_key(pvar, hostname, 0)) {
1055 break;
1056 }
1057
1058 if (pvar->hosts_state.hostkey.type != KEY_UNSPEC) {
1059 if (match_key(pvar, key)) {
1060 finish_read_host_files(pvar, 0);
1061 SSH_notify_host_OK(pvar);
1062 return TRUE;
1063 } else {
1064 // �L�[�� known_hosts ���������������A�L�[�����e���������B
1065 found_different_key = 1;
1066 }
1067 }
1068 } while (pvar->hosts_state.hostkey.type != KEY_UNSPEC); // �L�[�����������������������[�v����
1069
1070 finish_read_host_files(pvar, 0);
1071 }
1072
1073
1074 // known_hosts �������������L�[���������t�@�C�������������������A�������������������B
1075 pvar->hosts_state.hostkey.type = key->type;
1076 if (key->type == KEY_RSA1) { // SSH1
1077 pvar->hosts_state.hostkey.bits = key->bits;
1078 pvar->hosts_state.hostkey.exp = copy_mp_int(key->exp);
1079 pvar->hosts_state.hostkey.mod = copy_mp_int(key->mod);
1080
1081 } else if (key->type == KEY_RSA) { // SSH2 RSA
1082 pvar->hosts_state.hostkey.rsa = duplicate_RSA(key->rsa);
1083
1084 } else { // SSH2 DSA
1085 pvar->hosts_state.hostkey.dsa = duplicate_DSA(key->dsa);
1086
1087 }
1088 free(pvar->hosts_state.prefetched_hostname);
1089 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
1090
1091 if (found_different_key) {
1092 PostMessage(pvar->NotificationWindow, WM_COMMAND,
1093 ID_SSHDIFFERENTHOST, 0);
1094 } else {
1095 PostMessage(pvar->NotificationWindow, WM_COMMAND,
1096 ID_SSHUNKNOWNHOST, 0);
1097 }
1098
1099 return TRUE;
1100 }
1101
1102 void HOSTS_notify_disconnecting(PTInstVar pvar)
1103 {
1104 if (pvar->hosts_state.hosts_dialog != NULL) {
1105 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL,
1106 0);
1107 /* the main window might not go away if it's not enabled. (see vtwin.cpp) */
1108 EnableWindow(pvar->NotificationWindow, TRUE);
1109 }
1110 }
1111
1112 void HOSTS_end(PTInstVar pvar)
1113 {
1114 int i;
1115
1116 free(pvar->hosts_state.prefetched_hostname);
1117 #if 0
1118 free(pvar->hosts_state.key_exp);
1119 free(pvar->hosts_state.key_mod);
1120 #else
1121 init_hostkey(&pvar->hosts_state.hostkey);
1122 #endif
1123
1124 if (pvar->hosts_state.file_names != NULL) {
1125 for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {
1126 free(pvar->hosts_state.file_names[i]);
1127 }
1128 free(pvar->hosts_state.file_names);
1129 }
1130 }
1131
1132 /*
1133 * $Log: not supported by cvs2svn $
1134 * Revision 1.3 2006/02/18 07:37:02 yutakakn
1135 * �E�R���p�C���� Visual Studio 2005 Standard Edition �������������B
1136 * �Estricmp()��_stricmp()���u������
1137 * �Estrdup()��_strdup()���u������
1138 *
1139 * Revision 1.2 2004/12/19 15:39:42 yutakakn
1140 * CVS LogID������
1141 *
1142 */

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