diff options
Diffstat (limited to 'clientloop.c')
-rw-r--r-- | clientloop.c | 308 |
1 files changed, 11 insertions, 297 deletions
diff --git a/clientloop.c b/clientloop.c index 7bd1af60c..c87aa5a0a 100644 --- a/clientloop.c +++ b/clientloop.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: clientloop.c,v 1.191 2008/05/09 04:55:56 djm Exp $ */ | 1 | /* $OpenBSD: clientloop.c,v 1.192 2008/05/09 14:18:44 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -121,7 +121,7 @@ extern int stdin_null_flag; | |||
121 | extern int no_shell_flag; | 121 | extern int no_shell_flag; |
122 | 122 | ||
123 | /* Control socket */ | 123 | /* Control socket */ |
124 | extern int control_fd; | 124 | extern int muxserver_sock; |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * Name of the host we are connecting to. This is the name given on the | 127 | * Name of the host we are connecting to. This is the name given on the |
@@ -162,17 +162,6 @@ static int session_closed = 0; /* In SSH2: login session closed. */ | |||
162 | static void client_init_dispatch(void); | 162 | static void client_init_dispatch(void); |
163 | int session_ident = -1; | 163 | int session_ident = -1; |
164 | 164 | ||
165 | struct confirm_ctx { | ||
166 | int want_tty; | ||
167 | int want_subsys; | ||
168 | int want_x_fwd; | ||
169 | int want_agent_fwd; | ||
170 | Buffer cmd; | ||
171 | char *term; | ||
172 | struct termios tio; | ||
173 | char **env; | ||
174 | }; | ||
175 | |||
176 | struct channel_reply_ctx { | 165 | struct channel_reply_ctx { |
177 | const char *request_type; | 166 | const char *request_type; |
178 | int id, do_close; | 167 | int id, do_close; |
@@ -538,8 +527,8 @@ client_wait_until_can_do_something(fd_set **readsetp, fd_set **writesetp, | |||
538 | if (packet_have_data_to_write()) | 527 | if (packet_have_data_to_write()) |
539 | FD_SET(connection_out, *writesetp); | 528 | FD_SET(connection_out, *writesetp); |
540 | 529 | ||
541 | if (control_fd != -1) | 530 | if (muxserver_sock != -1) |
542 | FD_SET(control_fd, *readsetp); | 531 | FD_SET(muxserver_sock, *readsetp); |
543 | 532 | ||
544 | /* | 533 | /* |
545 | * Wait for something to happen. This will suspend the process until | 534 | * Wait for something to happen. This will suspend the process until |
@@ -707,284 +696,6 @@ client_expect_confirm(int id, const char *request, int do_close) | |||
707 | } | 696 | } |
708 | 697 | ||
709 | static void | 698 | static void |
710 | client_extra_session2_setup(int id, void *arg) | ||
711 | { | ||
712 | struct confirm_ctx *cctx = arg; | ||
713 | const char *display; | ||
714 | Channel *c; | ||
715 | int i; | ||
716 | |||
717 | if (cctx == NULL) | ||
718 | fatal("%s: cctx == NULL", __func__); | ||
719 | if ((c = channel_lookup(id)) == NULL) | ||
720 | fatal("%s: no channel for id %d", __func__, id); | ||
721 | |||
722 | display = getenv("DISPLAY"); | ||
723 | if (cctx->want_x_fwd && options.forward_x11 && display != NULL) { | ||
724 | char *proto, *data; | ||
725 | /* Get reasonable local authentication information. */ | ||
726 | client_x11_get_proto(display, options.xauth_location, | ||
727 | options.forward_x11_trusted, &proto, &data); | ||
728 | /* Request forwarding with authentication spoofing. */ | ||
729 | debug("Requesting X11 forwarding with authentication spoofing."); | ||
730 | x11_request_forwarding_with_spoofing(id, display, proto, data); | ||
731 | /* XXX wait for reply */ | ||
732 | } | ||
733 | |||
734 | if (cctx->want_agent_fwd && options.forward_agent) { | ||
735 | debug("Requesting authentication agent forwarding."); | ||
736 | channel_request_start(id, "auth-agent-req@openssh.com", 0); | ||
737 | packet_send(); | ||
738 | } | ||
739 | |||
740 | client_session2_setup(id, cctx->want_tty, cctx->want_subsys, | ||
741 | cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env); | ||
742 | |||
743 | c->open_confirm_ctx = NULL; | ||
744 | buffer_free(&cctx->cmd); | ||
745 | xfree(cctx->term); | ||
746 | if (cctx->env != NULL) { | ||
747 | for (i = 0; cctx->env[i] != NULL; i++) | ||
748 | xfree(cctx->env[i]); | ||
749 | xfree(cctx->env); | ||
750 | } | ||
751 | xfree(cctx); | ||
752 | } | ||
753 | |||
754 | static void | ||
755 | client_process_control(fd_set *readset) | ||
756 | { | ||
757 | Buffer m; | ||
758 | Channel *c; | ||
759 | int client_fd, new_fd[3], ver, allowed, window, packetmax; | ||
760 | socklen_t addrlen; | ||
761 | struct sockaddr_storage addr; | ||
762 | struct confirm_ctx *cctx; | ||
763 | char *cmd; | ||
764 | u_int i, j, len, env_len, command, flags; | ||
765 | uid_t euid; | ||
766 | gid_t egid; | ||
767 | |||
768 | /* | ||
769 | * Accept connection on control socket | ||
770 | */ | ||
771 | if (control_fd == -1 || !FD_ISSET(control_fd, readset)) | ||
772 | return; | ||
773 | |||
774 | memset(&addr, 0, sizeof(addr)); | ||
775 | addrlen = sizeof(addr); | ||
776 | if ((client_fd = accept(control_fd, | ||
777 | (struct sockaddr*)&addr, &addrlen)) == -1) { | ||
778 | error("%s accept: %s", __func__, strerror(errno)); | ||
779 | return; | ||
780 | } | ||
781 | |||
782 | if (getpeereid(client_fd, &euid, &egid) < 0) { | ||
783 | error("%s getpeereid failed: %s", __func__, strerror(errno)); | ||
784 | close(client_fd); | ||
785 | return; | ||
786 | } | ||
787 | if ((euid != 0) && (getuid() != euid)) { | ||
788 | error("control mode uid mismatch: peer euid %u != uid %u", | ||
789 | (u_int) euid, (u_int) getuid()); | ||
790 | close(client_fd); | ||
791 | return; | ||
792 | } | ||
793 | |||
794 | unset_nonblock(client_fd); | ||
795 | |||
796 | /* Read command */ | ||
797 | buffer_init(&m); | ||
798 | if (ssh_msg_recv(client_fd, &m) == -1) { | ||
799 | error("%s: client msg_recv failed", __func__); | ||
800 | close(client_fd); | ||
801 | buffer_free(&m); | ||
802 | return; | ||
803 | } | ||
804 | if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { | ||
805 | error("%s: wrong client version %d", __func__, ver); | ||
806 | buffer_free(&m); | ||
807 | close(client_fd); | ||
808 | return; | ||
809 | } | ||
810 | |||
811 | allowed = 1; | ||
812 | command = buffer_get_int(&m); | ||
813 | flags = buffer_get_int(&m); | ||
814 | |||
815 | buffer_clear(&m); | ||
816 | |||
817 | switch (command) { | ||
818 | case SSHMUX_COMMAND_OPEN: | ||
819 | if (options.control_master == SSHCTL_MASTER_ASK || | ||
820 | options.control_master == SSHCTL_MASTER_AUTO_ASK) | ||
821 | allowed = ask_permission("Allow shared connection " | ||
822 | "to %s? ", host); | ||
823 | /* continue below */ | ||
824 | break; | ||
825 | case SSHMUX_COMMAND_TERMINATE: | ||
826 | if (options.control_master == SSHCTL_MASTER_ASK || | ||
827 | options.control_master == SSHCTL_MASTER_AUTO_ASK) | ||
828 | allowed = ask_permission("Terminate shared connection " | ||
829 | "to %s? ", host); | ||
830 | if (allowed) | ||
831 | quit_pending = 1; | ||
832 | /* FALLTHROUGH */ | ||
833 | case SSHMUX_COMMAND_ALIVE_CHECK: | ||
834 | /* Reply for SSHMUX_COMMAND_TERMINATE and ALIVE_CHECK */ | ||
835 | buffer_clear(&m); | ||
836 | buffer_put_int(&m, allowed); | ||
837 | buffer_put_int(&m, getpid()); | ||
838 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
839 | error("%s: client msg_send failed", __func__); | ||
840 | close(client_fd); | ||
841 | buffer_free(&m); | ||
842 | return; | ||
843 | } | ||
844 | buffer_free(&m); | ||
845 | close(client_fd); | ||
846 | return; | ||
847 | default: | ||
848 | error("Unsupported command %d", command); | ||
849 | buffer_free(&m); | ||
850 | close(client_fd); | ||
851 | return; | ||
852 | } | ||
853 | |||
854 | /* Reply for SSHMUX_COMMAND_OPEN */ | ||
855 | buffer_clear(&m); | ||
856 | buffer_put_int(&m, allowed); | ||
857 | buffer_put_int(&m, getpid()); | ||
858 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
859 | error("%s: client msg_send failed", __func__); | ||
860 | close(client_fd); | ||
861 | buffer_free(&m); | ||
862 | return; | ||
863 | } | ||
864 | |||
865 | if (!allowed) { | ||
866 | error("Refused control connection"); | ||
867 | close(client_fd); | ||
868 | buffer_free(&m); | ||
869 | return; | ||
870 | } | ||
871 | |||
872 | buffer_clear(&m); | ||
873 | if (ssh_msg_recv(client_fd, &m) == -1) { | ||
874 | error("%s: client msg_recv failed", __func__); | ||
875 | close(client_fd); | ||
876 | buffer_free(&m); | ||
877 | return; | ||
878 | } | ||
879 | if ((ver = buffer_get_char(&m)) != SSHMUX_VER) { | ||
880 | error("%s: wrong client version %d", __func__, ver); | ||
881 | buffer_free(&m); | ||
882 | close(client_fd); | ||
883 | return; | ||
884 | } | ||
885 | |||
886 | cctx = xcalloc(1, sizeof(*cctx)); | ||
887 | cctx->want_tty = (flags & SSHMUX_FLAG_TTY) != 0; | ||
888 | cctx->want_subsys = (flags & SSHMUX_FLAG_SUBSYS) != 0; | ||
889 | cctx->want_x_fwd = (flags & SSHMUX_FLAG_X11_FWD) != 0; | ||
890 | cctx->want_agent_fwd = (flags & SSHMUX_FLAG_AGENT_FWD) != 0; | ||
891 | cctx->term = buffer_get_string(&m, &len); | ||
892 | |||
893 | cmd = buffer_get_string(&m, &len); | ||
894 | buffer_init(&cctx->cmd); | ||
895 | buffer_append(&cctx->cmd, cmd, strlen(cmd)); | ||
896 | |||
897 | env_len = buffer_get_int(&m); | ||
898 | env_len = MIN(env_len, 4096); | ||
899 | debug3("%s: receiving %d env vars", __func__, env_len); | ||
900 | if (env_len != 0) { | ||
901 | cctx->env = xcalloc(env_len + 1, sizeof(*cctx->env)); | ||
902 | for (i = 0; i < env_len; i++) | ||
903 | cctx->env[i] = buffer_get_string(&m, &len); | ||
904 | cctx->env[i] = NULL; | ||
905 | } | ||
906 | |||
907 | debug2("%s: accepted tty %d, subsys %d, cmd %s", __func__, | ||
908 | cctx->want_tty, cctx->want_subsys, cmd); | ||
909 | xfree(cmd); | ||
910 | |||
911 | /* Gather fds from client */ | ||
912 | for(i = 0; i < 3; i++) { | ||
913 | if ((new_fd[i] = mm_receive_fd(client_fd)) == -1) { | ||
914 | error("%s: failed to receive fd %d from slave", | ||
915 | __func__, i); | ||
916 | for (j = 0; j < i; j++) | ||
917 | close(new_fd[j]); | ||
918 | for (j = 0; j < env_len; j++) | ||
919 | xfree(cctx->env[j]); | ||
920 | if (env_len > 0) | ||
921 | xfree(cctx->env); | ||
922 | xfree(cctx->term); | ||
923 | buffer_free(&cctx->cmd); | ||
924 | close(client_fd); | ||
925 | xfree(cctx); | ||
926 | return; | ||
927 | } | ||
928 | } | ||
929 | |||
930 | debug2("%s: got fds stdin %d, stdout %d, stderr %d", __func__, | ||
931 | new_fd[0], new_fd[1], new_fd[2]); | ||
932 | |||
933 | /* Try to pick up ttymodes from client before it goes raw */ | ||
934 | if (cctx->want_tty && tcgetattr(new_fd[0], &cctx->tio) == -1) | ||
935 | error("%s: tcgetattr: %s", __func__, strerror(errno)); | ||
936 | |||
937 | /* This roundtrip is just for synchronisation of ttymodes */ | ||
938 | buffer_clear(&m); | ||
939 | if (ssh_msg_send(client_fd, SSHMUX_VER, &m) == -1) { | ||
940 | error("%s: client msg_send failed", __func__); | ||
941 | close(client_fd); | ||
942 | close(new_fd[0]); | ||
943 | close(new_fd[1]); | ||
944 | close(new_fd[2]); | ||
945 | buffer_free(&m); | ||
946 | xfree(cctx->term); | ||
947 | if (env_len != 0) { | ||
948 | for (i = 0; i < env_len; i++) | ||
949 | xfree(cctx->env[i]); | ||
950 | xfree(cctx->env); | ||
951 | } | ||
952 | return; | ||
953 | } | ||
954 | buffer_free(&m); | ||
955 | |||
956 | /* enable nonblocking unless tty */ | ||
957 | if (!isatty(new_fd[0])) | ||
958 | set_nonblock(new_fd[0]); | ||
959 | if (!isatty(new_fd[1])) | ||
960 | set_nonblock(new_fd[1]); | ||
961 | if (!isatty(new_fd[2])) | ||
962 | set_nonblock(new_fd[2]); | ||
963 | |||
964 | set_nonblock(client_fd); | ||
965 | |||
966 | window = CHAN_SES_WINDOW_DEFAULT; | ||
967 | packetmax = CHAN_SES_PACKET_DEFAULT; | ||
968 | if (cctx->want_tty) { | ||
969 | window >>= 1; | ||
970 | packetmax >>= 1; | ||
971 | } | ||
972 | |||
973 | c = channel_new("session", SSH_CHANNEL_OPENING, | ||
974 | new_fd[0], new_fd[1], new_fd[2], window, packetmax, | ||
975 | CHAN_EXTENDED_WRITE, "client-session", /*nonblock*/0); | ||
976 | |||
977 | /* XXX */ | ||
978 | c->ctl_fd = client_fd; | ||
979 | |||
980 | debug3("%s: channel_new: %d", __func__, c->self); | ||
981 | |||
982 | channel_send_open(c->self); | ||
983 | channel_register_open_confirm(c->self, | ||
984 | client_extra_session2_setup, cctx); | ||
985 | } | ||
986 | |||
987 | static void | ||
988 | process_cmdline(void) | 699 | process_cmdline(void) |
989 | { | 700 | { |
990 | void (*handler)(int); | 701 | void (*handler)(int); |
@@ -1448,8 +1159,8 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1448 | connection_in = packet_get_connection_in(); | 1159 | connection_in = packet_get_connection_in(); |
1449 | connection_out = packet_get_connection_out(); | 1160 | connection_out = packet_get_connection_out(); |
1450 | max_fd = MAX(connection_in, connection_out); | 1161 | max_fd = MAX(connection_in, connection_out); |
1451 | if (control_fd != -1) | 1162 | if (muxserver_sock != -1) |
1452 | max_fd = MAX(max_fd, control_fd); | 1163 | max_fd = MAX(max_fd, muxserver_sock); |
1453 | 1164 | ||
1454 | if (!compat20) { | 1165 | if (!compat20) { |
1455 | /* enable nonblocking unless tty */ | 1166 | /* enable nonblocking unless tty */ |
@@ -1569,7 +1280,10 @@ client_loop(int have_pty, int escape_char_arg, int ssh2_chan_id) | |||
1569 | client_process_net_input(readset); | 1280 | client_process_net_input(readset); |
1570 | 1281 | ||
1571 | /* Accept control connections. */ | 1282 | /* Accept control connections. */ |
1572 | client_process_control(readset); | 1283 | if (muxserver_sock != -1 &&FD_ISSET(muxserver_sock, readset)) { |
1284 | if (muxserver_accept_control()) | ||
1285 | quit_pending = 1; | ||
1286 | } | ||
1573 | 1287 | ||
1574 | if (quit_pending) | 1288 | if (quit_pending) |
1575 | break; | 1289 | break; |
@@ -2157,7 +1871,7 @@ cleanup_exit(int i) | |||
2157 | { | 1871 | { |
2158 | leave_raw_mode(); | 1872 | leave_raw_mode(); |
2159 | leave_non_blocking(); | 1873 | leave_non_blocking(); |
2160 | if (options.control_path != NULL && control_fd != -1) | 1874 | if (options.control_path != NULL && muxserver_sock != -1) |
2161 | unlink(options.control_path); | 1875 | unlink(options.control_path); |
2162 | _exit(i); | 1876 | _exit(i); |
2163 | } | 1877 | } |