]> andersk Git - openssh.git/blobdiff - channels.c
- markus@cvs.openbsd.org 2001/04/07 08:55:18
[openssh.git] / channels.c
index d5526fb8374ac9d10cef91d31113862768a4cf19..0e334db88a24025549f2bf814851f3ab7e1f43a2 100644 (file)
@@ -40,7 +40,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: channels.c,v 1.102 2001/04/06 21:00:10 markus Exp $");
+RCSID("$OpenBSD: channels.c,v 1.103 2001/04/07 08:55:17 markus Exp $");
 
 #include <openssl/rsa.h>
 #include <openssl/dsa.h>
@@ -51,6 +51,7 @@ RCSID("$OpenBSD: channels.c,v 1.102 2001/04/06 21:00:10 markus Exp $");
 #include "packet.h"
 #include "xmalloc.h"
 #include "buffer.h"
+#include "bufaux.h"
 #include "uidswap.h"
 #include "log.h"
 #include "misc.h"
@@ -133,6 +134,8 @@ static int have_hostname_in_open = 0;
 /* AF_UNSPEC or AF_INET or AF_INET6 */
 extern int IPv4or6;
 
+void    port_open_helper(Channel *c, char *rtype);
+
 /* Sets specific protocol options. */
 
 void
@@ -539,6 +542,89 @@ channel_pre_x11_open(Channel *c, fd_set * readset, fd_set * writeset)
        }
 }
 
+#define SSH_SOCKS_HEAD 1+1+2+4
+
+void
+channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       u_char *p, *host;
+       int len, i, done, have;
+       char username[256];
+       struct {
+               u_int8_t version;
+               u_int8_t command;
+               u_int16_t dest_port;
+               struct in_addr dest_ip;
+       } s4_req, s4_rsp;
+
+       have = buffer_len(&c->input);
+
+       debug("channel %d: pre_dynamic have: %d", c->self, have);
+       /*buffer_dump(&c->input);*/
+
+       /* Check if the fixed size part of the packet is in buffer. */
+       if (have < SSH_SOCKS_HEAD + 1) {
+               /* need more */
+               FD_SET(c->sock, readset);
+               return;
+       }
+       /* Check for end of username */
+       p = buffer_ptr(&c->input);
+       done = 0;
+       for (i = SSH_SOCKS_HEAD; i < have; i++) {
+               if (p[i] == '\0') {
+                       done = 1;
+                       break;
+               }
+       }
+       if (!done) {
+               /* need more */
+               FD_SET(c->sock, readset);
+               return;
+       }
+       buffer_get(&c->input, (char *)&s4_req.version, 1);
+       buffer_get(&c->input, (char *)&s4_req.command, 1);
+       buffer_get(&c->input, (char *)&s4_req.dest_port, 2);
+       buffer_get(&c->input, (char *)&s4_req.dest_ip, 4);
+       p = buffer_ptr(&c->input);
+       len = strlen(p);
+       have = buffer_len(&c->input);
+       debug2("channel %d: pre_dynamic user: %s/%d", c->self, p, len);
+       if (len > have)
+               fatal("channel %d: pre_dynamic: len %d > have %d",
+                   c->self, len, have);
+       strlcpy(username, p, sizeof(username));
+       buffer_consume(&c->input, len);
+       buffer_consume(&c->input, 1);           /* trailing '\0' */
+
+       host = inet_ntoa(s4_req.dest_ip);
+       strlcpy(c->path, host, sizeof(c->path));
+       c->host_port = ntohs(s4_req.dest_port);
+       
+       debug("channel %d: dynamic request received: "
+           "socks%x://%s@%s:%u/command?%u",
+           c->self, s4_req.version, username, host, c->host_port,
+           s4_req.command);
+
+       if ((s4_req.version != 4) || (s4_req.command != 1)) {
+               debug("channel %d: cannot handle: socks VN %d CN %d",
+                   c->self, s4_req.version, s4_req.command);
+               channel_free(c->self);
+               return;
+       }
+
+       s4_rsp.version = 0;                     /* VN: version of reply code */
+       s4_rsp.command = 90;                    /* CD: request granted */
+       s4_rsp.dest_port = 0;                   /* ignored */
+       s4_rsp.dest_ip.s_addr = INADDR_ANY;     /* ignored */
+       buffer_append(&c->output, (char *)&s4_rsp, sizeof(s4_rsp));
+
+       /* switch to next state */
+       c->type = SSH_CHANNEL_OPENING;
+       port_open_helper(c, "direct-tcpip");
+}
+
+
 /* This is our fake X11 server socket. */
 void
 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)
        }
 }
 
