diff options
author | jp161948 <none@none> | 2007-07-31 01:55:32 -0700 |
---|---|---|
committer | jp161948 <none@none> | 2007-07-31 01:55:32 -0700 |
commit | d80e6060324407c507b56eec0b706abbe697757d (patch) | |
tree | ed42043f7372e91764f8d7a3b84815a8675b07a6 /usr/src/cmd/ssh/libssh/common/channels.c | |
parent | c0f24e5b75f7cf29213fe54fa80ccfbeb20fffe1 (diff) | |
download | illumos-gate-d80e6060324407c507b56eec0b706abbe697757d.tar.gz |
PSARC/2007/034 ssh/sshd resync with OpenSSH
6459966 add SOCKS version 5 for dynamic forwarding in ssh(1)
Diffstat (limited to 'usr/src/cmd/ssh/libssh/common/channels.c')
-rw-r--r-- | usr/src/cmd/ssh/libssh/common/channels.c | 132 |
1 files changed, 130 insertions, 2 deletions
diff --git a/usr/src/cmd/ssh/libssh/common/channels.c b/usr/src/cmd/ssh/libssh/common/channels.c index 61febdd9e4..5980c6ca89 100644 --- a/usr/src/cmd/ssh/libssh/common/channels.c +++ b/usr/src/cmd/ssh/libssh/common/channels.c @@ -1,5 +1,5 @@ /* - * Copyright 2003 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* @@ -60,6 +60,7 @@ RCSID("$OpenBSD: channels.c,v 1.183 2002/09/17 07:47:02 itojun Exp $"); #include "key.h" #include "authfd.h" #include "pathnames.h" +#include "bufaux.h" /* -- channel core */ @@ -960,6 +961,128 @@ channel_decode_socks4(Channel *c, fd_set * readset, fd_set * writeset) return 1; } +/* try to decode a socks5 header */ +#define SSH_SOCKS5_AUTHDONE 0x1000 +#define SSH_SOCKS5_NOAUTH 0x00 +#define SSH_SOCKS5_IPV4 0x01 +#define SSH_SOCKS5_DOMAIN 0x03 +#define SSH_SOCKS5_IPV6 0x04 +#define SSH_SOCKS5_CONNECT 0x01 +#define SSH_SOCKS5_SUCCESS 0x00 + +/* ARGSUSED */ +static int +channel_decode_socks5(Channel *c, fd_set *readset, fd_set *writeset) +{ + struct { + u_int8_t version; + u_int8_t command; + u_int8_t reserved; + u_int8_t atyp; + } s5_req, s5_rsp; + u_int16_t dest_port; + u_char *p, dest_addr[255+1]; + u_int have, need, i, found, nmethods, addrlen; + struct in_addr bnd_addr; + int af; + + debug2("channel %d: decode socks5", c->self); + p = buffer_ptr(&c->input); + if (p[0] != 0x05) + return -1; + have = buffer_len(&c->input); + if (!(c->flags & SSH_SOCKS5_AUTHDONE)) { + /* format: ver | nmethods | methods */ + if (have < 2) + return 0; + nmethods = p[1]; + if (have < nmethods + 2) + return 0; + /* look for method: "NO AUTHENTICATION REQUIRED" */ + for (found = 0, i = 2 ; i < nmethods + 2; i++) { + if (p[i] == SSH_SOCKS5_NOAUTH) { + found = 1; + break; + } + } + if (!found) { + error("channel %d: socks5 authentication methods not implemented", + c->self); + error("channel %d: forwarding failed: " + "SSH_SOCKS5_NOAUTH method not found", c->self); + return -1; + } + buffer_consume(&c->input, nmethods + 2); + buffer_put_char(&c->output, 0x05); /* version */ + buffer_put_char(&c->output, SSH_SOCKS5_NOAUTH); /* method */ + FD_SET(c->sock, writeset); + c->flags |= SSH_SOCKS5_AUTHDONE; + debug2("channel %d: socks5 auth done", c->self); + return 0; /* need more */ + } + debug2("channel %d: socks5 post auth", c->self); + if (have < sizeof(s5_req)+1) + return 0; /* need more */ + memcpy(&s5_req, p, sizeof(s5_req)); + if (s5_req.version != 0x05 || + s5_req.command != SSH_SOCKS5_CONNECT || + s5_req.reserved != 0x00) { + error("channel %d: forwarding failed: " + "only socks5 connect is supported", c->self); + return -1; + } + switch (s5_req.atyp){ + case SSH_SOCKS5_IPV4: + addrlen = 4; + af = AF_INET; + break; + case SSH_SOCKS5_DOMAIN: + addrlen = p[sizeof(s5_req)]; + af = -1; + break; + case SSH_SOCKS5_IPV6: + addrlen = 16; + af = AF_INET6; + break; + default: + error("channel %d: forwarding failed: " + "bad socks5 atyp %d", c->self, s5_req.atyp); + return -1; + } + need = sizeof(s5_req) + addrlen + 2; + if (s5_req.atyp == SSH_SOCKS5_DOMAIN) + need++; + if (have < need) + return 0; + buffer_consume(&c->input, sizeof(s5_req)); + if (s5_req.atyp == SSH_SOCKS5_DOMAIN) + buffer_consume(&c->input, 1); /* host string length */ + buffer_get(&c->input, (char *)&dest_addr, addrlen); + buffer_get(&c->input, (char *)&dest_port, 2); + dest_addr[addrlen] = '\0'; + if (s5_req.atyp == SSH_SOCKS5_DOMAIN) + strlcpy(c->path, (char *)dest_addr, sizeof(c->path)); + else if (inet_ntop(af, dest_addr, c->path, sizeof(c->path)) == NULL) + return -1; + c->host_port = ntohs(dest_port); + + debug2("channel %d: dynamic request: socks5 host %s port %u command %u", + c->self, c->path, c->host_port, s5_req.command); + + s5_rsp.version = 0x05; + s5_rsp.command = SSH_SOCKS5_SUCCESS; + s5_rsp.reserved = 0; /* ignored */ + s5_rsp.atyp = SSH_SOCKS5_IPV4; + bzero(&bnd_addr, sizeof(bnd_addr)); + bnd_addr.s_addr = htonl(INADDR_ANY); + dest_port = 0; /* ignored */ + + buffer_append(&c->output, &s5_rsp, sizeof(s5_rsp)); + buffer_append(&c->output, &bnd_addr, sizeof(struct in_addr)); + buffer_append(&c->output, &dest_port, sizeof(dest_port)); + return 1; +} + /* dynamic port forwarding */ static void channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) @@ -972,7 +1095,7 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) debug2("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 < 4) { + if (have < 3) { /* need more */ FD_SET(c->sock, readset); return; @@ -983,7 +1106,12 @@ channel_pre_dynamic(Channel *c, fd_set * readset, fd_set * writeset) case 0x04: ret = channel_decode_socks4(c, readset, writeset); break; + case 0x05: + ret = channel_decode_socks5(c, readset, writeset); + break; default: + error("channel %d: forwarding failed: unknown socks " + "version 0x%02X", c->self, p[0]); ret = -1; break; } |