aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authormilo <milo@r0ot.me>2010-09-29 17:45:04 +0200
committerAris Adamantiadis <aris@0xbadc0de.be>2010-10-02 22:51:35 +0200
commit26d40b5354d6760472127f2c16045fbbb2f12fee (patch)
treede30f65d560762a324734d48c70872fdc50fcaaa /src
parentc4356531f78fdcf2f3b6a9861f6129eac81990f8 (diff)
downloadlibssh-26d40b5354d6760472127f2c16045fbbb2f12fee.tar.gz
libssh-26d40b5354d6760472127f2c16045fbbb2f12fee.tar.xz
libssh-26d40b5354d6760472127f2c16045fbbb2f12fee.zip
Handle global requests and reverse forwarding
Diffstat (limited to 'src')
-rw-r--r--src/channels.c73
-rw-r--r--src/messages.c87
-rw-r--r--src/packet.c2
-rw-r--r--src/server.c58
4 files changed, 218 insertions, 2 deletions
diff --git a/src/channels.c b/src/channels.c
index 83d0102..b91db72 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -41,6 +41,9 @@
#include "libssh/session.h"
#include "libssh/misc.h"
#include "libssh/messages.h"
+#if WITH_SERVER
+#include "libssh/server.h"
+#endif
#define WINDOWBASE 128000
#define WINDOWLIMIT (WINDOWBASE/2)
@@ -2503,6 +2506,74 @@ int ssh_channel_select(ssh_channel *readchans, ssh_channel *writechans,
return 0;
}
-/** @} */
+#if WITH_SERVER
+/**
+ * @brief Open a TCP/IP reverse forwarding channel.
+ *
+ * @param[in] channel An allocated channel.
+ *
+ * @param[in] remotehost The remote host to connected (host name or IP).
+ *
+ * @param[in] remoteport The remote port.
+ *
+ * @param[in] sourcehost The source host (your local computer). It's optional
+ * and for logging purpose.
+ *
+ * @param[in] localport The source port (your local computer). It's optional
+ * and for logging purpose.
+ *
+ * @return SSH_OK on success, SSH_ERROR if an error occured.
+ *
+ * @warning This function does not bind the local port and does not automatically
+ * forward the content of a socket to the channel. You still have to
+ * use channel_read and channel_write for this.
+ */
+int ssh_channel_open_reverse_forward(ssh_channel channel, const char *remotehost,
+ int remoteport, const char *sourcehost, int localport) {
+ ssh_session session = channel->session;
+ ssh_buffer payload = NULL;
+ ssh_string str = NULL;
+ int rc = SSH_ERROR;
+
+ enter_function();
+
+ payload = ssh_buffer_new();
+ if (payload == NULL) {
+ goto error;
+ }
+ str = ssh_string_from_char(remotehost);
+ if (str == NULL) {
+ goto error;
+ }
+
+ if (buffer_add_ssh_string(payload, str) < 0 ||
+ buffer_add_u32(payload,htonl(remoteport)) < 0) {
+ goto error;
+ }
+
+ ssh_string_free(str);
+ str = ssh_string_from_char(sourcehost);
+ if (str == NULL) {
+ goto error;
+ }
+
+ if (buffer_add_ssh_string(payload, str) < 0 ||
+ buffer_add_u32(payload,htonl(localport)) < 0) {
+ goto error;
+ }
+
+ rc = channel_open(channel, "forwarded-tcpip", 64000, 32000, payload);
+
+error:
+ ssh_buffer_free(payload);
+ ssh_string_free(str);
+
+ leave_function();
+ return rc;
+}
+
+#endif
+
+/* @} */
/* vim: set ts=4 sw=4 et cindent: */
diff --git a/src/messages.c b/src/messages.c
index 027daf2..e1297c2 100644
--- a/src/messages.c
+++ b/src/messages.c
@@ -39,6 +39,9 @@
#include "libssh/keys.h"
#include "libssh/dh.h"
#include "libssh/messages.h"
+#if WITH_SERVER
+#include "libssh/server.h"
+#endif
/**
* @defgroup libssh_messages The SSH message functions
@@ -64,6 +67,85 @@ static ssh_message ssh_message_new(ssh_session session){
return msg;
}
+SSH_PACKET_CALLBACK(ssh_packet_global_request){
+ ssh_message msg = NULL;
+ ssh_string request_s=NULL;
+ char *request=NULL;
+ ssh_string bind_addr_s=NULL;
+ char *bind_addr=NULL;
+ uint32_t bind_port;
+ uint8_t want_reply;
+ (void)user;
+ (void)type;
+ (void)packet;
+
+ request_s = buffer_get_ssh_string(packet);
+ if (request_s != NULL) {
+ request = ssh_string_to_char(request_s);
+ ssh_string_free(request_s);
+ }
+
+ buffer_get_u8(packet, &want_reply);
+
+ ssh_log(session,SSH_LOG_PROTOCOL,"Received SSH_MSG_GLOBAL_REQUEST packet");
+
+ msg = ssh_message_new(session);
+ msg->type = SSH_REQUEST_GLOBAL;
+
+ if(!strcmp(request, "tcpip-forward")) {
+ bind_addr_s = buffer_get_ssh_string(packet);
+ if (bind_addr_s != NULL) {
+ bind_addr = ssh_string_to_char(bind_addr_s);
+ ssh_string_free(bind_addr_s);
+ }
+
+ buffer_get_u32(packet, &bind_port);
+ bind_port = ntohl(bind_port);
+
+ msg->global_request.type = SSH_GLOBAL_REQUEST_TCPIP_FORWARD;
+ msg->global_request.want_reply = want_reply;
+ msg->global_request.bind_address = bind_addr;
+ msg->global_request.bind_port = bind_port;
+
+ ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
+
+ if(ssh_callbacks_exists(session->callbacks, global_request_function)) {
+ ssh_log(session, SSH_LOG_PROTOCOL, "Calling callback for SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
+ session->callbacks->global_request_function(session, msg, session->callbacks->userdata);
+ } else {
+ ssh_message_reply_default(msg);
+ }
+ } else if(!strcmp(request, "cancel-tcpip-forward")) {
+ bind_addr_s = buffer_get_ssh_string(packet);
+ if (bind_addr_s != NULL) {
+ bind_addr = ssh_string_to_char(bind_addr_s);
+ ssh_string_free(bind_addr_s);
+ }
+ buffer_get_u32(packet, &bind_port);
+ bind_port = ntohl(bind_port);
+
+ msg->global_request.type = SSH_GLOBAL_REQUEST_CANCEL_TCPIP_FORWARD;
+ msg->global_request.want_reply = want_reply;
+ msg->global_request.bind_address = bind_addr;
+ msg->global_request.bind_port = bind_port;
+
+ ssh_log(session, SSH_LOG_PROTOCOL, "Received SSH_MSG_GLOBAL_REQUEST %s %d %s:%d", request, want_reply, bind_addr, bind_port);
+
+ if(ssh_callbacks_exists(session->callbacks, global_request_function)) {
+ session->callbacks->global_request_function(session, msg, session->callbacks->userdata);
+ } else {
+ ssh_message_reply_default(msg);
+ }
+ } else {
+ ssh_log(session, SSH_LOG_PROTOCOL, "UNKNOWN SSH_MSG_GLOBAL_REQUEST %s %d", request, want_reply);
+ }
+
+ SAFE_FREE(msg);
+ SAFE_FREE(request);
+ SAFE_FREE(bind_addr);
+ return SSH_PACKET_USED;
+}
+
SSH_PACKET_CALLBACK(ssh_packet_service_request){
ssh_string service = NULL;
char *service_c = NULL;
@@ -763,6 +845,8 @@ int ssh_message_subtype(ssh_message msg) {
return msg->channel_request_open.type;
case SSH_REQUEST_CHANNEL:
return msg->channel_request.type;
+ case SSH_REQUEST_GLOBAL:
+ return msg->global_request.type;
}
return -1;
@@ -798,6 +882,9 @@ void ssh_message_free(ssh_message msg){
case SSH_REQUEST_SERVICE:
SAFE_FREE(msg->service_request.service);
break;
+ case SSH_REQUEST_GLOBAL:
+ SAFE_FREE(msg->global_request.bind_address);
+ break;
}
ZERO_STRUCTP(msg);
SAFE_FREE(msg);
diff --git a/src/packet.c b/src/packet.c
index 6acb0f3..ed64578 100644
--- a/src/packet.c
+++ b/src/packet.c
@@ -85,7 +85,7 @@ ssh_packet_callback default_packet_handlers[]= {
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, // 62-79
- NULL, // SSH2_MSG_GLOBAL_REQUEST 80
+ ssh_packet_global_request, // SSH2_MSG_GLOBAL_REQUEST 80
ssh_request_success, // SSH2_MSG_REQUEST_SUCCESS 81
ssh_request_denied, // SSH2_MSG_REQUEST_FAILURE 82
NULL, NULL, NULL, NULL, NULL, NULL, NULL,// 83-89
diff --git a/src/server.c b/src/server.c
index ac5eb05..dcd4c9f 100644
--- a/src/server.c
+++ b/src/server.c
@@ -890,6 +890,54 @@ int ssh_message_service_reply_success(ssh_message msg) {
return packet_send(msg->session);
}
+int ssh_message_global_request_reply_success(ssh_message msg, uint16_t bound_port) {
+ ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Accepting a global request");
+
+ if (msg->global_request.want_reply) {
+ if (buffer_add_u8(msg->session->out_buffer
+ , SSH2_MSG_REQUEST_SUCCESS) < 0) {
+ goto error;
+ }
+
+ if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD
+ && msg->global_request.bind_port == 0) {
+ if (buffer_add_u32(msg->session->out_buffer, htonl(bound_port)) < 0) {
+ goto error;
+ }
+ }
+
+ return packet_send(msg->session);
+ }
+
+ if(msg->global_request.type == SSH_GLOBAL_REQUEST_TCPIP_FORWARD
+ && msg->global_request.bind_port == 0) {
+ ssh_log(msg->session, SSH_LOG_PACKET,
+ "The client doesn't want to know the remote port!");
+ }
+
+ return SSH_OK;
+error:
+ return SSH_ERROR;
+}
+
+static int ssh_message_global_request_reply_default(ssh_message msg) {
+ ssh_log(msg->session, SSH_LOG_FUNCTIONS, "Refusing a global request");
+
+ if (msg->global_request.want_reply) {
+ if (buffer_add_u8(msg->session->out_buffer
+ , SSH2_MSG_REQUEST_FAILURE) < 0) {
+ goto error;
+ }
+ return packet_send(msg->session);
+ }
+ ssh_log(msg->session, SSH_LOG_PACKET,
+ "The client doesn't want to know the request failed!");
+
+ return SSH_OK;
+error:
+ return SSH_ERROR;
+}
+
int ssh_message_reply_default(ssh_message msg) {
if (msg == NULL) {
return -1;
@@ -904,6 +952,8 @@ int ssh_message_reply_default(ssh_message msg) {
return ssh_message_channel_request_reply_default(msg);
case SSH_REQUEST_SERVICE:
return ssh_message_service_request_reply_default(msg);
+ case SSH_REQUEST_GLOBAL:
+ return ssh_message_global_request_reply_default(msg);
default:
ssh_log(msg->session, SSH_LOG_PACKET,
"Don't know what to default reply to %d type",
@@ -1063,6 +1113,14 @@ char *ssh_message_channel_request_subsystem(ssh_message msg){
return msg->channel_request.subsystem;
}
+char *ssh_message_global_request_address(ssh_message msg){
+ return msg->global_request.bind_address;
+}
+
+int ssh_message_global_request_port(ssh_message msg){
+ return msg->global_request.bind_port;
+}
+
/** @brief defines the SSH_MESSAGE callback
* @param session the current ssh session
* @param[in] ssh_message_callback_ a function pointer to a callback taking the