+void
+port_open_helper(Channel *c, char *rtype)
+{
+       int direct;
+       char buf[1024];
+       char *remote_ipaddr = get_peer_ipaddr(c->sock);
+       u_short remote_port = get_peer_port(c->sock);
+
+       direct = (strcmp(rtype, "direct-tcpip") == 0);
+
+       snprintf(buf, sizeof buf,
+           "%s: listening port %d for %.100s port %d, "
+           "connect from %.200s port %d",
+           rtype, c->listening_port, c->path, c->host_port,
+           remote_ipaddr, remote_port);
+
+       xfree(c->remote_name);
+       c->remote_name = xstrdup(buf);
+
+       if (compat20) {
+               packet_start(SSH2_MSG_CHANNEL_OPEN);
+               packet_put_cstring(rtype);
+               packet_put_int(c->self);
+               packet_put_int(c->local_window_max);
+               packet_put_int(c->local_maxpacket);
+               if (direct) {
+                       /* target host, port */
+                       packet_put_cstring(c->path);
+                       packet_put_int(c->host_port);
+               } else {
+                       /* listen address, port */
+                       packet_put_cstring(c->path);
+                       packet_put_int(c->listening_port);
+               }
+               /* originator host and port */
+               packet_put_cstring(remote_ipaddr);
+               packet_put_int(remote_port);
+               packet_send();
+       } else {
+               packet_start(SSH_MSG_PORT_OPEN);
+               packet_put_int(c->self);
+               packet_put_cstring(c->path);
+               packet_put_int(c->host_port);
+               if (have_hostname_in_open)
+                       packet_put_cstring(c->remote_name);
+               packet_send();
+       }
+       xfree(remote_ipaddr);
+}
+
 /*
  * This socket is listening for connections to a forwarded TCP/IP port.
  */
 void
 channel_post_port_listener(Channel *c, fd_set * readset, fd_set * writeset)
 {
+       Channel *nc;
        struct sockaddr addr;
-       int newsock, newch;
+       int newsock, newch, nextstate;
        socklen_t addrlen;
-       char buf[1024], *remote_ipaddr, *rtype;
-       int remote_port;
-
-       rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ?
-           "forwarded-tcpip" : "direct-tcpip";
+       char *rtype;
 
        if (FD_ISSET(c->sock, readset)) {
                debug("Connection to port %d forwarding "
                    "to %.100s port %d requested.",
                    c->listening_port, c->path, c->host_port);
+
+               rtype = (c->type == SSH_CHANNEL_RPORT_LISTENER) ?
+                   "forwarded-tcpip" : "direct-tcpip";
+               nextstate = (c->host_port == 0) ? SSH_CHANNEL_DYNAMIC :
+                   SSH_CHANNEL_OPENING;
+
                addrlen = sizeof(addr);
                newsock = accept(c->sock, &addr, &addrlen);
                if (newsock < 0) {
                        error("accept: %.100s", strerror(errno));
                        return;
                }
-               remote_ipaddr = get_peer_ipaddr(newsock);
-               remote_port = get_peer_port(newsock);
-               snprintf(buf, sizeof buf,
-                   "listen port %d for %.100s port %d, "
-                   "connect from %.200s port %d",
-                   c->listening_port, c->path, c->host_port,
-                   remote_ipaddr, remote_port);
-
                newch = channel_new(rtype,
-                   SSH_CHANNEL_OPENING, newsock, newsock, -1,
+                   nextstate, newsock, newsock, -1,
                    c->local_window_max, c->local_maxpacket,
-                   0, xstrdup(buf), 1);
-               if (compat20) {
-                       packet_start(SSH2_MSG_CHANNEL_OPEN);
-                       packet_put_cstring(rtype);
-                       packet_put_int(newch);
-                       packet_put_int(c->local_window_max);
-                       packet_put_int(c->local_maxpacket);
-                       if (c->type == SSH_CHANNEL_RPORT_LISTENER) {
-                               /* listen address, port */
-                               packet_put_string(c->path, strlen(c->path));
-                               packet_put_int(c->listening_port);
-                       } else {
-                               /* target host, port */
-                               packet_put_string(c->path, strlen(c->path));
-                               packet_put_int(c->host_port);
-                       }
-                       /* originator host and port */
-                       packet_put_cstring(remote_ipaddr);
-                       packet_put_int(remote_port);
-                       packet_send();
-               } else {
-                       packet_start(SSH_MSG_PORT_OPEN);
-                       packet_put_int(newch);
-                       packet_put_string(c->path, strlen(c->path));
-                       packet_put_int(c->host_port);
-                       if (have_hostname_in_open) {
-                               packet_put_string(buf, strlen(buf));
-                       }
-                       packet_send();
+                   0, xstrdup(rtype), 1);
+
+               nc = channel_lookup(newch);
+               if (nc == NULL) {
+                       error("xxx: no new channel:");
+                       return;
                }
-               xfree(remote_ipaddr);
+               nc->listening_port = c->listening_port;
+               nc->host_port = c->host_port;
+               strlcpy(nc->path, c->path, sizeof(nc->path));
+
+               if (nextstate != SSH_CHANNEL_DYNAMIC)
+                       port_open_helper(nc, rtype);
        }
 }
 
