2009-03-27 20:20:48 +00:00
|
|
|
/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
|
2010-05-05 15:41:19 +07:00
|
|
|
* Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net>
|
2014-03-16 20:02:37 +01:00
|
|
|
* Copyright (c) 2008-2014 by Daniel Stenberg
|
2008-12-16 15:32:20 +00:00
|
|
|
*
|
2004-12-07 21:17:20 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms,
|
|
|
|
* with or without modification, are permitted provided
|
|
|
|
* that the following conditions are met:
|
|
|
|
*
|
|
|
|
* Redistributions of source code must retain the above
|
|
|
|
* copyright notice, this list of conditions and the
|
2005-06-23 05:55:01 +00:00
|
|
|
* following disclaimer.
|
2004-12-07 21:17:20 +00:00
|
|
|
*
|
|
|
|
* Redistributions in binary form must reproduce the above
|
|
|
|
* copyright notice, this list of conditions and the following
|
|
|
|
* disclaimer in the documentation and/or other materials
|
2005-06-23 05:55:01 +00:00
|
|
|
* provided with the distribution.
|
2004-12-07 21:17:20 +00:00
|
|
|
*
|
|
|
|
* Neither the name of the copyright holder nor the names
|
2005-06-23 05:55:01 +00:00
|
|
|
* of any other contributors may be used to endorse or
|
|
|
|
* promote products derived from this software without
|
|
|
|
* specific prior written permission.
|
2004-12-07 21:17:20 +00:00
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
|
|
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
|
|
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
|
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
|
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
|
|
|
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
|
|
* OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "libssh2_priv.h"
|
2007-04-12 22:20:18 +00:00
|
|
|
#ifdef HAVE_UNISTD_H
|
2004-12-07 21:17:20 +00:00
|
|
|
#include <unistd.h>
|
2005-01-03 22:46:15 +00:00
|
|
|
#endif
|
2007-04-12 22:20:18 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#ifdef HAVE_INTTYPES_H
|
2007-02-02 16:21:20 +00:00
|
|
|
#include <inttypes.h>
|
2007-04-12 22:20:18 +00:00
|
|
|
#endif
|
2009-05-24 23:44:23 +02:00
|
|
|
#include <assert.h>
|
2007-02-02 16:21:20 +00:00
|
|
|
|
2009-03-26 15:41:14 +00:00
|
|
|
#include "channel.h"
|
|
|
|
#include "transport.h"
|
2010-04-17 13:18:15 +02:00
|
|
|
#include "packet.h"
|
2010-04-24 20:21:22 +02:00
|
|
|
#include "session.h"
|
2007-02-07 21:39:17 +00:00
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
/*
|
|
|
|
* _libssh2_channel_nextid
|
|
|
|
*
|
2004-12-07 21:17:20 +00:00
|
|
|
* Determine the next channel ID we can use at our end
|
|
|
|
*/
|
2010-04-17 13:27:17 +02:00
|
|
|
uint32_t
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_channel_nextid(LIBSSH2_SESSION * session)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2010-04-17 13:27:17 +02:00
|
|
|
uint32_t id = session->next_channel;
|
2007-05-28 17:56:08 +00:00
|
|
|
LIBSSH2_CHANNEL *channel;
|
|
|
|
|
2009-08-20 00:56:05 +02:00
|
|
|
channel = _libssh2_list_first(&session->channels);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
|
|
|
while (channel) {
|
|
|
|
if (channel->local.id > id) {
|
|
|
|
id = channel->local.id;
|
|
|
|
}
|
2009-08-20 00:56:05 +02:00
|
|
|
channel = _libssh2_list_next(&channel->node);
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2008-12-22 22:10:47 +00:00
|
|
|
/* This is a shortcut to avoid waiting for close packets on channels we've
|
|
|
|
* forgotten about, This *could* be a problem if we request and close 4
|
|
|
|
* billion or so channels in too rapid succession for the remote end to
|
|
|
|
* respond, but the worst case scenario is that some data meant for
|
|
|
|
* another channel Gets picked up by the new one.... Pretty unlikely all
|
|
|
|
* told...
|
2007-05-28 17:56:08 +00:00
|
|
|
*/
|
|
|
|
session->next_channel = id + 1;
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN, "Allocated new channel ID#%lu",
|
2007-08-06 20:48:04 +00:00
|
|
|
id);
|
2007-05-28 17:56:08 +00:00
|
|
|
return id;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
/*
|
|
|
|
* _libssh2_channel_locate
|
|
|
|
*
|
2004-12-07 21:17:20 +00:00
|
|
|
* Locate a channel pointer by number
|
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
LIBSSH2_CHANNEL *
|
2010-04-17 13:27:17 +02:00
|
|
|
_libssh2_channel_locate(LIBSSH2_SESSION *session, uint32_t channel_id)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2009-05-12 09:33:22 +00:00
|
|
|
LIBSSH2_CHANNEL *channel;
|
2009-08-19 14:33:13 +02:00
|
|
|
LIBSSH2_LISTENER *l;
|
2009-05-12 09:33:22 +00:00
|
|
|
|
2009-08-20 00:56:05 +02:00
|
|
|
for(channel = _libssh2_list_first(&session->channels);
|
|
|
|
channel;
|
|
|
|
channel = _libssh2_list_next(&channel->node)) {
|
2009-05-12 09:33:22 +00:00
|
|
|
if (channel->local.id == channel_id)
|
2007-05-28 17:56:08 +00:00
|
|
|
return channel;
|
2009-05-12 09:33:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* We didn't find the channel in the session, let's then check its
|
2009-08-20 00:56:05 +02:00
|
|
|
listeners since each listener may have its own set of pending channels
|
|
|
|
*/
|
2009-08-19 14:33:13 +02:00
|
|
|
for(l = _libssh2_list_first(&session->listeners); l;
|
|
|
|
l = _libssh2_list_next(&l->node)) {
|
2009-08-20 00:56:05 +02:00
|
|
|
for(channel = _libssh2_list_first(&l->queue);
|
|
|
|
channel;
|
|
|
|
channel = _libssh2_list_next(&channel->node)) {
|
2009-05-12 09:33:22 +00:00
|
|
|
if (channel->local.id == channel_id)
|
|
|
|
return channel;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
/*
|
2009-03-29 22:09:29 +00:00
|
|
|
* _libssh2_channel_open
|
2009-03-17 13:48:35 +00:00
|
|
|
*
|
2004-12-07 21:17:20 +00:00
|
|
|
* Establish a generic session channel
|
|
|
|
*/
|
2009-03-29 22:09:29 +00:00
|
|
|
LIBSSH2_CHANNEL *
|
|
|
|
_libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
|
2010-04-17 13:27:17 +02:00
|
|
|
uint32_t channel_type_len,
|
|
|
|
uint32_t window_size,
|
|
|
|
uint32_t packet_size,
|
2010-10-23 00:11:59 +02:00
|
|
|
const unsigned char *message,
|
|
|
|
size_t message_len)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
static const unsigned char reply_codes[3] = {
|
|
|
|
SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
|
|
|
|
SSH_MSG_CHANNEL_OPEN_FAILURE,
|
|
|
|
0
|
|
|
|
};
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned char *s;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (session->open_state == libssh2_NB_state_idle) {
|
|
|
|
session->open_channel = NULL;
|
|
|
|
session->open_packet = NULL;
|
|
|
|
session->open_data = NULL;
|
2008-12-22 22:10:47 +00:00
|
|
|
/* 17 = packet_type(1) + channel_type_len(4) + sender_channel(4) +
|
|
|
|
* window_size(4) + packet_size(4) */
|
2010-10-23 00:11:59 +02:00
|
|
|
session->open_packet_len = channel_type_len + 17;
|
2009-03-17 13:48:35 +00:00
|
|
|
session->open_local_channel = _libssh2_channel_nextid(session);
|
2007-06-06 12:34:06 +00:00
|
|
|
|
|
|
|
/* Zero the whole thing out */
|
2007-08-06 20:48:04 +00:00
|
|
|
memset(&session->open_packet_requirev_state, 0,
|
|
|
|
sizeof(session->open_packet_requirev_state));
|
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2007-08-06 20:48:04 +00:00
|
|
|
"Opening Channel - win %d pack %d", window_size,
|
|
|
|
packet_size);
|
|
|
|
session->open_channel =
|
2014-12-22 15:59:21 +01:00
|
|
|
LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
2007-06-06 12:34:06 +00:00
|
|
|
if (!session->open_channel) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate space for channel data");
|
2007-06-06 12:34:06 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
session->open_channel->channel_type_len = channel_type_len;
|
2007-08-06 20:48:04 +00:00
|
|
|
session->open_channel->channel_type =
|
|
|
|
LIBSSH2_ALLOC(session, channel_type_len);
|
2007-06-06 12:34:06 +00:00
|
|
|
if (!session->open_channel->channel_type) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Failed allocating memory for channel type name");
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->open_channel);
|
|
|
|
session->open_channel = NULL;
|
|
|
|
return NULL;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
memcpy(session->open_channel->channel_type, channel_type,
|
|
|
|
channel_type_len);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* REMEMBER: local as in locally sourced */
|
2007-08-06 20:48:04 +00:00
|
|
|
session->open_channel->local.id = session->open_local_channel;
|
|
|
|
session->open_channel->remote.window_size = window_size;
|
|
|
|
session->open_channel->remote.window_size_initial = window_size;
|
|
|
|
session->open_channel->remote.packet_size = packet_size;
|
2009-08-20 00:56:05 +02:00
|
|
|
session->open_channel->session = session;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2009-08-20 00:56:05 +02:00
|
|
|
_libssh2_list_add(&session->channels,
|
|
|
|
&session->open_channel->node);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
s = session->open_packet =
|
|
|
|
LIBSSH2_ALLOC(session, session->open_packet_len);
|
2007-06-06 12:34:06 +00:00
|
|
|
if (!session->open_packet) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate temporary space for packet");
|
2007-06-06 12:34:06 +00:00
|
|
|
goto channel_error;
|
|
|
|
}
|
|
|
|
*(s++) = SSH_MSG_CHANNEL_OPEN;
|
2010-04-17 13:18:15 +02:00
|
|
|
_libssh2_store_str(&s, channel_type, channel_type_len);
|
|
|
|
_libssh2_store_u32(&s, session->open_local_channel);
|
|
|
|
_libssh2_store_u32(&s, window_size);
|
|
|
|
_libssh2_store_u32(&s, packet_size);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2010-10-23 00:11:59 +02:00
|
|
|
/* Do not copy the message */
|
2007-06-06 12:34:06 +00:00
|
|
|
|
|
|
|
session->open_state = libssh2_NB_state_created;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->open_state == libssh2_NB_state_created) {
|
2010-10-23 00:11:59 +02:00
|
|
|
rc = _libssh2_transport_send(session,
|
|
|
|
session->open_packet,
|
|
|
|
session->open_packet_len,
|
|
|
|
message, message_len);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
2010-10-07 11:16:49 +02:00
|
|
|
_libssh2_error(session, rc,
|
2010-04-16 00:18:51 +02:00
|
|
|
"Would block sending channel-open request");
|
2007-06-06 12:34:06 +00:00
|
|
|
return NULL;
|
2010-10-07 11:16:49 +02:00
|
|
|
}
|
|
|
|
else if (rc) {
|
|
|
|
_libssh2_error(session, rc,
|
2010-04-16 00:18:51 +02:00
|
|
|
"Unable to send channel-open request");
|
2007-06-06 12:34:06 +00:00
|
|
|
goto channel_error;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->open_state = libssh2_NB_state_sent;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->open_state == libssh2_NB_state_sent) {
|
2009-03-17 13:48:35 +00:00
|
|
|
rc = _libssh2_packet_requirev(session, reply_codes,
|
|
|
|
&session->open_data,
|
|
|
|
&session->open_data_len, 1,
|
|
|
|
session->open_packet + 5 +
|
|
|
|
channel_type_len, 4,
|
|
|
|
&session->open_packet_requirev_state);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
2007-06-06 12:34:06 +00:00
|
|
|
return NULL;
|
2007-08-06 20:48:04 +00:00
|
|
|
} else if (rc) {
|
2007-06-06 12:34:06 +00:00
|
|
|
goto channel_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_CONFIRMATION) {
|
2007-08-06 20:48:04 +00:00
|
|
|
session->open_channel->remote.id =
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_ntohu32(session->open_data + 5);
|
2007-08-06 20:48:04 +00:00
|
|
|
session->open_channel->local.window_size =
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_ntohu32(session->open_data + 9);
|
2007-08-06 20:48:04 +00:00
|
|
|
session->open_channel->local.window_size_initial =
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_ntohu32(session->open_data + 9);
|
2007-08-06 20:48:04 +00:00
|
|
|
session->open_channel->local.packet_size =
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_ntohu32(session->open_data + 13);
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2008-12-22 22:10:47 +00:00
|
|
|
"Connection Established - ID: %lu/%lu win: %lu/%lu"
|
|
|
|
" pack: %lu/%lu",
|
2007-08-06 20:48:04 +00:00
|
|
|
session->open_channel->local.id,
|
|
|
|
session->open_channel->remote.id,
|
|
|
|
session->open_channel->local.window_size,
|
|
|
|
session->open_channel->remote.window_size,
|
|
|
|
session->open_channel->local.packet_size,
|
|
|
|
session->open_channel->remote.packet_size);
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->open_packet);
|
|
|
|
session->open_packet = NULL;
|
|
|
|
LIBSSH2_FREE(session, session->open_data);
|
|
|
|
session->open_data = NULL;
|
|
|
|
|
|
|
|
session->open_state = libssh2_NB_state_idle;
|
|
|
|
return session->open_channel;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (session->open_data[0] == SSH_MSG_CHANNEL_OPEN_FAILURE) {
|
2015-04-28 10:47:23 +02:00
|
|
|
unsigned int reason_code = _libssh2_ntohu32(session->open_data + 5);
|
|
|
|
switch (reason_code) {
|
|
|
|
case SSH_OPEN_ADMINISTRATIVELY_PROHIBITED:
|
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
|
|
|
|
"Channel open failure (admininstratively prohibited)");
|
|
|
|
break;
|
|
|
|
case SSH_OPEN_CONNECT_FAILED:
|
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
|
|
|
|
"Channel open failure (connect failed)");
|
|
|
|
break;
|
|
|
|
case SSH_OPEN_UNKNOWN_CHANNELTYPE:
|
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
|
|
|
|
"Channel open failure (unknown channel type)");
|
|
|
|
break;
|
|
|
|
case SSH_OPEN_RESOURCE_SHORTAGE:
|
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
|
|
|
|
"Channel open failure (resource shortage)");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE,
|
|
|
|
"Channel open failure");
|
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
channel_error:
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->open_data) {
|
|
|
|
LIBSSH2_FREE(session, session->open_data);
|
|
|
|
session->open_data = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->open_packet) {
|
|
|
|
LIBSSH2_FREE(session, session->open_packet);
|
|
|
|
session->open_packet = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->open_channel) {
|
2007-05-28 17:56:08 +00:00
|
|
|
unsigned char channel_id[4];
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->open_channel->channel_type);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2009-08-20 00:56:05 +02:00
|
|
|
_libssh2_list_remove(&session->open_channel->node);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
|
|
|
/* Clear out packets meant for this channel */
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_htonu32(channel_id, session->open_channel->local.id);
|
|
|
|
while ((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA,
|
|
|
|
&session->open_data,
|
|
|
|
&session->open_data_len, 1,
|
2009-03-23 12:43:59 +00:00
|
|
|
channel_id, 4) >= 0)
|
2007-08-06 20:48:04 +00:00
|
|
|
||
|
2009-03-17 13:48:35 +00:00
|
|
|
(_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA,
|
|
|
|
&session->open_data,
|
|
|
|
&session->open_data_len, 1,
|
2009-03-23 12:43:59 +00:00
|
|
|
channel_id, 4) >= 0)) {
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->open_data);
|
|
|
|
session->open_data = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->open_channel);
|
|
|
|
session->open_channel = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->open_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return NULL;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-26 15:41:14 +00:00
|
|
|
/*
|
|
|
|
* libssh2_channel_open_ex
|
|
|
|
*
|
|
|
|
* Establish a generic session channel
|
|
|
|
*/
|
|
|
|
LIBSSH2_API LIBSSH2_CHANNEL *
|
|
|
|
libssh2_channel_open_ex(LIBSSH2_SESSION *session, const char *type,
|
|
|
|
unsigned int type_len,
|
|
|
|
unsigned int window_size, unsigned int packet_size,
|
|
|
|
const char *msg, unsigned int msg_len)
|
|
|
|
{
|
|
|
|
LIBSSH2_CHANNEL *ptr;
|
2010-06-11 13:05:55 +02:00
|
|
|
|
|
|
|
if(!session)
|
|
|
|
return NULL;
|
|
|
|
|
2009-03-29 22:09:29 +00:00
|
|
|
BLOCK_ADJUST_ERRNO(ptr, session,
|
|
|
|
_libssh2_channel_open(session, type, type_len,
|
|
|
|
window_size, packet_size,
|
2010-10-23 00:11:59 +02:00
|
|
|
(unsigned char *)msg,
|
|
|
|
msg_len));
|
2009-03-26 15:41:14 +00:00
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
/*
|
|
|
|
* libssh2_channel_direct_tcpip_ex
|
|
|
|
*
|
2004-12-07 21:17:20 +00:00
|
|
|
* Tunnel TCP/IP connect through the SSH session to direct host/port
|
|
|
|
*/
|
2009-03-26 15:41:14 +00:00
|
|
|
static LIBSSH2_CHANNEL *
|
|
|
|
channel_direct_tcpip(LIBSSH2_SESSION * session, const char *host,
|
|
|
|
int port, const char *shost, int sport)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
LIBSSH2_CHANNEL *channel;
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned char *s;
|
|
|
|
|
|
|
|
if (session->direct_state == libssh2_NB_state_idle) {
|
|
|
|
session->direct_host_len = strlen(host);
|
|
|
|
session->direct_shost_len = strlen(shost);
|
|
|
|
/* host_len(4) + port(4) + shost_len(4) + sport(4) */
|
2007-08-06 20:48:04 +00:00
|
|
|
session->direct_message_len =
|
|
|
|
session->direct_host_len + session->direct_shost_len + 16;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2007-08-06 20:48:04 +00:00
|
|
|
"Requesting direct-tcpip session to from %s:%d to %s:%d",
|
2007-06-06 12:34:06 +00:00
|
|
|
shost, sport, host, port);
|
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
s = session->direct_message =
|
|
|
|
LIBSSH2_ALLOC(session, session->direct_message_len);
|
2007-06-06 12:34:06 +00:00
|
|
|
if (!session->direct_message) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate memory for direct-tcpip connection");
|
2007-06-06 12:34:06 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2010-04-17 13:18:15 +02:00
|
|
|
_libssh2_store_str(&s, host, session->direct_host_len);
|
|
|
|
_libssh2_store_u32(&s, port);
|
|
|
|
_libssh2_store_str(&s, shost, session->direct_shost_len);
|
|
|
|
_libssh2_store_u32(&s, sport);
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
channel =
|
2010-04-24 21:14:16 +02:00
|
|
|
_libssh2_channel_open(session, "direct-tcpip",
|
|
|
|
sizeof("direct-tcpip") - 1,
|
|
|
|
LIBSSH2_CHANNEL_WINDOW_DEFAULT,
|
|
|
|
LIBSSH2_CHANNEL_PACKET_DEFAULT,
|
2010-10-23 00:11:59 +02:00
|
|
|
session->direct_message,
|
2010-04-24 21:14:16 +02:00
|
|
|
session->direct_message_len);
|
2009-02-20 16:14:45 +00:00
|
|
|
|
2009-08-24 22:44:22 +02:00
|
|
|
if (!channel &&
|
|
|
|
libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN) {
|
|
|
|
/* The error code is still set to LIBSSH2_ERROR_EAGAIN, set our state
|
|
|
|
to created to avoid re-creating the package on next invoke */
|
|
|
|
session->direct_state = libssh2_NB_state_created;
|
|
|
|
return NULL;
|
2007-06-06 12:34:06 +00:00
|
|
|
}
|
2010-04-24 21:14:16 +02:00
|
|
|
/* by default we set (keep?) idle state... */
|
|
|
|
session->direct_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->direct_message);
|
|
|
|
session->direct_message = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
|
|
|
return channel;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
/*
|
2009-03-26 15:41:14 +00:00
|
|
|
* libssh2_channel_direct_tcpip_ex
|
|
|
|
*
|
|
|
|
* Tunnel TCP/IP connect through the SSH session to direct host/port
|
|
|
|
*/
|
|
|
|
LIBSSH2_API LIBSSH2_CHANNEL *
|
2010-06-11 13:05:55 +02:00
|
|
|
libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host,
|
2009-03-26 15:41:14 +00:00
|
|
|
int port, const char *shost, int sport)
|
|
|
|
{
|
|
|
|
LIBSSH2_CHANNEL *ptr;
|
2010-06-11 13:05:55 +02:00
|
|
|
|
|
|
|
if(!session)
|
|
|
|
return NULL;
|
|
|
|
|
2009-03-26 15:41:14 +00:00
|
|
|
BLOCK_ADJUST_ERRNO(ptr, session,
|
|
|
|
channel_direct_tcpip(session, host, port, shost, sport));
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* channel_forward_listen
|
2009-03-17 13:48:35 +00:00
|
|
|
*
|
2004-12-29 19:26:28 +00:00
|
|
|
* Bind a port on the remote host and listen for connections
|
|
|
|
*/
|
2009-03-26 15:41:14 +00:00
|
|
|
static LIBSSH2_LISTENER *
|
|
|
|
channel_forward_listen(LIBSSH2_SESSION * session, const char *host,
|
|
|
|
int port, int *bound_port, int queue_maxsize)
|
2004-12-29 19:26:28 +00:00
|
|
|
{
|
2010-04-24 13:23:24 +02:00
|
|
|
unsigned char *s;
|
2007-08-06 20:48:04 +00:00
|
|
|
static const unsigned char reply_codes[3] =
|
|
|
|
{ SSH_MSG_REQUEST_SUCCESS, SSH_MSG_REQUEST_FAILURE, 0 };
|
2007-06-06 12:34:06 +00:00
|
|
|
int rc;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2010-10-23 00:11:59 +02:00
|
|
|
if(!host)
|
|
|
|
host = "0.0.0.0";
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->fwdLstn_state == libssh2_NB_state_idle) {
|
2010-10-23 00:11:59 +02:00
|
|
|
session->fwdLstn_host_len = strlen(host);
|
2008-12-22 22:10:47 +00:00
|
|
|
/* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4)
|
|
|
|
+ port(4) */
|
2007-08-06 20:48:04 +00:00
|
|
|
session->fwdLstn_packet_len =
|
|
|
|
session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* Zero the whole thing out */
|
2007-08-06 20:48:04 +00:00
|
|
|
memset(&session->fwdLstn_packet_requirev_state, 0,
|
|
|
|
sizeof(session->fwdLstn_packet_requirev_state));
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2007-08-06 20:48:04 +00:00
|
|
|
"Requesting tcpip-forward session for %s:%d", host,
|
|
|
|
port);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
s = session->fwdLstn_packet =
|
|
|
|
LIBSSH2_ALLOC(session, session->fwdLstn_packet_len);
|
2007-06-06 12:34:06 +00:00
|
|
|
if (!session->fwdLstn_packet) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
2014-02-18 23:46:25 +01:00
|
|
|
"Unable to allocate memory for setenv packet");
|
2007-06-06 12:34:06 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
*(s++) = SSH_MSG_GLOBAL_REQUEST;
|
2010-04-17 13:18:15 +02:00
|
|
|
_libssh2_store_str(&s, "tcpip-forward", sizeof("tcpip-forward") - 1);
|
2007-08-06 20:48:04 +00:00
|
|
|
*(s++) = 0x01; /* want_reply */
|
|
|
|
|
2010-10-23 00:11:59 +02:00
|
|
|
_libssh2_store_str(&s, host, session->fwdLstn_host_len);
|
2010-04-17 13:18:15 +02:00
|
|
|
_libssh2_store_u32(&s, port);
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->fwdLstn_state = libssh2_NB_state_created;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->fwdLstn_state == libssh2_NB_state_created) {
|
2010-10-23 00:11:59 +02:00
|
|
|
rc = _libssh2_transport_send(session,
|
|
|
|
session->fwdLstn_packet,
|
|
|
|
session->fwdLstn_packet_len,
|
|
|
|
NULL, 0);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
|
|
|
|
"Would block sending global-request packet for "
|
|
|
|
"forward listen request");
|
2007-05-28 17:56:08 +00:00
|
|
|
return NULL;
|
2010-10-07 11:16:49 +02:00
|
|
|
}
|
|
|
|
else if (rc) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
|
|
|
"Unable to send global-request packet for forward "
|
|
|
|
"listen request");
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->fwdLstn_packet);
|
|
|
|
session->fwdLstn_packet = NULL;
|
|
|
|
session->fwdLstn_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, session->fwdLstn_packet);
|
|
|
|
session->fwdLstn_packet = NULL;
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->fwdLstn_state = libssh2_NB_state_sent;
|
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->fwdLstn_state == libssh2_NB_state_sent) {
|
2010-04-24 13:23:24 +02:00
|
|
|
unsigned char *data;
|
|
|
|
size_t data_len;
|
2009-03-17 13:48:35 +00:00
|
|
|
rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len,
|
|
|
|
0, NULL, 0,
|
|
|
|
&session->fwdLstn_packet_requirev_state);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_EAGAIN, "Would block");
|
2007-06-06 12:34:06 +00:00
|
|
|
return NULL;
|
2007-08-06 20:48:04 +00:00
|
|
|
} else if (rc) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_PROTO, "Unknown");
|
2007-06-06 12:34:06 +00:00
|
|
|
session->fwdLstn_state = libssh2_NB_state_idle;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (data[0] == SSH_MSG_REQUEST_SUCCESS) {
|
|
|
|
LIBSSH2_LISTENER *listener;
|
|
|
|
|
2014-12-22 15:59:21 +01:00
|
|
|
listener = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_LISTENER));
|
2010-04-24 13:30:32 +02:00
|
|
|
if (!listener)
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate memory for listener queue");
|
2010-04-24 13:30:32 +02:00
|
|
|
else {
|
|
|
|
listener->host =
|
|
|
|
LIBSSH2_ALLOC(session, session->fwdLstn_host_len + 1);
|
|
|
|
if (!listener->host) {
|
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|