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 2761 - (show annotations) (download) (as text)
Sun Dec 19 15:39:58 2004 UTC (19 years, 3 months ago) by yutakakn
Original Path: ttssh2/trunk/ttxssh/hosts.c
File MIME type: text/x-csrc
File size: 17464 byte(s)
CVS LogIDの追加

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
39 #include <openssl/bn.h>
40
41 #include <fcntl.h>
42 #include <io.h>
43 #include <errno.h>
44 #include <sys/stat.h>
45
46 static char FAR *FAR * parse_multi_path(char FAR * buf)
47 {
48 int i;
49 int ch;
50 int num_paths = 1;
51 char FAR *FAR * result;
52 int last_path_index;
53
54 for (i = 0; (ch = buf[i]) != 0; i++) {
55 if (ch == ';') {
56 num_paths++;
57 }
58 }
59
60 result =
61 (char FAR * FAR *) malloc(sizeof(char FAR *) * (num_paths + 1));
62
63 last_path_index = 0;
64 num_paths = 0;
65 for (i = 0; (ch = buf[i]) != 0; i++) {
66 if (ch == ';') {
67 buf[i] = 0;
68 result[num_paths] = _strdup(buf + last_path_index);
69 num_paths++;
70 buf[i] = ch;
71 last_path_index = i + 1;
72 }
73 }
74 if (i > last_path_index) {
75 result[num_paths] = _strdup(buf + last_path_index);
76 num_paths++;
77 }
78 result[num_paths] = NULL;
79 return result;
80 }
81
82 void HOSTS_init(PTInstVar pvar)
83 {
84 pvar->hosts_state.prefetched_hostname = NULL;
85 pvar->hosts_state.key_exp = NULL;
86 pvar->hosts_state.key_mod = NULL;
87 pvar->hosts_state.hosts_dialog = NULL;
88 pvar->hosts_state.file_names = NULL;
89 }
90
91 void HOSTS_open(PTInstVar pvar)
92 {
93 pvar->hosts_state.file_names =
94 parse_multi_path(pvar->session_settings.KnownHostsFiles);
95 }
96
97 static int begin_read_file(PTInstVar pvar, char FAR * name,
98 int suppress_errors)
99 {
100 int fd;
101 int length;
102 int amount_read;
103 char buf[2048];
104
105 get_teraterm_dir_relative_name(buf, sizeof(buf), name);
106 fd = _open(buf, _O_RDONLY | _O_SEQUENTIAL | _O_BINARY);
107 if (fd == -1) {
108 if (!suppress_errors) {
109 if (errno == ENOENT) {
110 notify_nonfatal_error(pvar,
111 "An error occurred while trying to read a known_hosts file.\n"
112 "The specified filename does not exist.");
113 } else {
114 notify_nonfatal_error(pvar,
115 "An error occurred while trying to read a known_hosts file.");
116 }
117 }
118 return 0;
119 }
120
121 length = (int) _lseek(fd, 0, SEEK_END);
122 _lseek(fd, 0, SEEK_SET);
123
124 if (length >= 0 && length < 0x7FFFFFFF) {
125 pvar->hosts_state.file_data = malloc(length + 1);
126 if (pvar->hosts_state.file_data == NULL) {
127 if (!suppress_errors) {
128 notify_nonfatal_error(pvar,
129 "Memory ran out while trying to allocate space to read a known_hosts file.");
130 }
131 _close(fd);
132 return 0;
133 }
134 } else {
135 if (!suppress_errors) {
136 notify_nonfatal_error(pvar,
137 "An error occurred while trying to read a known_hosts file.");
138 }
139 _close(fd);
140 return 0;
141 }
142
143 amount_read = _read(fd, pvar->hosts_state.file_data, length);
144 pvar->hosts_state.file_data[length] = 0;
145
146 _close(fd);
147
148 if (amount_read != length) {
149 if (!suppress_errors) {
150 notify_nonfatal_error(pvar,
151 "An error occurred while trying to read a known_hosts file.");
152 }
153 free(pvar->hosts_state.file_data);
154 pvar->hosts_state.file_data = NULL;
155 return 0;
156 } else {
157 return 1;
158 }
159 }
160
161 static int end_read_file(PTInstVar pvar, int suppress_errors)
162 {
163 free(pvar->hosts_state.file_data);
164 pvar->hosts_state.file_data = NULL;
165 return 1;
166 }
167
168 static int begin_read_host_files(PTInstVar pvar, int suppress_errors)
169 {
170 pvar->hosts_state.file_num = 0;
171 pvar->hosts_state.file_data = NULL;
172 return 1;
173 }
174
175 static int eat_spaces(char FAR * data)
176 {
177 int index = 0;
178 int ch;
179
180 while ((ch = data[index]) == ' ' || ch == '\t') {
181 index++;
182 }
183 return index;
184 }
185
186 static int eat_digits(char FAR * data)
187 {
188 int index = 0;
189 int ch;
190
191 while ((ch = data[index]) >= '0' && ch <= '9') {
192 index++;
193 }
194 return index;
195 }
196
197 static int eat_to_end_of_line(char FAR * data)
198 {
199 int index = 0;
200 int ch;
201
202 while ((ch = data[index]) != '\n' && ch != '\r' && ch != 0) {
203 index++;
204 }
205
206 while ((ch = data[index]) == '\n' || ch == '\r') {
207 index++;
208 }
209
210 return index;
211 }
212
213 static int eat_to_end_of_pattern(char FAR * data)
214 {
215 int index = 0;
216 int ch;
217
218 while (ch = data[index], is_pattern_char(ch)) {
219 index++;
220 }
221
222 return index;
223 }
224
225 static char FAR *parse_bignum(char FAR * data)
226 {
227 uint32 digits = 0;
228 BIGNUM *num = BN_new();
229 BIGNUM *billion = BN_new();
230 BIGNUM *digits_num = BN_new();
231 BN_CTX *ctx = BN_CTX_new();
232 char FAR *result;
233 int ch;
234 int leftover_digits = 1;
235
236 BN_CTX_init(ctx);
237 BN_set_word(num, 0);
238 BN_set_word(billion, 1000000000L);
239
240 while ((ch = *data) >= '0' && ch <= '9') {
241 if (leftover_digits == 1000000000L) {
242 BN_set_word(digits_num, digits);
243 BN_mul(num, num, billion, ctx);
244 BN_add(num, num, digits_num);
245 leftover_digits = 1;
246 digits = 0;
247 }
248
249 digits = digits * 10 + ch - '0';
250 leftover_digits *= 10;
251 data++;
252 }
253
254 BN_set_word(digits_num, digits);
255 BN_set_word(billion, leftover_digits);
256 BN_mul(num, num, billion, ctx);
257 BN_add(num, num, digits_num);
258
259 result = (char FAR *) malloc(2 + BN_num_bytes(num));
260 set_ushort16_MSBfirst(result, BN_num_bits(num));
261 BN_bn2bin(num, result + 2);
262
263 BN_CTX_free(ctx);
264 BN_free(digits_num);
265 BN_free(num);
266 BN_free(billion);
267
268 return result;
269 }
270
271 static int check_host_key(PTInstVar pvar, char FAR * hostname,
272 char FAR * data)
273 {
274 int index = eat_spaces(data);
275 int matched = 0;
276 int keybits = 0;
277
278 if (data[index] == '#') {
279 return index + eat_to_end_of_line(data + index);
280 }
281
282 /* if we find an empty line, then it won't have any patterns matching the hostname
283 and so we skip it */
284 index--;
285 do {
286 int negated;
287
288 index++;
289 negated = data[index] == '!';
290
291 if (negated) {
292 index++;
293 if (match_pattern(data + index, hostname)) {
294 return index + eat_to_end_of_line(data + index);
295 }
296 } else if (match_pattern(data + index, hostname)) {
297 matched = 1;
298 }
299
300 index += eat_to_end_of_pattern(data + index);
301 } while (data[index] == ',');
302
303 if (!matched) {
304 return index + eat_to_end_of_line(data + index);
305 } else {
306 index += eat_spaces(data + index);
307
308 pvar->hosts_state.key_bits = atoi(data + index);
309 index += eat_digits(data + index);
310 index += eat_spaces(data + index);
311
312 pvar->hosts_state.key_exp = parse_bignum(data + index);
313 index += eat_digits(data + index);
314 index += eat_spaces(data + index);
315
316 pvar->hosts_state.key_mod = parse_bignum(data + index);
317
318 if (pvar->hosts_state.key_bits < 0
319 || pvar->hosts_state.key_exp == NULL
320 || pvar->hosts_state.key_mod == NULL) {
321 pvar->hosts_state.key_bits = 0;
322 free(pvar->hosts_state.key_exp);
323 free(pvar->hosts_state.key_mod);
324 }
325
326 return index + eat_to_end_of_line(data + index);
327 }
328 }
329
330 static int read_host_key(PTInstVar pvar, char FAR * hostname,
331 int suppress_errors)
332 {
333 int i;
334
335 for (i = 0; hostname[i] != 0; i++) {
336 int ch = hostname[i];
337
338 if (!is_pattern_char(ch) || ch == '*' || ch == '?') {
339 if (!suppress_errors) {
340 notify_fatal_error(pvar,
341 "The host name contains an invalid character.\n"
342 "This session will be terminated.");
343 }
344 return 0;
345 }
346 }
347
348 if (i == 0) {
349 if (!suppress_errors) {
350 notify_fatal_error(pvar, "The host name should not be empty.\n"
351 "This session will be terminated.");
352 }
353 return 0;
354 }
355
356 pvar->hosts_state.key_bits = 0;
357 free(pvar->hosts_state.key_exp);
358 pvar->hosts_state.key_exp = NULL;
359 free(pvar->hosts_state.key_mod);
360 pvar->hosts_state.key_mod = NULL;
361
362 do {
363 if (pvar->hosts_state.file_data == NULL
364 || pvar->hosts_state.file_data[pvar->hosts_state.
365 file_data_index] == 0) {
366 char FAR *filename;
367 int keep_going = 1;
368
369 if (pvar->hosts_state.file_data != NULL) {
370 end_read_file(pvar, suppress_errors);
371 }
372
373 do {
374 filename =
375 pvar->hosts_state.file_names[pvar->hosts_state.
376 file_num];
377
378 if (filename == NULL) {
379 return 1;
380 } else {
381 pvar->hosts_state.file_num++;
382
383 if (filename[0] != 0) {
384 if (begin_read_file
385 (pvar, filename, suppress_errors)) {
386 pvar->hosts_state.file_data_index = 0;
387 keep_going = 0;
388 }
389 }
390 }
391 } while (keep_going);
392 }
393
394 pvar->hosts_state.file_data_index +=
395 check_host_key(pvar, hostname,
396 pvar->hosts_state.file_data +
397 pvar->hosts_state.file_data_index);
398 } while (pvar->hosts_state.key_bits == 0);
399
400 return 1;
401 }
402
403 static void finish_read_host_files(PTInstVar pvar, int suppress_errors)
404 {
405 if (pvar->hosts_state.file_data != NULL) {
406 end_read_file(pvar, suppress_errors);
407 }
408 }
409
410 void HOSTS_prefetch_host_key(PTInstVar pvar, char FAR * hostname)
411 {
412 if (!begin_read_host_files(pvar, 1)) {
413 return;
414 }
415
416 if (!read_host_key(pvar, hostname, 1)) {
417 return;
418 }
419
420 free(pvar->hosts_state.prefetched_hostname);
421 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
422
423 finish_read_host_files(pvar, 1);
424 }
425
426 static BOOL equal_mp_ints(unsigned char FAR * num1,
427 unsigned char FAR * num2)
428 {
429 if (num1 == NULL || num2 == NULL) {
430 return FALSE;
431 } else {
432 uint32 bytes = (get_ushort16_MSBfirst(num1) + 7) / 8;
433
434 if (bytes != (get_ushort16_MSBfirst(num2) + 7) / 8) {
435 return FALSE; /* different byte lengths */
436 } else {
437 return memcmp(num1 + 2, num2 + 2, bytes) == 0;
438 }
439 }
440 }
441
442 static BOOL match_key(PTInstVar pvar,
443 int bits, unsigned char FAR * exp,
444 unsigned char FAR * mod)
445 {
446 /* just check for equal exponent and modulus */
447 return equal_mp_ints(exp, pvar->hosts_state.key_exp)
448 && equal_mp_ints(mod, pvar->hosts_state.key_mod);
449 }
450
451 static void init_hosts_dlg(PTInstVar pvar, HWND dlg)
452 {
453 char buf[1024];
454 char buf2[2048];
455 int i, j;
456 int ch;
457
458 GetDlgItemText(dlg, IDC_HOSTWARNING, buf, sizeof(buf));
459 for (i = 0; (ch = buf[i]) != 0 && ch != '#'; i++) {
460 buf2[i] = ch;
461 }
462 if (sizeof(buf2) - i - 1 > 0) {
463 strncpy(buf2 + i, pvar->hosts_state.prefetched_hostname,
464 sizeof(buf2) - i - 1);
465 }
466 j = i + strlen(buf2 + i);
467 for (; buf[i] == '#'; i++) {
468 }
469 if (sizeof(buf2) - j - 1 > 0) {
470 strncpy(buf2 + j, buf + i, sizeof(buf2) - j - 1);
471 }
472 buf2[sizeof(buf2) - 1] = 0;
473
474 SetDlgItemText(dlg, IDC_HOSTWARNING, buf2);
475 }
476
477 static int print_mp_int(char FAR * buf, unsigned char FAR * mp)
478 {
479 int i = 0, j, k;
480 BIGNUM *num = BN_new();
481 int ch;
482
483 BN_bin2bn(mp + 2, (get_ushort16_MSBfirst(mp) + 7) / 8, num);
484
485 do {
486 buf[i] = (char) ((BN_div_word(num, 10)) + '0');
487 i++;
488 } while (!BN_is_zero(num));
489
490 /* we need to reverse the digits */
491 for (j = 0, k = i - 1; j < k; j++, k--) {
492 ch = buf[j];
493 buf[j] = buf[k];
494 buf[k] = ch;
495 }
496
497 buf[i] = 0;
498 return i;
499 }
500
501 static char FAR *format_host_key(PTInstVar pvar)
502 {
503 int host_len = strlen(pvar->hosts_state.prefetched_hostname);
504 char FAR *result = (char FAR *) malloc(host_len
505 + 50 +
506 get_ushort16_MSBfirst(pvar->
507 hosts_state.
508 key_exp) /
509 3 +
510 get_ushort16_MSBfirst(pvar->
511 hosts_state.
512 key_mod) /
513 3);
514 int index;
515
516 strcpy(result, pvar->hosts_state.prefetched_hostname);
517 index = host_len;
518
519 sprintf(result + index, " %d ", pvar->hosts_state.key_bits);
520 index += strlen(result + index);
521 index += print_mp_int(result + index, pvar->hosts_state.key_exp);
522 result[index] = ' ';
523 index++;
524 index += print_mp_int(result + index, pvar->hosts_state.key_mod);
525 strcpy(result + index, " \r\n");
526
527 return result;
528 }
529
530 static void add_host_key(PTInstVar pvar)
531 {
532 char FAR *name = pvar->hosts_state.file_names[0];
533
534 if (name == NULL || name[0] == 0) {
535 notify_nonfatal_error(pvar,
536 "The host and its key cannot be added, because no known-hosts file has been specified.\n"
537 "Restart Teraterm and specify a read/write known-hosts file in the TTSSH Setup dialog box.");
538 } else {
539 char FAR *keydata = format_host_key(pvar);
540 int length = strlen(keydata);
541 int fd =
542 _open(name,
543 _O_APPEND | _O_CREAT | _O_WRONLY | _O_SEQUENTIAL |
544 _O_BINARY,
545 _S_IREAD | _S_IWRITE);
546 int amount_written;
547 int close_result;
548
549 if (fd == -1) {
550 if (errno == EACCES) {
551 notify_nonfatal_error(pvar,
552 "An error occurred while trying to write the host key.\n"
553 "You do not have permission to write to the known-hosts file.");
554 } else {
555 notify_nonfatal_error(pvar,
556 "An error occurred while trying to write the host key.\n"
557 "The host key could not be written.");
558 }
559 return;
560 }
561
562 amount_written = _write(fd, keydata, length);
563 free(keydata);
564 close_result = _close(fd);
565
566 if (amount_written != length || close_result == -1) {
567 notify_nonfatal_error(pvar,
568 "An error occurred while trying to write the host key.\n"
569 "The host key could not be written.");
570 }
571 }
572 }
573
574 static BOOL CALLBACK hosts_dlg_proc(HWND dlg, UINT msg, WPARAM wParam,
575 LPARAM lParam)
576 {
577 PTInstVar pvar;
578
579 switch (msg) {
580 case WM_INITDIALOG:
581 pvar = (PTInstVar) lParam;
582 pvar->hosts_state.hosts_dialog = dlg;
583 SetWindowLong(dlg, DWL_USER, lParam);
584
585 init_hosts_dlg(pvar, dlg);
586 return TRUE; /* because we do not set the focus */
587
588 case WM_COMMAND:
589 pvar = (PTInstVar) GetWindowLong(dlg, DWL_USER);
590
591 switch (LOWORD(wParam)) {
592 case IDC_CONTINUE:
593 if (IsDlgButtonChecked(dlg, IDC_ADDTOKNOWNHOSTS)) {
594 add_host_key(pvar);
595 }
596 SSH_notify_host_OK(pvar);
597
598 pvar->hosts_state.hosts_dialog = NULL;
599
600 EndDialog(dlg, 1);
601 return TRUE;
602
603 case IDCANCEL: /* kill the connection */
604 pvar->hosts_state.hosts_dialog = NULL;
605 notify_closed_connection(pvar);
606 EndDialog(dlg, 0);
607 return TRUE;
608
609 default:
610 return FALSE;
611 }
612
613 default:
614 return FALSE;
615 }
616 }
617
618 static char FAR *copy_mp_int(char FAR * num)
619 {
620 int len = (get_ushort16_MSBfirst(num) + 7) / 8 + 2;
621 char FAR *result = (char FAR *) malloc(len);
622
623 if (result != NULL) {
624 memcpy(result, num, len);
625 }
626
627 return result;
628 }
629
630 void HOSTS_do_unknown_host_dialog(HWND wnd, PTInstVar pvar)
631 {
632 if (pvar->hosts_state.hosts_dialog == NULL) {
633 HWND cur_active = GetActiveWindow();
634
635 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHUNKNOWNHOST),
636 cur_active != NULL ? cur_active : wnd,
637 hosts_dlg_proc, (LPARAM) pvar);
638 }
639 }
640
641 void HOSTS_do_different_host_dialog(HWND wnd, PTInstVar pvar)
642 {
643 if (pvar->hosts_state.hosts_dialog == NULL) {
644 HWND cur_active = GetActiveWindow();
645
646 DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_SSHDIFFERENTHOST),
647 cur_active != NULL ? cur_active : wnd,
648 hosts_dlg_proc, (LPARAM) pvar);
649 }
650 }
651
652 BOOL HOSTS_check_host_key(PTInstVar pvar, char FAR * hostname,
653 int bits, unsigned char FAR * exp,
654 unsigned char FAR * mod)
655 {
656 int found_different_key = 0;
657
658 if (pvar->hosts_state.prefetched_hostname != NULL
659 && stricmp(pvar->hosts_state.prefetched_hostname, hostname) == 0
660 && match_key(pvar, bits, exp, mod)) {
661 SSH_notify_host_OK(pvar);
662 return TRUE;
663 }
664
665 if (begin_read_host_files(pvar, 0)) {
666 do {
667 if (!read_host_key(pvar, hostname, 0)) {
668 break;
669 }
670
671 if (pvar->hosts_state.key_bits > 0) {
672 if (match_key(pvar, bits, exp, mod)) {
673 finish_read_host_files(pvar, 0);
674 SSH_notify_host_OK(pvar);
675 return TRUE;
676 } else {
677 found_different_key = 1;
678 }
679 }
680 } while (pvar->hosts_state.key_bits > 0);
681
682 finish_read_host_files(pvar, 0);
683 }
684
685 pvar->hosts_state.key_bits = bits;
686 pvar->hosts_state.key_exp = copy_mp_int(exp);
687 pvar->hosts_state.key_mod = copy_mp_int(mod);
688 free(pvar->hosts_state.prefetched_hostname);
689 pvar->hosts_state.prefetched_hostname = _strdup(hostname);
690
691 if (found_different_key) {
692 PostMessage(pvar->NotificationWindow, WM_COMMAND,
693 ID_SSHDIFFERENTHOST, 0);
694 } else {
695 PostMessage(pvar->NotificationWindow, WM_COMMAND,
696 ID_SSHUNKNOWNHOST, 0);
697 }
698
699 return TRUE;
700 }
701
702 void HOSTS_notify_disconnecting(PTInstVar pvar)
703 {
704 if (pvar->hosts_state.hosts_dialog != NULL) {
705 PostMessage(pvar->hosts_state.hosts_dialog, WM_COMMAND, IDCANCEL,
706 0);
707 /* the main window might not go away if it's not enabled. (see vtwin.cpp) */
708 EnableWindow(pvar->NotificationWindow, TRUE);
709 }
710 }
711
712 void HOSTS_end(PTInstVar pvar)
713 {
714 int i;
715
716 free(pvar->hosts_state.prefetched_hostname);
717 free(pvar->hosts_state.key_exp);
718 free(pvar->hosts_state.key_mod);
719
720 if (pvar->hosts_state.file_names != NULL) {
721 for (i = 0; pvar->hosts_state.file_names[i] != NULL; i++) {
722 free(pvar->hosts_state.file_names[i]);
723 }
724 free(pvar->hosts_state.file_names);
725 }
726 }
727
728 /*
729 * $Log: not supported by cvs2svn $
730 */

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