diff options
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 175 |
1 files changed, 106 insertions, 69 deletions
diff --git a/clientloop.c b/clientloop.c index 1bcf4392f..90bdcbc39 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -59,7 +59,7 @@ | |||
59 | */ | 59 | */ |
60 | 60 | ||
61 | #include "includes.h" | 61 | #include "includes.h" |
62 | RCSID("$OpenBSD: clientloop.c,v 1.130 2004/08/11 21:43:04 avsm Exp $"); | 62 | RCSID("$OpenBSD: clientloop.c,v 1.135 2005/03/01 10:09:52 djm Exp $"); |
63 | 63 | ||
64 | #include "ssh.h" | 64 | #include "ssh.h" |
65 | #include "ssh1.h" | 65 | #include "ssh1.h" |
@@ -437,8 +437,6 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
437 | static void | 437 | static void |
438 | client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | 438 | client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) |
439 | { | 439 | { |
440 | struct winsize oldws, newws; | ||
441 | |||
442 | /* Flush stdout and stderr buffers. */ | 440 | /* Flush stdout and stderr buffers. */ |
443 | if (buffer_len(bout) > 0) | 441 | if (buffer_len(bout) > 0) |
444 | atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout)); | 442 | atomicio(vwrite, fileno(stdout), buffer_ptr(bout), buffer_len(bout)); |
@@ -455,19 +453,11 @@ client_suspend_self(Buffer *bin, Buffer *bout, Buffer *berr) | |||
455 | buffer_free(bout); | 453 | buffer_free(bout); |
456 | buffer_free(berr); | 454 | buffer_free(berr); |
457 | 455 | ||
458 | /* Save old window size. */ | ||
459 | ioctl(fileno(stdin), TIOCGWINSZ, &oldws); | ||
460 | |||
461 | /* Send the suspend signal to the program itself. */ | 456 | /* Send the suspend signal to the program itself. */ |
462 | kill(getpid(), SIGTSTP); | 457 | kill(getpid(), SIGTSTP); |
463 | 458 | ||
464 | /* Check if the window size has changed. */ | 459 | /* Reset window sizes in case they have changed */ |
465 | if (ioctl(fileno(stdin), TIOCGWINSZ, &newws) >= 0 && | 460 | received_window_change_signal = 1; |
466 | (oldws.ws_row != newws.ws_row || | ||
467 | oldws.ws_col != newws.ws_col || | ||
468 | oldws.ws_xpixel != newws.ws_xpixel || | ||
469 | oldws.ws_ypixel != newws.ws_ypixel)) | ||
470 | received_window_change_signal = 1; | ||
471 | 461 | ||
472 | /* OK, we have been continued by the user. Reinitialize buffers. */ | 462 | /* OK, we have been continued by the user. Reinitialize buffers. */ |
473 | buffer_init(bin); | 463 | buffer_init(bin); |
@@ -576,7 +566,7 @@ client_process_control(fd_set * readset) | |||
576 | struct sockaddr_storage addr; | 566 | struct sockaddr_storage addr; |
577 | struct confirm_ctx *cctx; | 567 | struct confirm_ctx *cctx; |
578 | char *cmd; | 568 | char *cmd; |
579 | u_int len, env_len; | 569 | u_int len, env_len, command, flags; |
580 | uid_t euid; | 570 | uid_t euid; |
581 | gid_t egid; | 571 | gid_t egid; |
582 | 572 | ||
@@ -606,39 +596,74 @@ client_process_control(fd_set * readset) | |||
606 | return; | 596 | return; |
607 | } | 597 | } |
608 | 598 | ||
609 | allowed = 1; | ||
610 | if (options.control_master == 2) { | ||
611 | char *p, prompt[1024]; | ||
612 | |||
613 | allowed = 0; | ||
614 | snprintf(prompt, sizeof(prompt), | ||
615 | "Allow shared connection to %s? ", host); | ||
616 | p = read_passphrase(prompt, RP_USE_ASKPASS|RP_ALLOW_EOF); | ||
617 | if (p != NULL) { | ||
618 | /* | ||
619 | * Accept empty responses and responses consisting | ||
620 | * of the word "yes" as affirmative. | ||
621 | */ | ||
622 | if (*p == '\0' || *p == '\n' || | ||
623 | strcasecmp(p, "yes") == 0) | ||
624 | allowed = 1; | ||
625 | xfree(p); | ||
626 | } | ||
627 | } | ||
628 | |||
629 | unset_nonblock(client_fd); | 599 | unset_nonblock(client_fd); |
630 | 600 | ||
601 | /* Read command */ | ||
631 | buffer_init(&m); | 602 | buffer_init(&m); |
603 | if (ssh_msg_recv(client_fd, &m) == -1) { | ||
604 | error("%s: client msg_recv failed", __func__); | ||
605 | close(client_fd); | ||
606 | buffer_free(&m); | ||
607 | return; | ||
608 | } | ||
609 | if ((ver = buffer_get_char(&m)) != 1) { | ||
610 | error("%s: wrong client version %d", __func__, ver); | ||
611 | buffer_free(&m); | ||
612 | close(client_fd); | ||
613 | return; | ||
614 | } | ||
615 | |||
616 | allowed = 1; | ||
617 | command = buffer_get_int(&m); | ||
618 | flags = buffer_get_int(&m); | ||
619 | |||
620 | buffer_clear(&m); | ||
632 | 621 | ||
622 | switch (command) { | ||
623 | case SSHMUX_COMMAND_OPEN: | ||
624 | if (options.control_master == 2) | ||
625 | allowed = ask_permission("Allow shared connection " | ||
626 | "to %s? ", host); | ||
627 | /* continue below */ | ||
628 | break; | ||
629 | case SSHMUX_COMMAND_TERMINATE: | ||
630 | if (options.control_master == 2) | ||
631 | allowed = ask_permission("Terminate shared connection " | ||
632 | "to %s? ", host); | ||
633 | if (allowed) | ||
634 | quit_pending = 1; | ||
635 | /* FALLTHROUGH */ | ||
636 | case SSHMUX_COMMAND_ALIVE_CHECK: | ||
637 | /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ | ||
638 | buffer_clear(&m); | ||
639 | buffer_put_int(&m, allowed); | ||
640 | buffer_put_int(&m, getpid()); | ||
641 | if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { | ||
642 | error("%s: client msg_send failed", __func__); | ||
643 | close(client_fd); | ||
644 | buffer_free(&m); | ||
645 | return; | ||
646 | } | ||
647 | buffer_free(&m); | ||
648 | close(client_fd); | ||
649 | return; | ||
650 | default: | ||
651 | error("Unsupported command %d", command); | ||
652 | buffer_free(&m); | ||
653 | close(client_fd); | ||
654 | return; | ||
655 | } | ||
656 | |||
657 | /* Reply for SSHMUX_COMMAND_OPEN */ | ||
658 | buffer_clear(&m); | ||
633 | buffer_put_int(&m, allowed); | 659 | buffer_put_int(&m, allowed); |
634 | buffer_put_int(&m, getpid()); | 660 | buffer_put_int(&m, getpid()); |
635 | if (ssh_msg_send(client_fd, /* version */0, &m) == -1) { | 661 | if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { |
636 | error("%s: client msg_send failed", __func__); | 662 | error("%s: client msg_send failed", __func__); |
637 | close(client_fd); | 663 | close(client_fd); |
638 | buffer_free(&m); | 664 | buffer_free(&m); |
639 | return; | 665 | return; |
640 | } | 666 | } |
641 | buffer_clear(&m); | ||
642 | 667 | ||
643 | if (!allowed) { | 668 | if (!allowed) { |
644 | error("Refused control connection"); | 669 | error("Refused control connection"); |
@@ -647,14 +672,14 @@ client_process_control(fd_set * readset) | |||
647 | return; | 672 | return; |
648 | } | 673 | } |
649 | 674 | ||
675 | buffer_clear(&m); | ||
650 | if (ssh_msg_recv(client_fd, &m) == -1) { | 676 | if (ssh_msg_recv(client_fd, &m) == -1) { |
651 | error("%s: client msg_recv failed", __func__); | 677 | error("%s: client msg_recv failed", __func__); |
652 | close(client_fd); | 678 | close(client_fd); |
653 | buffer_free(&m); | 679 | buffer_free(&m); |
654 | return; | 680 | return; |
655 | } | 681 | } |
656 | 682 | if ((ver = buffer_get_char(&m)) != 1) { | |
657 | if ((ver = buffer_get_char(&m)) != 0) { | ||
658 | error("%s: wrong client version %d", __func__, ver); | 683 | error("%s: wrong client version %d", __func__, ver); |
659 | buffer_free(&m); | 684 | buffer_free(&m); |
660 | close(client_fd); | 685 | close(client_fd); |
@@ -663,9 +688,8 @@ client_process_control(fd_set * readset) | |||
663 | 688 | ||
664 | cctx = xmalloc(sizeof(*cctx)); | 689 | cctx = xmalloc(sizeof(*cctx)); |
665 | memset(cctx, 0, sizeof(*cctx)); | 690 | memset(cctx, 0, sizeof(*cctx)); |
666 | 691 | cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; | |
667 | cctx->want_tty = buffer_get_int(&m); | 692 | cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; |
668 | cctx->want_subsys = buffer_get_int(&m); | ||
669 | cctx->term = buffer_get_string(&m, &len); | 693 | cctx->term = buffer_get_string(&m, &len); |
670 | 694 | ||
671 | cmd = buffer_get_string(&m, &len); | 695 | cmd = buffer_get_string(&m, &len); |
@@ -697,14 +721,21 @@ client_process_control(fd_set * readset) | |||
697 | if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) | 721 | if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) |
698 | error("%s: tcgetattr: %s", __func__, strerror(errno)); | 722 | error("%s: tcgetattr: %s", __func__, strerror(errno)); |
699 | 723 | ||
724 | /* This roundtrip is just for synchronisation of ttymodes */ | ||
700 | buffer_clear(&m); | 725 | buffer_clear(&m); |
701 | if (ssh_msg_send(client_fd, /* version */0, &m) == -1) { | 726 | if (ssh_msg_send(client_fd, /* version */1, &m) == -1) { |
702 | error("%s: client msg_send failed", __func__); | 727 | error("%s: client msg_send failed", __func__); |
703 | close(client_fd); | 728 | close(client_fd); |
704 | close(new_fd[0]); | 729 | close(new_fd[0]); |
705 | close(new_fd[1]); | 730 | close(new_fd[1]); |
706 | close(new_fd[2]); | 731 | close(new_fd[2]); |
707 | buffer_free(&m); | 732 | buffer_free(&m); |
733 | xfree(cctx->term); | ||
734 | if (env_len != 0) { | ||
735 | for (i = 0; i < env_len; i++) | ||
736 | xfree(cctx->env[i]); | ||
737 | xfree(cctx->env); | ||
738 | } | ||
708 | return; | 739 | return; |
709 | } | 740 | } |
710 | buffer_free(&m); | 741 | buffer_free(&m); |
@@ -737,11 +768,11 @@ static void | |||
737 | process_cmdline(void) | 768 | process_cmdline(void) |
738 | { | 769 | { |
739 | void (*handler)(int); | 770 | void (*handler)(int); |
740 | char *s, *cmd; | 771 | char *s, *cmd, *cancel_host; |
741 | u_short fwd_port, fwd_host_port; | ||
742 | char buf[1024], sfwd_port[6], sfwd_host_port[6]; | ||
743 | int delete = 0; | 772 | int delete = 0; |
744 | int local = 0; | 773 | int local = 0; |
774 | u_short cancel_port; | ||
775 | Forward fwd; | ||
745 | 776 | ||
746 | leave_raw_mode(); | 777 | leave_raw_mode(); |
747 | handler = signal(SIGINT, SIG_IGN); | 778 | handler = signal(SIGINT, SIG_IGN); |
@@ -787,37 +818,38 @@ process_cmdline(void) | |||
787 | s++; | 818 | s++; |
788 | 819 | ||
789 | if (delete) { | 820 | if (delete) { |
790 | if (sscanf(s, "%5[0-9]", sfwd_host_port) != 1) { | 821 | cancel_port = 0; |
791 | logit("Bad forwarding specification."); | 822 | cancel_host = hpdelim(&s); /* may be NULL */ |
792 | goto out; | 823 | if (s != NULL) { |
824 | cancel_port = a2port(s); | ||
825 | cancel_host = cleanhostname(cancel_host); | ||
826 | } else { | ||
827 | cancel_port = a2port(cancel_host); | ||
828 | cancel_host = NULL; | ||
793 | } | 829 | } |
794 | if ((fwd_host_port = a2port(sfwd_host_port)) == 0) { | 830 | if (cancel_port == 0) { |
795 | logit("Bad forwarding port(s)."); | 831 | logit("Bad forwarding close port"); |
796 | goto out; | 832 | goto out; |
797 | } | 833 | } |
798 | channel_request_rforward_cancel(fwd_host_port); | 834 | channel_request_rforward_cancel(cancel_host, cancel_port); |
799 | } else { | 835 | } else { |
800 | if (sscanf(s, "%5[0-9]:%255[^:]:%5[0-9]", | 836 | if (!parse_forward(&fwd, s)) { |
801 | sfwd_port, buf, sfwd_host_port) != 3 && | ||
802 | sscanf(s, "%5[0-9]/%255[^/]/%5[0-9]", | ||
803 | sfwd_port, buf, sfwd_host_port) != 3) { | ||
804 | logit("Bad forwarding specification."); | 837 | logit("Bad forwarding specification."); |
805 | goto out; | 838 | goto out; |
806 | } | 839 | } |
807 | if ((fwd_port = a2port(sfwd_port)) == 0 || | ||
808 | (fwd_host_port = a2port(sfwd_host_port)) == 0) { | ||
809 | logit("Bad forwarding port(s)."); | ||
810 | goto out; | ||
811 | } | ||
812 | if (local) { | 840 | if (local) { |
813 | if (channel_setup_local_fwd_listener(fwd_port, buf, | 841 | if (channel_setup_local_fwd_listener(fwd.listen_host, |
814 | fwd_host_port, options.gateway_ports) < 0) { | 842 | fwd.listen_port, fwd.connect_host, |
843 | fwd.connect_port, options.gateway_ports) < 0) { | ||
815 | logit("Port forwarding failed."); | 844 | logit("Port forwarding failed."); |
816 | goto out; | 845 | goto out; |
817 | } | 846 | } |
818 | } else | 847 | } else { |
819 | channel_request_remote_forwarding(fwd_port, buf, | 848 | channel_request_remote_forwarding(fwd.listen_host, |
820 | fwd_host_port); | 849 | fwd.listen_port, fwd.connect_host, |
850 | fwd.connect_port); | ||
851 | } | ||
852 | |||
821 | logit("Forwarding port."); | 853 | logit("Forwarding port."); |
822 | } | 854 | } |
823 | 855 | ||
@@ -1201,14 +1233,15 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1201 | * Set signal handlers, (e.g. to restore non-blocking mode) | 1233 | * Set signal handlers, (e.g. to restore non-blocking mode) |
1202 | * but don't overwrite SIG_IGN, matches behaviour from rsh(1) | 1234 | * but don't overwrite SIG_IGN, matches behaviour from rsh(1) |
1203 | */ | 1235 | */ |
1236 | if (signal(SIGHUP, SIG_IGN) != SIG_IGN) | ||
1237 | signal(SIGHUP, signal_handler); | ||
1204 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) | 1238 | if (signal(SIGINT, SIG_IGN) != SIG_IGN) |
1205 | signal(SIGINT, signal_handler); | 1239 | signal(SIGINT, signal_handler); |
1206 | if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) | 1240 | if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) |
1207 | signal(SIGQUIT, signal_handler); | 1241 | signal(SIGQUIT, signal_handler); |
1208 | if (signal(SIGTERM, SIG_IGN) != SIG_IGN) | 1242 | if (signal(SIGTERM, SIG_IGN) != SIG_IGN) |
1209 | signal(SIGTERM, signal_handler); | 1243 | signal(SIGTERM, signal_handler); |
1210 | if (have_pty) | 1244 | signal(SIGWINCH, window_change_handler); |
1211 | signal(SIGWINCH, window_change_handler); | ||
1212 | 1245 | ||
1213 | if (have_pty) | 1246 | if (have_pty) |
1214 | enter_raw_mode(); | 1247 | enter_raw_mode(); |
@@ -1316,8 +1349,7 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1316 | /* Terminate the session. */ | 1349 | /* Terminate the session. */ |
1317 | 1350 | ||
1318 | /* Stop watching for window change. */ | 1351 | /* Stop watching for window change. */ |
1319 | if (have_pty) | 1352 | signal(SIGWINCH, SIG_DFL); |
1320 | signal(SIGWINCH, SIG_DFL); | ||
1321 | 1353 | ||
1322 | channel_free_all(); | 1354 | channel_free_all(); |
1323 | 1355 | ||
@@ -1684,9 +1716,13 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
1684 | dispatch_fn *subsys_repl) | 1716 | dispatch_fn *subsys_repl) |
1685 | { | 1717 | { |
1686 | int len; | 1718 | int len; |
1719 | Channel *c = NULL; | ||
1687 | 1720 | ||
1688 | debug2("%s: id %d", __func__, id); | 1721 | debug2("%s: id %d", __func__, id); |
1689 | 1722 | ||
1723 | if ((c = channel_lookup(id)) == NULL) | ||
1724 | fatal("client_session2_setup: channel %d: unknown channel", id); | ||
1725 | |||
1690 | if (want_tty) { | 1726 | if (want_tty) { |
1691 | struct winsize ws; | 1727 | struct winsize ws; |
1692 | struct termios tio; | 1728 | struct termios tio; |
@@ -1705,6 +1741,7 @@ client_session2_setup(int id, int want_tty, int want_subsystem, | |||
1705 | tty_make_modes(-1, tiop != NULL ? tiop : &tio); | 1741 | tty_make_modes(-1, tiop != NULL ? tiop : &tio); |
1706 | packet_send(); | 1742 | packet_send(); |
1707 | /* XXX wait for reply */ | 1743 | /* XXX wait for reply */ |
1744 | c->client_tty = 1; | ||
1708 | } | 1745 | } |
1709 | 1746 | ||
1710 | /* Transfer any environment variables from client to server */ | 1747 | /* Transfer any environment variables from client to server */ |