diff options
Diffstat (limited to 'channels.c')
-rw-r--r-- | channels.c | 228 |
1 files changed, 182 insertions, 46 deletions
diff --git a/channels.c b/channels.c index d5526fb83..0e334db88 100644 --- a/channels.c +++ b/channels.c | |||
@@ -40,7 +40,7 @@ | |||
40 | */ | 40 | */ |
41 | 41 | ||
42 | #include "includes.h" | 42 | #include "includes.h" |
43 | RCSID("$OpenBSD: channels.c,v 1.102 2001/04/06 21:00:10 markus Exp $"); | 43 | RCSID("$OpenBSD: channels.c,v 1.103 2001/04/07 08:55:17 markus Exp $"); |
44 | 44 | ||
45 | #include <openssl/rsa.h> | 45 | #include <openssl/rsa.h> |
46 | #include <openssl/dsa.h> | 46 | #include <openssl/dsa.h> |
@@ -51,6 +51,7 @@ RCSID("$OpenBSD: channels.c,v 1.102 2001/04/06 21:00:10 markus Exp $"); | |||
51 | #include "packet.h" | 51 | #include "packet.h" |
52 | #include "xmalloc.h" | 52 | #include "xmalloc.h" |
53 | #include "buffer.h" | 53 | #include "buffer.h" |
54 | #include "bufaux.h" | ||
54 | #include "uidswap.h" | 55 | #include "uidswap.h" |
55 | #include "log.h" | 56 | #include "log.h" |
56 | #include "misc.h" | 57 | #include "misc.h" |
@@ -133,6 +134,8 @@ static int have_hostname_in_open = 0; | |||
133 | /* AF_UNSPEC or AF_INET or AF_INET6 */ | 134 | /* AF_UNSPEC or AF_INET or AF_INET6 */ |
134 | extern int IPv4or6; | 135 | extern int IPv4or6; |
135 | 136 | ||
137 | void port_open_helper(Channel *c, char *rtype); | ||
138 | |||
136 | /* Sets specific protocol options. */ | 139 | /* Sets specific protocol options. */ |
137 | 140 | ||
138 | void | 141 | void |
@@ -539,6 +542,89 @@ channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset) | |||
539 | } | 542 | } |
540 | } | 543 | } |
541 | 544 | ||
545 | #define SSH_SOCKS_HEAD 1+1+2+4 | ||
546 | |||
547 | void | ||
548 | channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | ||
549 | { | ||
550 | u_char *p, *host; | ||
551 | int len, i, done, have; | ||
552 | char username[256]; | ||
553 | struct { | ||
554 | u_int8_t version; | ||
555 | u_int8_t command; | ||
556 | u_int16_t dest_port; | ||
557 | struct in_addr dest_ip; | ||
558 | } s4_req, s4_rsp; | ||
559 | |||
560 | have = buffer_len(&c->input); | ||
561 | |||
562 | debug("channel %d: pre_dynamic have: %d", c->self, have); | ||
563 | /*buffer_dump(&c->input);*/ | ||
564 | |||
565 | /* Check if the fixed size part of the packet is in buffer. */ | ||
566 | if (have < SSH_SOCKS_HEAD + 1) { | ||
567 | /* need more */ | ||
568 | FD_SET(c->sock, readset); | ||
569 | return; | ||
570 | } | ||
571 | /* Check for end of username */ | ||
572 | p = buffer_ptr(&c->input); | ||
573 | done = 0; | ||
574 | for (i = SSH_SOCKS_HEAD; i < have; i++) { | ||
575 | if (p[i] == '\0') { | ||
576 | done = 1; | ||
577 | break; | ||
578 | } | ||
579 | } | ||
580 | if (!done) { | ||
581 | /* need more */ | ||
582 | FD_SET(c->sock, readset); | ||
583 | return; | ||
584 | } | ||
585 | buffer_get(&c->input, (char *)&s4_req.version, 1); | ||
586 | buffer_get(&c->input, (char *)&s4_req.command, 1); | ||
587 | buffer_get(&c->input, (char *)&s4_req.dest_port, 2); | ||
588 | buffer_get(&c->input, (char *)&s4_req.dest_ip, 4); | ||
589 | p = buffer_ptr(&c->input); | ||
590 | len = strlen(p); | ||
591 | have = buffer_len(&c->input); | ||
592 | debug2("channel %d: pre_dynamic user: %s/%d", c->self, p, len); | ||
593 | if (len > have) | ||
594 | fatal("channel %d: pre_dynamic: len %d > have %d", | ||
595 | c->self, len, have); | ||
596 | strlcpy(username, p, sizeof(username)); | ||
597 | buffer_consume(&c->input, len); | ||
598 | buffer_consume(&c->input, 1); /* trailing '\0' */ | ||
599 | |||
600 | host = inet_ntoa(s4_req.dest_ip); | ||
601 | strlcpy(c->path, host, sizeof(c->path)); | ||
602 | c->host_port = ntohs(s4_req.dest_port); | ||
603 | |||
604 | debug("channel %d: dynamic request received: " | ||
605 | "socks%x://%s@%s:%u/command?%u", | ||
606 | c->self, s4_req.version, username, host, c->host_port, | ||
607 | s4_req.command); | ||
608 | |||
609 | if ((s4_req.version != 4) || (s4_req.command != 1)) { | ||
610 | debug("channel %d: cannot handle: socks VN %d CN %d", | ||
611 | c->self, s4_req.version, s4_req.command); | ||
612 | channel_free(c->self); | ||
613 | return; | ||
614 | } | ||
615 | |||
616 | s4_rsp.version = 0; /* VN: version of reply code */ | ||
617 | s4_rsp.command = 90; /* CD: request granted */ | ||
618 | s4_rsp.dest_port = 0; /* ignored */ | ||
619 | s4_rsp.dest_ip.s_addr = INADDR_ANY; /* ignored */ | ||
620 | buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp)); | ||
621 | |||
622 | /* switch to next state */ | ||
623 | c->type = SSH_CHANNEL_OPENING; | ||
624 | port_open_helper(c, "direct-tcpip"); | ||
625 | } | ||
626 | |||
627 | |||
542 | /* This is our fake X11 server socket. */ | 628 | /* This is our fake X11 server socket. */ |
543 | void | 629 | void |
544 | channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) | 630 | channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) |
@@ -591,73 +677,100 @@ channel_post_x11_listener(Channel *c, fd_set * readset, fd_set * writeset) | |||
591 | } | 677 | } |
592 | } | 678 | } |
593 | 679 | ||
680 | void | ||
681 | port_open_helper(Channel *c, char *rtype) | ||
682 | { | ||
683 | int direct; | ||
684 | char buf[1024]; | ||
685 | char *remote_ipaddr = get_peer_ipaddr(c->sock); | ||
686 | u_short remote_port = get_peer_port(c->sock); | ||
687 | |||
688 | direct = (strcmp(rtype, "direct-tcpip") == 0); | ||
689 | |||
690 | snprintf(buf, sizeof buf, | ||
691 | "%s: listening port %d for %.100s port %d, " | ||
692 | "connect from %.200s port %d", | ||
693 | rtype, c->listening_port, c->path, c->host_port, | ||
694 | remote_ipaddr, remote_port); | ||
695 | |||
696 | xfree(c->remote_name); | ||
697 | c->remote_name = xstrdup(buf); | ||
698 | |||
699 | if (compat20) { | ||
700 | packet_start(SSH2_MSG_CHANNEL_OPEN); | ||
701 | packet_put_cstring(rtype); | ||
702 | packet_put_int(c->self); | ||
703 | packet_put_int(c->local_window_max); | ||
704 | packet_put_int(c->local_maxpacket); | ||
705 | if (direct) { | ||
706 | /* target host, port */ | ||
707 | packet_put_cstring(c->path); | ||
708 | packet_put_int(c->host_port); | ||
709 | } else { | ||
710 | /* listen address, port */ | ||
711 | packet_put_cstring(c->path); | ||
712 | packet_put_int(c->listening_port); | ||
713 | } | ||
714 | /* originator host and port */ | ||
715 | packet_put_cstring(remote_ipaddr); | ||
716 | packet_put_int(remote_port); | ||
717 | packet_send(); | ||
718 | } else { | ||
719 | packet_start(SSH_MSG_PORT_OPEN); | ||
720 | packet_put_int(c->self); | ||
721 | packet_put_cstring(c->path); | ||
722 | packet_put_int(c->host_port); | ||
723 | if (have_hostname_in_open) | ||
724 | packet_put_cstring(c->remote_name); | ||
725 | packet_send(); | ||
726 | } | ||
727 | xfree(remote_ipaddr); | ||
728 | } | ||
729 | |||
594 | /* | 730 | /* |
595 | * This socket is listening for connections to a forwarded TCP/IP port. | 731 | * This socket is listening for connections to a forwarded TCP/IP port. |
596 | */ | 732 | */ |
597 | void | 733 | void |
598 | channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) | 734 | channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset) |
599 | { | 735 | { |
736 | Channel *nc; | ||
600 | struct sockaddr addr; | 737 | struct sockaddr addr; |
601 | int newsock, newch; | 738 | int newsock, newch, nextstate; |
602 | socklen_t addrlen; | 739 | socklen_t addrlen; |
603 | char buf[1024], *remote_ipaddr, *rtype; | 740 | char *rtype; |
604 | int remote_port; | ||
605 | |||
606 | rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ? | ||
607 | "forwarded-tcpip" : "direct-tcpip"; | ||
608 | 741 | ||
609 | if (FD_ISSET(c->sock, readset)) { | 742 | if (FD_ISSET(c->sock, readset)) { |
610 | debug("Connection to port %d forwarding " | 743 | debug("Connection to port %d forwarding " |
611 | "to %.100s port %d requested.", | 744 | "to %.100s port %d requested.", |
612 | c->listening_port, c->path, c->host_port); | 745 | c->listening_port, c->path, c->host_port); |
746 | |||
747 | rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ? | ||
748 | "forwarded-tcpip" : "direct-tcpip"; | ||
749 | nextstate = (c->host_port == 0) ? SSH_CHANNEL_DYNAMIC : | ||
750 | SSH_CHANNEL_OPENING; | ||
751 | |||
613 | addrlen = sizeof(addr); | 752 | addrlen = sizeof(addr); |
614 | newsock = accept(c->sock, &addr, &addrlen); | 753 | newsock = accept(c->sock, &addr, &addrlen); |
615 | if (newsock < 0) { | 754 | if (newsock < 0) { |
616 | error("accept: %.100s", strerror(errno)); | 755 | error("accept: %.100s", strerror(errno)); |
617 | return; | 756 | return; |
618 | } | 757 | } |
619 | remote_ipaddr = get_peer_ipaddr(newsock); | ||
620 | remote_port = get_peer_port(newsock); | ||
621 | snprintf(buf, sizeof buf, | ||
622 | "listen port %d for %.100s port %d, " | ||
623 | "connect from %.200s port %d", | ||
624 | c->listening_port, c->path, c->host_port, | ||
625 | remote_ipaddr, remote_port); | ||
626 | |||
627 | newch = channel_new(rtype, | 758 | newch = channel_new(rtype, |
628 | SSH_CHANNEL_OPENING, newsock, newsock, -1, | 759 | nextstate, newsock, newsock, -1, |
629 | c->local_window_max, c->local_maxpacket, | 760 | c->local_window_max, c->local_maxpacket, |
630 | 0, xstrdup(buf), 1); | 761 | 0, xstrdup(rtype), 1); |
631 | if (compat20) { | 762 | |
632 | packet_start(SSH2_MSG_CHANNEL_OPEN); | 763 | nc = channel_lookup(newch); |
633 | packet_put_cstring(rtype); | 764 | if (nc == NULL) { |
634 | packet_put_int(newch); | 765 | error("xxx: no new channel:"); |
635 | packet_put_int(c->local_window_max); | 766 | return; |
636 | packet_put_int(c->local_maxpacket); | ||
637 | if (c->type == SSH_CHANNEL_RPORT_LISTENER) { | ||
638 | /* listen address, port */ | ||
639 | packet_put_string(c->path, strlen(c->path)); | ||
640 | packet_put_int(c->listening_port); | ||
641 | } else { | ||
642 | /* target host, port */ | ||
643 | packet_put_string(c->path, strlen(c->path)); | ||
644 | packet_put_int(c->host_port); | ||
645 | } | ||
646 | /* originator host and port */ | ||
647 | packet_put_cstring(remote_ipaddr); | ||
648 | packet_put_int(remote_port); | ||
649 | packet_send(); | ||
650 | } else { | ||
651 | packet_start(SSH_MSG_PORT_OPEN); | ||
652 | packet_put_int(newch); | ||
653 | packet_put_string(c->path, strlen(c->path)); | ||
654 | packet_put_int(c->host_port); | ||
655 | if (have_hostname_in_open) { | ||
656 | packet_put_string(buf, strlen(buf)); | ||
657 | } | ||
658 | packet_send(); | ||
659 | } | 767 | } |
660 | xfree(remote_ipaddr); | 768 | nc->listening_port = c->listening_port; |
769 | nc->host_port = c->host_port; | ||
770 | strlcpy(nc->path, c->path, sizeof(nc->path)); | ||
771 | |||
772 | if (nextstate != SSH_CHANNEL_DYNAMIC) | ||
773 | port_open_helper(nc, rtype); | ||
661 | } | 774 | } |
662 | } | 775 | } |
663 | 776 | ||
@@ -733,6 +846,15 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset) | |||
733 | if (len <= 0) { | 846 | if (len <= 0) { |
734 | debug("channel %d: read<=0 rfd %d len %d", | 847 | debug("channel %d: read<=0 rfd %d len %d", |
735 | c->self, c->rfd, len); | 848 | c->self, c->rfd, len); |
849 | if (c->type == SSH_CHANNEL_DYNAMIC) { | ||
850 | /* | ||
851 | * we are not yet connected to a remote peer, | ||
852 | * so the connection-close protocol won't work | ||
853 | */ | ||
854 | debug("channel %d: dynamic: closed", c->self); | ||
855 | channel_free(c->self); | ||
856 | return -1; | ||
857 | } | ||
736 | if (compat13) { | 858 | if (compat13) { |
737 | buffer_consume(&c->output, buffer_len(&c->output)); | 859 | buffer_consume(&c->output, buffer_len(&c->output)); |
738 | c->type = SSH_CHANNEL_INPUT_DRAINING; | 860 | c->type = SSH_CHANNEL_INPUT_DRAINING; |
@@ -894,6 +1016,12 @@ channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset) | |||
894 | } | 1016 | } |
895 | 1017 | ||
896 | void | 1018 | void |
1019 | channel_post_dynamic(Channel *c, fd_set * readset, fd_set * writeset) | ||
1020 | { | ||
1021 | channel_handle_rfd(c, readset, writeset); | ||
1022 | } | ||
1023 | |||
1024 | void | ||
897 | channel_handler_init_20(void) | 1025 | channel_handler_init_20(void) |
898 | { | 1026 | { |
899 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; | 1027 | channel_pre[SSH_CHANNEL_OPEN] = &channel_pre_open_20; |
@@ -903,6 +1031,7 @@ channel_handler_init_20(void) | |||
903 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; | 1031 | channel_pre[SSH_CHANNEL_X11_LISTENER] = &channel_pre_listener; |
904 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | 1032 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
905 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | 1033 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
1034 | channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; | ||
906 | 1035 | ||
907 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2; | 1036 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_2; |
908 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | 1037 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
@@ -910,6 +1039,7 @@ channel_handler_init_20(void) | |||
910 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | 1039 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
911 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 1040 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
912 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 1041 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
1042 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic; | ||
913 | } | 1043 | } |
914 | 1044 | ||
915 | void | 1045 | void |
@@ -923,6 +1053,7 @@ channel_handler_init_13(void) | |||
923 | channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; | 1053 | channel_pre[SSH_CHANNEL_INPUT_DRAINING] = &channel_pre_input_draining; |
924 | channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; | 1054 | channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_pre_output_draining; |
925 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | 1055 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
1056 | channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; | ||
926 | 1057 | ||
927 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; | 1058 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; |
928 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | 1059 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
@@ -930,6 +1061,7 @@ channel_handler_init_13(void) | |||
930 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 1061 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
931 | channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; | 1062 | channel_post[SSH_CHANNEL_OUTPUT_DRAINING] = &channel_post_output_drain_13; |
932 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 1063 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
1064 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic; | ||
933 | } | 1065 | } |
934 | 1066 | ||
935 | void | 1067 | void |
@@ -941,12 +1073,14 @@ channel_handler_init_15(void) | |||
941 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; | 1073 | channel_pre[SSH_CHANNEL_PORT_LISTENER] = &channel_pre_listener; |
942 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; | 1074 | channel_pre[SSH_CHANNEL_AUTH_SOCKET] = &channel_pre_listener; |
943 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; | 1075 | channel_pre[SSH_CHANNEL_CONNECTING] = &channel_pre_connecting; |
1076 | channel_pre[SSH_CHANNEL_DYNAMIC] = &channel_pre_dynamic; | ||
944 | 1077 | ||
945 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; | 1078 | channel_post[SSH_CHANNEL_X11_LISTENER] = &channel_post_x11_listener; |
946 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; | 1079 | channel_post[SSH_CHANNEL_PORT_LISTENER] = &channel_post_port_listener; |
947 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; | 1080 | channel_post[SSH_CHANNEL_AUTH_SOCKET] = &channel_post_auth_listener; |
948 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; | 1081 | channel_post[SSH_CHANNEL_OPEN] = &channel_post_open_1; |
949 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; | 1082 | channel_post[SSH_CHANNEL_CONNECTING] = &channel_post_connecting; |
1083 | channel_post[SSH_CHANNEL_DYNAMIC] = &channel_post_dynamic; | ||
950 | } | 1084 | } |
951 | 1085 | ||
952 | void | 1086 | void |
@@ -1500,6 +1634,7 @@ channel_still_open() | |||
1500 | case SSH_CHANNEL_RPORT_LISTENER: | 1634 | case SSH_CHANNEL_RPORT_LISTENER: |
1501 | case SSH_CHANNEL_CLOSED: | 1635 | case SSH_CHANNEL_CLOSED: |
1502 | case SSH_CHANNEL_AUTH_SOCKET: | 1636 | case SSH_CHANNEL_AUTH_SOCKET: |
1637 | case SSH_CHANNEL_DYNAMIC: | ||
1503 | case SSH_CHANNEL_CONNECTING: /* XXX ??? */ | 1638 | case SSH_CHANNEL_CONNECTING: /* XXX ??? */ |
1504 | continue; | 1639 | continue; |
1505 | case SSH_CHANNEL_LARVAL: | 1640 | case SSH_CHANNEL_LARVAL: |
@@ -1551,6 +1686,7 @@ channel_open_message() | |||
1551 | case SSH_CHANNEL_LARVAL: | 1686 | case SSH_CHANNEL_LARVAL: |
1552 | case SSH_CHANNEL_OPENING: | 1687 | case SSH_CHANNEL_OPENING: |
1553 | case SSH_CHANNEL_CONNECTING: | 1688 | case SSH_CHANNEL_CONNECTING: |
1689 | case SSH_CHANNEL_DYNAMIC: | ||
1554 | case SSH_CHANNEL_OPEN: | 1690 | case SSH_CHANNEL_OPEN: |
1555 | case SSH_CHANNEL_X11_OPEN: | 1691 | case SSH_CHANNEL_X11_OPEN: |
1556 | case SSH_CHANNEL_INPUT_DRAINING: | 1692 | case SSH_CHANNEL_INPUT_DRAINING: |