summaryrefslogtreecommitdiff
path: root/usr/src/cmd/ssh/libssh/common/channels.c
diff options
context:
space:
mode:
authorjp161948 <none@none>2007-07-31 01:55:32 -0700
committerjp161948 <none@none>2007-07-31 01:55:32 -0700
commitd80e6060324407c507b56eec0b706abbe697757d (patch)
treeed42043f7372e91764f8d7a3b84815a8675b07a6 /usr/src/cmd/ssh/libssh/common/channels.c
parentc0f24e5b75f7cf29213fe54fa80ccfbeb20fffe1 (diff)
downloadillumos-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.c132
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;
}