@@ -733,6 +846,15 @@ channel_handle_rfd(Channel *c, fd_set * readset, fd_set * writeset)
                if (len <= 0) {
                        debug("channel %d: read<=0 rfd %d len %d",
                            c->self, c->rfd, len);
+                       if (c->type == SSH_CHANNEL_DYNAMIC) {
+                               /*
+                                * we are not yet connected to a remote peer,
+                                * so the connection-close protocol won't work
+                                */
+                               debug("channel %d: dynamic: closed", c->self);
+                               channel_free(c->self);
+                               return -1;
+                       }
                        if (compat13) {
                                buffer_consume(&c->output, buffer_len(&c->output));
                                c->type = SSH_CHANNEL_INPUT_DRAINING;
@@ -893,6 +1015,12 @@ channel_post_output_drain_13(Channel *c, fd_set * readset, fd_set * writeset)
        }
 }
 
+void
+channel_post_dynamic(Channel *c, fd_set * readset, fd_set * writeset)
+{
+       channel_handle_rfd(c, readset, writeset);
+}
+
 void
 channel_handler_init_20(void)
 {
@@ -903,6 +1031,7 @@ channel_handler_init_20(void)
        channel_pre[SSH_CHANNEL_X11_LISTENER] =         &channel_pre_listener;
        channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
        channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
 
        channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_2;
        channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
@@ -910,6 +1039,7 @@ channel_handler_init_20(void)
        channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
        channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
        channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_dynamic;
 }
 
 void
@@ -923,6 +1053,7 @@ channel_handler_init_13(void)
        channel_pre[SSH_CHANNEL_INPUT_DRAINING] =       &channel_pre_input_draining;
        channel_pre[SSH_CHANNEL_OUTPUT_DRAINING] =      &channel_pre_output_draining;
        channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
 
        channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_1;
        channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
@@ -930,6 +1061,7 @@ channel_handler_init_13(void)
        channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
        channel_post[SSH_CHANNEL_OUTPUT_DRAINING] =     &channel_post_output_drain_13;
        channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_dynamic;
 }
 
 void
@@ -941,12 +1073,14 @@ channel_handler_init_15(void)
        channel_pre[SSH_CHANNEL_PORT_LISTENER] =        &channel_pre_listener;
        channel_pre[SSH_CHANNEL_AUTH_SOCKET] =          &channel_pre_listener;
        channel_pre[SSH_CHANNEL_CONNECTING] =           &channel_pre_connecting;
+       channel_pre[SSH_CHANNEL_DYNAMIC] =              &channel_pre_dynamic;
 
        channel_post[SSH_CHANNEL_X11_LISTENER] =        &channel_post_x11_listener;
        channel_post[SSH_CHANNEL_PORT_LISTENER] =       &channel_post_port_listener;
        channel_post[SSH_CHANNEL_AUTH_SOCKET] =         &channel_post_auth_listener;
        channel_post[SSH_CHANNEL_OPEN] =                &channel_post_open_1;
        channel_post[SSH_CHANNEL_CONNECTING] =          &channel_post_connecting;
+       channel_post[SSH_CHANNEL_DYNAMIC] =             &channel_post_dynamic;
 }
 
 void
@@ -1500,6 +1634,7 @@ channel_still_open()
                case SSH_CHANNEL_RPORT_LISTENER:
                case SSH_CHANNEL_CLOSED:
                case SSH_CHANNEL_AUTH_SOCKET:
+               case SSH_CHANNEL_DYNAMIC:
                case SSH_CHANNEL_CONNECTING:    /* XXX ??? */
                        continue;
                case SSH_CHANNEL_LARVAL:
@@ -1551,6 +1686,7 @@ channel_open_message()
                case SSH_CHANNEL_LARVAL:
                case SSH_CHANNEL_OPENING:
                case SSH_CHANNEL_CONNECTING:
+               case SSH_CHANNEL_DYNAMIC:
                case SSH_CHANNEL_OPEN:
                case SSH_CHANNEL_X11_OPEN:
                case SSH_CHANNEL_INPUT_DRAINING:
This page took 0.144571 seconds and 4 git commands to generate.