Develop and Download Open Source Software

Browse Subversion Repository

Annotation of /trunk/ttssh2/ttxssh/hosts.c

Parent Directory Parent Directory | Revision Log Revision Log


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

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

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