2007-02-02 16:21:20 +00:00
|
|
|
/* Copyright (c) 2004-2007, Sara Golemon <sarag@libssh2.org>
|
2010-05-05 15:41:19 +07:00
|
|
|
* Copyright (c) 2005,2006 Mikhail Gusarov
|
2010-10-23 00:11:59 +02:00
|
|
|
* Copyright (c) 2009-2010 by Daniel Stenberg
|
2010-01-28 14:30:25 +01:00
|
|
|
* Copyright (c) 2010 Simon Josefsson
|
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
|
|
|
|
* following disclaimer.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* provided with the distribution.
|
|
|
|
*
|
|
|
|
* Neither the name of the copyright holder nor the names
|
|
|
|
* of any other contributors may be used to endorse or
|
|
|
|
* promote products derived from this software without
|
|
|
|
* specific prior written permission.
|
|
|
|
*
|
|
|
|
* 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"
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.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
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-04-12 22:20:18 +00:00
|
|
|
#ifdef HAVE_SYS_TIME_H
|
|
|
|
#include <sys/time.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_INTTYPES_H
|
|
|
|
#include <inttypes.h>
|
|
|
|
#endif
|
|
|
|
|
2005-03-21 21:26:08 +00:00
|
|
|
/* Needed for struct iovec on some platforms */
|
|
|
|
#ifdef HAVE_SYS_UIO_H
|
|
|
|
#include <sys/uio.h>
|
|
|
|
#endif
|
2004-12-29 19:26:28 +00:00
|
|
|
|
2007-02-02 16:21:20 +00:00
|
|
|
#include <sys/types.h>
|
2006-11-14 01:30:39 +00:00
|
|
|
|
2009-03-26 15:41:14 +00:00
|
|
|
#include "transport.h"
|
2009-08-24 23:24:35 +02:00
|
|
|
#include "channel.h"
|
2010-04-17 13:18:15 +02:00
|
|
|
#include "packet.h"
|
2009-03-26 15:41:14 +00:00
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
/*
|
|
|
|
* libssh2_packet_queue_listener
|
|
|
|
*
|
2004-12-29 19:26:28 +00:00
|
|
|
* Queue a connection request for a listener
|
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
static inline int
|
2009-03-17 13:48:35 +00:00
|
|
|
packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data,
|
|
|
|
unsigned long datalen,
|
2009-08-20 00:56:05 +02:00
|
|
|
packet_queue_listener_state_t *listen_state)
|
2004-12-29 19:26:28 +00:00
|
|
|
{
|
2007-06-06 12:34:06 +00:00
|
|
|
/*
|
|
|
|
* Look for a matching listener
|
|
|
|
*/
|
2007-05-28 17:56:08 +00:00
|
|
|
/* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
|
2007-06-06 12:34:06 +00:00
|
|
|
unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1);
|
|
|
|
unsigned char *p;
|
2010-11-10 13:06:39 +01:00
|
|
|
LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners);
|
2010-11-09 14:28:29 +01:00
|
|
|
char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED;
|
2007-06-06 12:34:06 +00:00
|
|
|
int rc;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
|
|
|
(void) datalen;
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (listen_state->state == libssh2_NB_state_idle) {
|
2010-04-28 08:47:30 +02:00
|
|
|
unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5;
|
2009-03-17 13:48:35 +00:00
|
|
|
listen_state->sender_channel = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
listen_state->initial_window_size = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
2009-03-17 13:48:35 +00:00
|
|
|
listen_state->packet_size = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
listen_state->host_len = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
|
|
|
listen_state->host = s;
|
|
|
|
s += listen_state->host_len;
|
2009-03-17 13:48:35 +00:00
|
|
|
listen_state->port = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
listen_state->shost_len = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
|
|
|
listen_state->shost = s;
|
|
|
|
s += listen_state->shost_len;
|
2009-03-17 13:48:35 +00:00
|
|
|
listen_state->sport = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2007-06-06 12:34:06 +00:00
|
|
|
"Remote received connection from %s:%ld to %s:%ld",
|
|
|
|
listen_state->shost, listen_state->sport,
|
|
|
|
listen_state->host, listen_state->port);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
listen_state->state = libssh2_NB_state_allocated;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (listen_state->state != libssh2_NB_state_sent) {
|
2010-11-10 13:06:39 +01:00
|
|
|
while (listn) {
|
|
|
|
if ((listn->port == (int) listen_state->port) &&
|
|
|
|
(strlen(listn->host) == listen_state->host_len) &&
|
|
|
|
(memcmp (listn->host, listen_state->host,
|
2009-08-20 00:56:05 +02:00
|
|
|
listen_state->host_len) == 0)) {
|
2007-06-06 12:34:06 +00:00
|
|
|
/* This is our listener */
|
2009-08-20 00:56:05 +02:00
|
|
|
LIBSSH2_CHANNEL *channel = NULL;
|
|
|
|
listen_state->channel = NULL;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (listen_state->state == libssh2_NB_state_allocated) {
|
2010-11-10 13:06:39 +01:00
|
|
|
if (listn->queue_maxsize &&
|
|
|
|
(listn->queue_maxsize <= listn->queue_size)) {
|
2007-06-06 12:34:06 +00:00
|
|
|
/* Queue is full */
|
2010-11-09 14:28:29 +01:00
|
|
|
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2007-06-06 12:34:06 +00:00
|
|
|
"Listener queue full, ignoring");
|
|
|
|
listen_state->state = libssh2_NB_state_sent;
|
|
|
|
break;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
|
|
|
if (!channel) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate a channel for "
|
|
|
|
"new connection");
|
2010-11-09 14:28:29 +01:00
|
|
|
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
|
2007-06-06 12:34:06 +00:00
|
|
|
listen_state->state = libssh2_NB_state_sent;
|
|
|
|
break;
|
|
|
|
}
|
2009-10-18 03:41:25 +02:00
|
|
|
listen_state->channel = channel;
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
channel->session = session;
|
|
|
|
channel->channel_type_len = sizeof("forwarded-tcpip") - 1;
|
|
|
|
channel->channel_type = LIBSSH2_ALLOC(session,
|
2007-08-06 20:48:04 +00:00
|
|
|
channel->
|
|
|
|
channel_type_len +
|
|
|
|
1);
|
2007-06-06 12:34:06 +00:00
|
|
|
if (!channel->channel_type) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"Unable to allocate a channel for new"
|
|
|
|
" connection");
|
2007-06-06 12:34:06 +00:00
|
|
|
LIBSSH2_FREE(session, channel);
|
2010-11-09 14:28:29 +01:00
|
|
|
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
|
2007-06-06 12:34:06 +00:00
|
|
|
listen_state->state = libssh2_NB_state_sent;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
memcpy(channel->channel_type, "forwarded-tcpip",
|
|
|
|
channel->channel_type_len + 1);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
channel->remote.id = listen_state->sender_channel;
|
2007-08-06 20:48:04 +00:00
|
|
|
channel->remote.window_size_initial =
|
|
|
|
LIBSSH2_CHANNEL_WINDOW_DEFAULT;
|
|
|
|
channel->remote.window_size =
|
|
|
|
LIBSSH2_CHANNEL_WINDOW_DEFAULT;
|
|
|
|
channel->remote.packet_size =
|
|
|
|
LIBSSH2_CHANNEL_PACKET_DEFAULT;
|
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
channel->local.id = _libssh2_channel_nextid(session);
|
2007-08-06 20:48:04 +00:00
|
|
|
channel->local.window_size_initial =
|
|
|
|
listen_state->initial_window_size;
|
|
|
|
channel->local.window_size =
|
|
|
|
listen_state->initial_window_size;
|
2007-06-06 12:34:06 +00:00
|
|
|
channel->local.packet_size = listen_state->packet_size;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2010-11-09 14:32:02 +01:00
|
|
|
"Connection queued: channel %lu/%lu "
|
|
|
|
"win %lu/%lu packet %lu/%lu",
|
2007-06-06 12:34:06 +00:00
|
|
|
channel->local.id, channel->remote.id,
|
|
|
|
channel->local.window_size,
|
|
|
|
channel->remote.window_size,
|
|
|
|
channel->local.packet_size,
|
|
|
|
channel->remote.packet_size);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
p = listen_state->packet;
|
|
|
|
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
|
2010-04-18 15:24:13 +02:00
|
|
|
_libssh2_store_u32(&p, channel->remote.id);
|
|
|
|
_libssh2_store_u32(&p, channel->local.id);
|
2010-11-09 14:32:02 +01:00
|
|
|
_libssh2_store_u32(&p,
|
|
|
|
channel->remote.window_size_initial);
|
2010-04-18 15:24:13 +02:00
|
|
|
_libssh2_store_u32(&p, channel->remote.packet_size);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
listen_state->state = libssh2_NB_state_created;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (listen_state->state == libssh2_NB_state_created) {
|
2010-10-23 00:11:59 +02:00
|
|
|
rc = _libssh2_transport_send(session, listen_state->packet,
|
|
|
|
17, NULL, 0);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN)
|
2009-08-25 00:54:47 +02:00
|
|
|
return rc;
|
2009-08-20 00:56:05 +02:00
|
|
|
else if (rc) {
|
2007-06-06 12:34:06 +00:00
|
|
|
listen_state->state = libssh2_NB_state_idle;
|
2010-04-16 00:18:51 +02:00
|
|
|
return _libssh2_error(session, rc,
|
|
|
|
"Unable to send channel "
|
|
|
|
"open confirmation");
|
2007-06-06 12:34:06 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* Link the channel into the end of the queue list */
|
2010-11-10 13:06:39 +01:00
|
|
|
_libssh2_list_add(&listn->queue,
|
2009-08-20 00:56:05 +02:00
|
|
|
&listen_state->channel->node);
|
2010-11-10 13:06:39 +01:00
|
|
|
listn->queue_size++;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
listen_state->state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 13:06:39 +01:00
|
|
|
listn = _libssh2_list_next(&listn->node);
|
2007-06-06 12:34:06 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
listen_state->state = libssh2_NB_state_sent;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* We're not listening to you */
|
2009-08-20 00:56:05 +02:00
|
|
|
p = listen_state->packet;
|
|
|
|
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
|
2010-04-18 15:24:13 +02:00
|
|
|
_libssh2_store_u32(&p, listen_state->sender_channel);
|
|
|
|
_libssh2_store_u32(&p, failure_code);
|
|
|
|
_libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1);
|
2009-08-20 00:56:05 +02:00
|
|
|
_libssh2_htonu32(p, 0);
|
|
|
|
|
2010-10-23 00:11:59 +02:00
|
|
|
rc = _libssh2_transport_send(session, listen_state->packet,
|
|
|
|
packet_len, NULL, 0);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
2009-08-25 00:54:47 +02:00
|
|
|
return rc;
|
2009-08-20 00:56:05 +02:00
|
|
|
} else if (rc) {
|
2007-06-06 12:34:06 +00:00
|
|
|
listen_state->state = libssh2_NB_state_idle;
|
2010-04-16 00:18:51 +02:00
|
|
|
return _libssh2_error(session, rc, "Unable to send open failure");
|
2010-03-03 23:04:05 +01:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
}
|
2009-08-20 00:56:05 +02:00
|
|
|
listen_state->state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
2007-06-06 12:34:06 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
/*
|
|
|
|
* packet_x11_open
|
|
|
|
*
|
2007-06-06 12:34:06 +00:00
|
|
|
* Accept a forwarded X11 connection
|
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
static inline int
|
2009-03-17 13:48:35 +00:00
|
|
|
packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data,
|
|
|
|
unsigned long datalen,
|
2009-08-20 00:56:05 +02:00
|
|
|
packet_x11_open_state_t *x11open_state)
|
2007-06-06 12:34:06 +00:00
|
|
|
{
|
2010-11-09 14:28:29 +01:00
|
|
|
int failure_code = SSH_OPEN_CONNECT_FAILED;
|
2007-06-06 12:34:06 +00:00
|
|
|
/* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */
|
|
|
|
unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1);
|
|
|
|
unsigned char *p;
|
2009-08-20 00:56:05 +02:00
|
|
|
LIBSSH2_CHANNEL *channel = x11open_state->channel;
|
2007-06-06 12:34:06 +00:00
|
|
|
int rc;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
|
|
|
(void) datalen;
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (x11open_state->state == libssh2_NB_state_idle) {
|
2010-04-28 08:48:50 +02:00
|
|
|
unsigned char *s = data + (sizeof("x11") - 1) + 5;
|
2009-03-17 13:48:35 +00:00
|
|
|
x11open_state->sender_channel = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
2009-03-17 13:48:35 +00:00
|
|
|
x11open_state->initial_window_size = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
2009-03-17 13:48:35 +00:00
|
|
|
x11open_state->packet_size = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
2009-03-17 13:48:35 +00:00
|
|
|
x11open_state->shost_len = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
s += 4;
|
|
|
|
x11open_state->shost = s;
|
|
|
|
s += x11open_state->shost_len;
|
2009-03-17 13:48:35 +00:00
|
|
|
x11open_state->sport = _libssh2_ntohu32(s);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2007-06-06 12:34:06 +00:00
|
|
|
"X11 Connection Received from %s:%ld on channel %lu",
|
|
|
|
x11open_state->shost, x11open_state->sport,
|
|
|
|
x11open_state->sender_channel);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
x11open_state->state = libssh2_NB_state_allocated;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->x11) {
|
|
|
|
if (x11open_state->state == libssh2_NB_state_allocated) {
|
2007-05-28 17:56:08 +00:00
|
|
|
channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL));
|
|
|
|
if (!channel) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
2010-11-09 14:32:02 +01:00
|
|
|
"allocate a channel for new connection");
|
2010-11-09 14:28:29 +01:00
|
|
|
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
|
2007-06-06 12:34:06 +00:00
|
|
|
goto x11_exit;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
memset(channel, 0, sizeof(LIBSSH2_CHANNEL));
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
channel->session = session;
|
2007-06-06 12:34:06 +00:00
|
|
|
channel->channel_type_len = sizeof("x11") - 1;
|
|
|
|
channel->channel_type = LIBSSH2_ALLOC(session,
|
2007-08-06 20:48:04 +00:00
|
|
|
channel->channel_type_len +
|
|
|
|
1);
|
2007-05-28 17:56:08 +00:00
|
|
|
if (!channel->channel_type) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
2010-11-09 14:32:02 +01:00
|
|
|
"allocate a channel for new connection");
|
2007-05-28 17:56:08 +00:00
|
|
|
LIBSSH2_FREE(session, channel);
|
2010-11-09 14:28:29 +01:00
|
|
|
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
|
2007-06-06 12:34:06 +00:00
|
|
|
goto x11_exit;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
memcpy(channel->channel_type, "x11",
|
|
|
|
channel->channel_type_len + 1);
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
channel->remote.id = x11open_state->sender_channel;
|
2007-08-06 20:48:04 +00:00
|
|
|
channel->remote.window_size_initial =
|
|
|
|
LIBSSH2_CHANNEL_WINDOW_DEFAULT;
|
2007-05-28 17:56:08 +00:00
|
|
|
channel->remote.window_size = LIBSSH2_CHANNEL_WINDOW_DEFAULT;
|
|
|
|
channel->remote.packet_size = LIBSSH2_CHANNEL_PACKET_DEFAULT;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
channel->local.id = _libssh2_channel_nextid(session);
|
2007-08-06 20:48:04 +00:00
|
|
|
channel->local.window_size_initial =
|
|
|
|
x11open_state->initial_window_size;
|
2007-06-06 12:34:06 +00:00
|
|
|
channel->local.window_size = x11open_state->initial_window_size;
|
|
|
|
channel->local.packet_size = x11open_state->packet_size;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2010-11-09 14:32:02 +01:00
|
|
|
"X11 Connection established: channel %lu/%lu "
|
|
|
|
"win %lu/%lu packet %lu/%lu",
|
2007-05-28 17:56:08 +00:00
|
|
|
channel->local.id, channel->remote.id,
|
2007-06-06 12:34:06 +00:00
|
|
|
channel->local.window_size,
|
|
|
|
channel->remote.window_size,
|
|
|
|
channel->local.packet_size,
|
|
|
|
channel->remote.packet_size);
|
|
|
|
p = x11open_state->packet;
|
2007-05-28 17:56:08 +00:00
|
|
|
*(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION;
|
2010-04-18 15:24:13 +02:00
|
|
|
_libssh2_store_u32(&p, channel->remote.id);
|
|
|
|
_libssh2_store_u32(&p, channel->local.id);
|
|
|
|
_libssh2_store_u32(&p, channel->remote.window_size_initial);
|
|
|
|
_libssh2_store_u32(&p, channel->remote.packet_size);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
x11open_state->state = libssh2_NB_state_created;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (x11open_state->state == libssh2_NB_state_created) {
|
2010-10-23 00:11:59 +02:00
|
|
|
rc = _libssh2_transport_send(session, x11open_state->packet, 17,
|
|
|
|
NULL, 0);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
2009-08-25 00:54:47 +02:00
|
|
|
return rc;
|
2007-08-06 20:48:04 +00:00
|
|
|
} else if (rc) {
|
2007-06-06 12:34:06 +00:00
|
|
|
x11open_state->state = libssh2_NB_state_idle;
|
2010-04-16 00:18:51 +02:00
|
|
|
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
|
|
|
|
"Unable to send channel open "
|
|
|
|
"confirmation");
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/* Link the channel into the session */
|
2009-08-20 00:56:05 +02:00
|
|
|
_libssh2_list_add(&session->channels, &channel->node);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/*
|
|
|
|
* Pass control to the callback, they may turn right around and
|
|
|
|
* free the channel, or actually use it
|
|
|
|
*/
|
2009-08-20 00:56:05 +02:00
|
|
|
LIBSSH2_X11_OPEN(channel, (char *)x11open_state->shost,
|
2007-08-06 20:48:04 +00:00
|
|
|
x11open_state->sport);
|
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
x11open_state->state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return 0;
|
2007-02-02 16:21:20 +00:00
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2010-11-09 14:28:29 +01:00
|
|
|
else
|
|
|
|
failure_code = SSH_OPEN_RESOURCE_SHORTAGE;
|
|
|
|
/* fall-trough */
|
2007-08-06 20:48:04 +00:00
|
|
|
x11_exit:
|
2007-06-06 12:34:06 +00:00
|
|
|
p = x11open_state->packet;
|
2007-05-28 17:56:08 +00:00
|
|
|
*(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE;
|
2010-04-18 15:24:13 +02:00
|
|
|
_libssh2_store_u32(&p, x11open_state->sender_channel);
|
|
|
|
_libssh2_store_u32(&p, failure_code);
|
|
|
|
_libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1);
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_htonu32(p, 0);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-10-23 00:11:59 +02:00
|
|
|
rc = _libssh2_transport_send(session, x11open_state->packet, packet_len,
|
|
|
|
NULL, 0);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
2009-08-25 00:54:47 +02:00
|
|
|
return rc;
|
2007-08-06 20:48:04 +00:00
|
|
|
} else if (rc) {
|
2007-06-06 12:34:06 +00:00
|
|
|
x11open_state->state = libssh2_NB_state_idle;
|
2010-04-16 00:18:51 +02:00
|
|
|
return _libssh2_error(session, rc, "Unable to send open failure");
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-06-06 12:34:06 +00:00
|
|
|
x11open_state->state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return 0;
|
2005-01-06 00:51:30 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-13 22:15:27 +00:00
|
|
|
/*
|
2009-03-17 13:48:35 +00:00
|
|
|
* _libssh2_packet_add
|
2009-03-13 22:15:27 +00:00
|
|
|
*
|
|
|
|
* Create a new packet and attach it to the brigade. Called from the transport
|
2010-01-28 14:30:25 +01:00
|
|
|
* layer when it has received a packet.
|
2009-08-24 23:03:08 +02:00
|
|
|
*
|
|
|
|
* The input pointer 'data' is pointing to allocated data that this function
|
|
|
|
* is asked to deal with so on failure OR success, it must be freed fine.
|
2010-11-09 14:53:44 +01:00
|
|
|
*
|
|
|
|
* This function will always be called with 'datalen' greater than zero.
|
2004-12-07 21:17:20 +00:00
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
int
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data,
|
|
|
|
size_t datalen, int macstate)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2010-11-10 14:56:14 +01:00
|
|
|
int rc = 0;
|
|
|
|
char *message=NULL;
|
|
|
|
char *language=NULL;
|
|
|
|
size_t message_len=0;
|
|
|
|
size_t language_len=0;
|
|
|
|
LIBSSH2_CHANNEL *channelp = NULL;
|
|
|
|
size_t data_head = 0;
|
|
|
|
unsigned char msg = data[0];
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
switch(session->packAdd_state) {
|
|
|
|
case libssh2_NB_state_idle:
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
2007-06-06 12:34:06 +00:00
|
|
|
"Packet type %d received, length=%d",
|
2010-11-10 14:56:14 +01:00
|
|
|
(int) msg, (int) datalen);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
if ((macstate == LIBSSH2_MAC_INVALID) &&
|
|
|
|
(!session->macerror ||
|
|
|
|
LIBSSH2_MACERROR(session, (char *) data, datalen))) {
|
|
|
|
/* Bad MAC input, but no callback set or non-zero return from the
|
|
|
|
callback */
|
2007-06-06 12:34:06 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
return _libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC,
|
|
|
|
"Invalid MAC received");
|
|
|
|
}
|
|
|
|
session->packAdd_state = libssh2_NB_state_allocated;
|
|
|
|
break;
|
2010-11-10 12:21:48 +01:00
|
|
|
case libssh2_NB_state_jump1:
|
2007-06-06 12:34:06 +00:00
|
|
|
goto libssh2_packet_add_jump_point1;
|
2010-11-10 12:21:48 +01:00
|
|
|
case libssh2_NB_state_jump2:
|
2007-06-06 12:34:06 +00:00
|
|
|
goto libssh2_packet_add_jump_point2;
|
2010-11-10 12:21:48 +01:00
|
|
|
case libssh2_NB_state_jump3:
|
2007-06-06 12:34:06 +00:00
|
|
|
goto libssh2_packet_add_jump_point3;
|
2010-11-10 12:21:48 +01:00
|
|
|
case libssh2_NB_state_jump4:
|
2010-01-28 14:30:25 +01:00
|
|
|
goto libssh2_packet_add_jump_point4;
|
2010-11-10 12:21:48 +01:00
|
|
|
case libssh2_NB_state_jump5:
|
2010-01-28 15:03:24 +01:00
|
|
|
goto libssh2_packet_add_jump_point5;
|
2010-11-10 12:21:48 +01:00
|
|
|
default: /* nothing to do */
|
|
|
|
break;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->packAdd_state == libssh2_NB_state_allocated) {
|
|
|
|
/* A couple exceptions to the packet adding rule: */
|
2010-11-10 14:56:14 +01:00
|
|
|
switch (msg) {
|
2010-11-09 15:07:32 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
byte SSH_MSG_DISCONNECT
|
|
|
|
uint32 reason code
|
|
|
|
string description in ISO-10646 UTF-8 encoding [RFC3629]
|
|
|
|
string language tag [RFC3066]
|
|
|
|
*/
|
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
case SSH_MSG_DISCONNECT:
|
2010-11-09 14:53:44 +01:00
|
|
|
if(datalen >= 5) {
|
2010-11-10 14:56:14 +01:00
|
|
|
size_t reason = _libssh2_ntohu32(data + 1);
|
2010-11-09 14:53:44 +01:00
|
|
|
|
|
|
|
if(datalen >= 9) {
|
|
|
|
message_len = _libssh2_ntohu32(data + 5);
|
|
|
|
|
|
|
|
if(message_len < datalen-13) {
|
|
|
|
/* 9 = packet_type(1) + reason(4) + message_len(4) */
|
|
|
|
message = (char *) data + 9;
|
|
|
|
|
|
|
|
language_len = _libssh2_ntohu32(data + 9 + message_len);
|
|
|
|
language = (char *) data + 9 + message_len + 4;
|
|
|
|
|
|
|
|
if(language_len > (datalen-13-message_len)) {
|
|
|
|
/* bad input, clear info */
|
|
|
|
language = message = NULL;
|
|
|
|
language_len = message_len = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
/* bad size, clear it */
|
|
|
|
message_len=0;
|
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
if (session->ssh_msg_disconnect) {
|
|
|
|
LIBSSH2_DISCONNECT(session, reason, message,
|
|
|
|
message_len, language, language_len);
|
|
|
|
}
|
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
|
|
|
"Disconnect(%d): %s(%s)", reason,
|
|
|
|
message, language);
|
2010-04-16 00:18:51 +02:00
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
|
2010-04-16 00:18:51 +02:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT,
|
|
|
|
"socket disconnect");
|
2010-11-10 14:56:14 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_IGNORE
|
|
|
|
string data
|
|
|
|
*/
|
2010-11-09 15:07:32 +01:00
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
case SSH_MSG_IGNORE:
|
2010-11-09 14:57:36 +01:00
|
|
|
if (datalen >= 2) {
|
2009-10-28 15:27:11 +01:00
|
|
|
if (session->ssh_msg_ignore) {
|
2010-11-09 14:57:36 +01:00
|
|
|
LIBSSH2_IGNORE(session, (char *) data + 1, datalen - 1);
|
2009-10-28 15:27:11 +01:00
|
|
|
}
|
|
|
|
} else if (session->ssh_msg_ignore) {
|
|
|
|
LIBSSH2_IGNORE(session, "", 0);
|
2007-08-06 20:48:04 +00:00
|
|
|
}
|
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
|
2010-11-09 15:07:32 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_DEBUG
|
|
|
|
boolean always_display
|
|
|
|
string message in ISO-10646 UTF-8 encoding [RFC3629]
|
|
|
|
string language tag [RFC3066]
|
|
|
|
*/
|
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
case SSH_MSG_DEBUG:
|
2010-11-09 15:07:32 +01:00
|
|
|
if(datalen >= 2) {
|
2010-12-15 21:57:06 +01:00
|
|
|
int always_display= data[1];
|
2010-11-09 15:07:32 +01:00
|
|
|
|
|
|
|
if(datalen >= 6) {
|
|
|
|
message_len = _libssh2_ntohu32(data + 2);
|
|
|
|
|
|
|
|
if(message_len <= (datalen - 10)) {
|
|
|
|
/* 6 = packet_type(1) + display(1) + message_len(4) */
|
|
|
|
message = (char *) data + 6;
|
|
|
|
language_len = _libssh2_ntohu32(data + 6 + message_len);
|
|
|
|
|
|
|
|
if(language_len <= (datalen - 10 - message_len))
|
|
|
|
language = (char *) data + 10 + message_len;
|
|
|
|
}
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
if (session->ssh_msg_debug) {
|
|
|
|
LIBSSH2_DEBUG(session, always_display, message,
|
|
|
|
message_len, language, language_len);
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
}
|
2010-04-16 00:18:51 +02:00
|
|
|
/*
|
|
|
|
* _libssh2_debug will actually truncate this for us so
|
|
|
|
* that it's not an inordinate about of data
|
|
|
|
*/
|
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
|
|
|
"Debug Packet: %s", message);
|
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_GLOBAL_REQUEST
|
|
|
|
string request name in US-ASCII only
|
|
|
|
boolean want reply
|
|
|
|
.... request-specific data follows
|
|
|
|
*/
|
2010-11-09 19:59:18 +01:00
|
|
|
|
2010-01-28 15:03:24 +01:00
|
|
|
case SSH_MSG_GLOBAL_REQUEST:
|
2010-11-09 19:59:18 +01:00
|
|
|
if(datalen >= 5) {
|
2010-11-10 14:56:14 +01:00
|
|
|
uint32_t len =0;
|
|
|
|
unsigned char want_reply=0;
|
2010-11-09 19:59:18 +01:00
|
|
|
len = _libssh2_ntohu32(data + 1);
|
|
|
|
if(datalen >= (6 + len)) {
|
|
|
|
want_reply = data[5 + len];
|
|
|
|
_libssh2_debug(session,
|
|
|
|
LIBSSH2_TRACE_CONN,
|
|
|
|
"Received global request type %.*s (wr %X)",
|
|
|
|
len, data + 5, want_reply);
|
|
|
|
}
|
2010-01-28 15:03:24 +01:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
|
|
|
|
if (want_reply) {
|
|
|
|
unsigned char packet = SSH_MSG_REQUEST_FAILURE;
|
|
|
|
libssh2_packet_add_jump_point5:
|
|
|
|
session->packAdd_state = libssh2_NB_state_jump5;
|
|
|
|
rc = _libssh2_transport_send(session, &packet, 1, NULL, 0);
|
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN)
|
|
|
|
return rc;
|
|
|
|
}
|
2010-01-28 15:03:24 +01:00
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
2010-01-28 15:03:24 +01:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_CHANNEL_EXTENDED_DATA
|
|
|
|
uint32 recipient channel
|
|
|
|
uint32 data_type_code
|
|
|
|
string data
|
|
|
|
*/
|
2010-11-09 19:59:18 +01:00
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
case SSH_MSG_CHANNEL_EXTENDED_DATA:
|
|
|
|
/* streamid(4) */
|
2010-11-10 14:56:14 +01:00
|
|
|
data_head += 4;
|
|
|
|
|
|
|
|
/* fall-through */
|
2010-11-09 19:59:18 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
byte SSH_MSG_CHANNEL_DATA
|
|
|
|
uint32 recipient channel
|
|
|
|
string data
|
|
|
|
*/
|
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
case SSH_MSG_CHANNEL_DATA:
|
|
|
|
/* packet_type(1) + channelno(4) + datalen(4) */
|
2010-11-10 14:56:14 +01:00
|
|
|
data_head += 9;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
if(datalen >= data_head)
|
|
|
|
channelp =
|
|
|
|
_libssh2_channel_locate(session,
|
|
|
|
_libssh2_ntohu32(data + 1));
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
if (!channelp) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN,
|
2010-11-09 14:32:02 +01:00
|
|
|
"Packet received for unknown channel");
|
2009-03-14 22:29:48 +00:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#ifdef LIBSSH2DEBUG
|
|
|
|
{
|
2010-11-10 14:56:14 +01:00
|
|
|
uint32_t stream_id = 0;
|
|
|
|
if (msg == SSH_MSG_CHANNEL_EXTENDED_DATA)
|
2009-03-17 13:48:35 +00:00
|
|
|
stream_id = _libssh2_ntohu32(data + 5);
|
2009-03-14 22:29:48 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2009-03-14 22:29:48 +00:00
|
|
|
"%d bytes packet_add() for %lu/%lu/%lu",
|
2010-11-10 14:56:14 +01:00
|
|
|
(int) (datalen - data_head),
|
|
|
|
channelp->local.id,
|
|
|
|
channelp->remote.id,
|
2009-03-14 22:29:48 +00:00
|
|
|
stream_id);
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
#endif
|
2010-11-10 14:56:14 +01:00
|
|
|
if ((channelp->remote.extended_data_ignore_mode ==
|
2009-03-14 22:29:48 +00:00
|
|
|
LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) &&
|
2010-11-10 14:56:14 +01:00
|
|
|
(msg == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
|
2009-03-14 22:29:48 +00:00
|
|
|
/* Pretend we didn't receive this */
|
|
|
|
LIBSSH2_FREE(session, data);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2009-03-14 22:29:48 +00:00
|
|
|
"Ignoring extended data and refunding %d bytes",
|
|
|
|
(int) (datalen - 13));
|
2010-11-10 14:56:14 +01:00
|
|
|
session->packAdd_channelp = channelp;
|
|
|
|
|
2009-03-14 22:29:48 +00:00
|
|
|
/* Adjust the window based on the block we just freed */
|
|
|
|
libssh2_packet_add_jump_point1:
|
|
|
|
session->packAdd_state = libssh2_NB_state_jump1;
|
2009-08-24 23:24:35 +02:00
|
|
|
rc = _libssh2_channel_receive_window_adjust(session->
|
2010-11-10 14:56:14 +01:00
|
|
|
packAdd_channelp,
|
2009-08-24 23:24:35 +02:00
|
|
|
datalen - 13,
|
2012-04-03 22:36:19 +02:00
|
|
|
1, NULL);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN)
|
2009-08-24 23:24:35 +02:00
|
|
|
return rc;
|
|
|
|
|
2009-03-14 22:29:48 +00:00
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-14 22:29:48 +00:00
|
|
|
/*
|
|
|
|
* REMEMBER! remote means remote as source of data,
|
|
|
|
* NOT remote window!
|
|
|
|
*/
|
2010-11-10 14:56:14 +01:00
|
|
|
if (channelp->remote.packet_size < (datalen - data_head)) {
|
2007-08-06 20:48:04 +00:00
|
|
|
/*
|
2009-03-14 22:29:48 +00:00
|
|
|
* Spec says we MAY ignore bytes sent beyond
|
|
|
|
* packet_size
|
2007-08-06 20:48:04 +00:00
|
|
|
*/
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session,
|
|
|
|
LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED,
|
|
|
|
"Packet contains more data than we offered"
|
|
|
|
" to receive, truncating");
|
2010-11-10 14:56:14 +01:00
|
|
|
datalen = channelp->remote.packet_size + data_head;
|
2009-03-14 22:29:48 +00:00
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
if (channelp->remote.window_size <= 0) {
|
2009-03-14 22:29:48 +00:00
|
|
|
/*
|
|
|
|
* Spec says we MAY ignore bytes sent beyond
|
|
|
|
* window_size
|
|
|
|
*/
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session,
|
|
|
|
LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
|
|
|
|
"The current receive window is full,"
|
|
|
|
" data ignored");
|
2009-03-14 22:29:48 +00:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/* Reset EOF status */
|
2010-11-10 14:56:14 +01:00
|
|
|
channelp->remote.eof = 0;
|
2009-03-14 22:29:48 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
if ((datalen - data_head) > channelp->remote.window_size) {
|
2010-04-16 00:18:51 +02:00
|
|
|
_libssh2_error(session,
|
|
|
|
LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED,
|
|
|
|
"Remote sent more data than current "
|
|
|
|
"window allows, truncating");
|
2010-11-10 14:56:14 +01:00
|
|
|
datalen = channelp->remote.window_size + data_head;
|
2011-08-30 23:56:50 +02:00
|
|
|
channelp->remote.window_size = 0;
|
2009-03-14 22:29:48 +00:00
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
else
|
2009-03-14 22:29:48 +00:00
|
|
|
/* Now that we've received it, shrink our window */
|
2010-11-10 14:56:14 +01:00
|
|
|
channelp->remote.window_size -= datalen - data_head;
|
2009-03-14 22:29:48 +00:00
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
break;
|
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_CHANNEL_EOF
|
|
|
|
uint32 recipient channel
|
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
case SSH_MSG_CHANNEL_EOF:
|
|
|
|
if(datalen >= 5)
|
|
|
|
channelp =
|
|
|
|
_libssh2_channel_locate(session,
|
|
|
|
_libssh2_ntohu32(data + 1));
|
|
|
|
if (!channelp)
|
2009-08-20 00:59:23 +02:00
|
|
|
/* We may have freed already, just quietly ignore this... */
|
2010-11-10 14:56:14 +01:00
|
|
|
;
|
|
|
|
else {
|
|
|
|
_libssh2_debug(session,
|
|
|
|
LIBSSH2_TRACE_CONN,
|
|
|
|
"EOF received for channel %lu/%lu",
|
|
|
|
channelp->local.id,
|
|
|
|
channelp->remote.id);
|
|
|
|
channelp->remote.eof = 1;
|
2007-08-06 20:48:04 +00:00
|
|
|
}
|
2009-08-20 00:59:23 +02:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_CHANNEL_REQUEST
|
|
|
|
uint32 recipient channel
|
|
|
|
string request type in US-ASCII characters only
|
|
|
|
boolean want reply
|
|
|
|
.... type-specific data follows
|
|
|
|
*/
|
2010-01-28 14:30:25 +01:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
case SSH_MSG_CHANNEL_REQUEST:
|
|
|
|
if(datalen >= 9) {
|
|
|
|
uint32_t channel = _libssh2_ntohu32(data + 1);
|
|
|
|
uint32_t len = _libssh2_ntohu32(data + 5);
|
|
|
|
unsigned char want_reply = 0;
|
|
|
|
|
|
|
|
if(len < (datalen - 10))
|
|
|
|
want_reply = data[9 + len];
|
|
|
|
|
|
|
|
_libssh2_debug(session,
|
|
|
|
LIBSSH2_TRACE_CONN,
|
|
|
|
"Channel %d received request type %.*s (wr %X)",
|
|
|
|
channel, len, data + 9, want_reply);
|
|
|
|
|
|
|
|
if (len == sizeof("exit-status") - 1
|
|
|
|
&& !memcmp("exit-status", data + 9,
|
|
|
|
sizeof("exit-status") - 1)) {
|
|
|
|
|
|
|
|
/* we've got "exit-status" packet. Set the session value */
|
|
|
|
if(datalen >= 20)
|
|
|
|
channelp =
|
|
|
|
_libssh2_channel_locate(session, channel);
|
|
|
|
|
|
|
|
if (channelp) {
|
|
|
|
channelp->exit_status =
|
|
|
|
_libssh2_ntohu32(data + 9 + sizeof("exit-status"));
|
2010-10-13 15:31:06 +02:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2010-11-10 14:56:14 +01:00
|
|
|
"Exit status %lu received for "
|
2010-11-09 14:32:02 +01:00
|
|
|
"channel %lu/%lu",
|
2010-11-10 14:56:14 +01:00
|
|
|
channelp->exit_status,
|
|
|
|
channelp->local.id,
|
|
|
|
channelp->remote.id);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (len == sizeof("exit-signal") - 1
|
|
|
|
&& !memcmp("exit-signal", data + 9,
|
|
|
|
sizeof("exit-signal") - 1)) {
|
|
|
|
/* command terminated due to signal */
|
|
|
|
if(datalen >= 20)
|
|
|
|
channelp = _libssh2_channel_locate(session, channel);
|
|
|
|
|
|
|
|
if (channelp) {
|
|
|
|
/* set signal name (without SIG prefix) */
|
|
|
|
uint32_t namelen =
|
|
|
|
_libssh2_ntohu32(data + 9 + sizeof("exit-signal"));
|
|
|
|
channelp->exit_signal =
|
|
|
|
LIBSSH2_ALLOC(session, namelen + 1);
|
|
|
|
if (!channelp->exit_signal)
|
|
|
|
rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
|
|
|
|
"memory for signal name");
|
|
|
|
else {
|
|
|
|
memcpy(channelp->exit_signal,
|
|
|
|
data + 13 + sizeof("exit_signal"), namelen);
|
|
|
|
channelp->exit_signal[namelen] = '\0';
|
|
|
|
/* TODO: save error message and language tag */
|
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
|
|
|
"Exit signal %s received for "
|
|
|
|
"channel %lu/%lu",
|
|
|
|
channelp->exit_signal,
|
|
|
|
channelp->local.id,
|
|
|
|
channelp->remote.id);
|
|
|
|
}
|
2010-10-13 15:31:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
if (want_reply) {
|
|
|
|
unsigned char packet[5];
|
|
|
|
libssh2_packet_add_jump_point4:
|
|
|
|
session->packAdd_state = libssh2_NB_state_jump4;
|
|
|
|
packet[0] = SSH_MSG_CHANNEL_FAILURE;
|
|
|
|
memcpy(&packet[1], data+1, 4);
|
|
|
|
rc = _libssh2_transport_send(session, packet, 5, NULL, 0);
|
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN)
|
|
|
|
return rc;
|
|
|
|
}
|
2010-01-28 14:30:25 +01:00
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return rc;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_CHANNEL_CLOSE
|
|
|
|
uint32 recipient channel
|
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
case SSH_MSG_CHANNEL_CLOSE:
|
|
|
|
if(datalen >= 5)
|
|
|
|
channelp =
|
|
|
|
_libssh2_channel_locate(session,
|
|
|
|
_libssh2_ntohu32(data + 1));
|
|
|
|
if (!channelp) {
|
2009-08-20 00:59:23 +02:00
|
|
|
/* We may have freed already, just quietly ignore this... */
|
2007-08-06 20:48:04 +00:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
|
|
|
}
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
2009-08-20 00:59:23 +02:00
|
|
|
"Close received for channel %lu/%lu",
|
2010-11-10 14:56:14 +01:00
|
|
|
channelp->local.id,
|
|
|
|
channelp->remote.id);
|
2009-08-20 00:59:23 +02:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
channelp->remote.close = 1;
|
|
|
|
channelp->remote.eof = 1;
|
2009-08-20 00:59:23 +02:00
|
|
|
|
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_CHANNEL_OPEN
|
|
|
|
string "session"
|
|
|
|
uint32 sender channel
|
|
|
|
uint32 initial window size
|
|
|
|
uint32 maximum packet size
|
|
|
|
*/
|
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
case SSH_MSG_CHANNEL_OPEN:
|
2010-11-10 14:56:14 +01:00
|
|
|
if(datalen < 17)
|
|
|
|
;
|
|
|
|
else if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
|
|
|
|
((sizeof("forwarded-tcpip") - 1) ==
|
|
|
|
_libssh2_ntohu32(data + 1))
|
|
|
|
&&
|
|
|
|
(memcmp(data + 5, "forwarded-tcpip",
|
|
|
|
sizeof("forwarded-tcpip") - 1) == 0)) {
|
|
|
|
|
|
|
|
/* init the state struct */
|
|
|
|
memset(&session->packAdd_Qlstn_state, 0,
|
|
|
|
sizeof(session->packAdd_Qlstn_state));
|
2007-08-06 20:48:04 +00:00
|
|
|
|
|
|
|
libssh2_packet_add_jump_point2:
|
|
|
|
session->packAdd_state = libssh2_NB_state_jump2;
|
2009-03-17 13:48:35 +00:00
|
|
|
rc = packet_queue_listener(session, data, datalen,
|
|
|
|
&session->packAdd_Qlstn_state);
|
2007-08-06 20:48:04 +00:00
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
else if ((datalen >= (sizeof("x11") + 4)) &&
|
|
|
|
((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) &&
|
|
|
|
(memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
|
|
|
|
|
|
|
|
/* init the state struct */
|
|
|
|
memset(&session->packAdd_x11open_state, 0,
|
|
|
|
sizeof(session->packAdd_x11open_state));
|
2007-08-06 20:48:04 +00:00
|
|
|
|
|
|
|
libssh2_packet_add_jump_point3:
|
|
|
|
session->packAdd_state = libssh2_NB_state_jump3;
|
2009-03-17 13:48:35 +00:00
|
|
|
rc = packet_x11_open(session, data, datalen,
|
|
|
|
&session->packAdd_x11open_state);
|
2007-08-06 20:48:04 +00:00
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return rc;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
/*
|
|
|
|
byte SSH_MSG_CHANNEL_WINDOW_ADJUST
|
|
|
|
uint32 recipient channel
|
|
|
|
uint32 bytes to add
|
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
case SSH_MSG_CHANNEL_WINDOW_ADJUST:
|
2010-11-10 14:56:14 +01:00
|
|
|
if(datalen < 9)
|
|
|
|
;
|
|
|
|
else {
|
|
|
|
uint32_t bytestoadd = _libssh2_ntohu32(data + 5);
|
|
|
|
channelp =
|
|
|
|
_libssh2_channel_locate(session,
|
|
|
|
_libssh2_ntohu32(data + 1));
|
|
|
|
if(channelp) {
|
|
|
|
channelp->local.window_size += bytestoadd;
|
2010-04-16 00:18:51 +02:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_CONN,
|
|
|
|
"Window adjust for channel %lu/%lu, "
|
|
|
|
"adding %lu bytes, new window_size=%lu",
|
|
|
|
channelp->local.id,
|
|
|
|
channelp->remote.id,
|
|
|
|
bytestoadd,
|
|
|
|
channelp->local.window_size);
|
|
|
|
}
|
|
|
|
}
|
2010-04-16 00:18:51 +02:00
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
return 0;
|
2010-11-10 14:56:14 +01:00
|
|
|
default:
|
|
|
|
break;
|
2007-02-02 16:21:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->packAdd_state = libssh2_NB_state_sent;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (session->packAdd_state == libssh2_NB_state_sent) {
|
2010-11-10 14:56:14 +01:00
|
|
|
LIBSSH2_PACKET *packetp =
|
2010-04-16 00:18:51 +02:00
|
|
|
LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
|
2010-11-10 14:56:14 +01:00
|
|
|
if (!packetp) {
|
2007-06-06 12:34:06 +00:00
|
|
|
_libssh2_debug(session, LIBSSH2_ERROR_ALLOC,
|
2010-11-10 14:56:14 +01:00
|
|
|
"memory for packet");
|
2007-06-06 12:34:06 +00:00
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
2010-11-10 14:56:14 +01:00
|
|
|
return LIBSSH2_ERROR_ALLOC;
|
2007-06-06 12:34:06 +00:00
|
|
|
}
|
2010-11-10 14:56:14 +01:00
|
|
|
packetp->data = data;
|
|
|
|
packetp->data_len = datalen;
|
|
|
|
packetp->data_head = data_head;
|
2009-08-20 00:56:05 +02:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
_libssh2_list_add(&session->packets, &packetp->node);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->packAdd_state = libssh2_NB_state_sent1;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2010-11-10 14:56:14 +01:00
|
|
|
if ((msg == SSH_MSG_KEXINIT &&
|
2007-06-06 12:34:06 +00:00
|
|
|
!(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) ||
|
|
|
|
(session->packAdd_state == libssh2_NB_state_sent2)) {
|
|
|
|
if (session->packAdd_state == libssh2_NB_state_sent1) {
|
|
|
|
/*
|
|
|
|
* Remote wants new keys
|
|
|
|
* Well, it's already in the brigade,
|
|
|
|
* let's just call back into ourselves
|
|
|
|
*/
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS, "Renegotiating Keys");
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->packAdd_state = libssh2_NB_state_sent2;
|
|
|
|
}
|
2008-07-03 16:26:55 +00:00
|
|
|
|
|
|
|
/*
|
2009-03-26 15:41:14 +00:00
|
|
|
* The KEXINIT message has been added to the queue. The packAdd and
|
2010-04-24 21:14:16 +02:00
|
|
|
* readPack states need to be reset because _libssh2_kex_exchange
|
2009-03-26 15:41:14 +00:00
|
|
|
* (eventually) calls upon _libssh2_transport_read to read the rest of
|
|
|
|
* the key exchange conversation.
|
2008-07-03 16:26:55 +00:00
|
|
|
*/
|
|
|
|
session->readPack_state = libssh2_NB_state_idle;
|
|
|
|
session->packet.total_num = 0;
|
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
|
|
|
session->fullpacket_state = libssh2_NB_state_idle;
|
|
|
|
|
|
|
|
memset(&session->startup_key_state, 0, sizeof(key_exchange_state_t));
|
2009-03-14 22:29:48 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/*
|
|
|
|
* If there was a key reexchange failure, let's just hope we didn't
|
|
|
|
* send NEWKEYS yet, otherwise remote will drop us like a rock
|
2007-05-28 17:56:08 +00:00
|
|
|
*/
|
2010-04-24 21:14:16 +02:00
|
|
|
rc = _libssh2_kex_exchange(session, 1, &session->startup_key_state);
|
|
|
|
if (rc == LIBSSH2_ERROR_EAGAIN)
|
2009-08-25 00:54:47 +02:00
|
|
|
return rc;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
session->packAdd_state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return 0;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-13 22:15:27 +00:00
|
|
|
/*
|
2009-03-17 13:48:35 +00:00
|
|
|
* _libssh2_packet_ask
|
2009-03-13 22:15:27 +00:00
|
|
|
*
|
2007-02-02 16:21:20 +00:00
|
|
|
* Scan the brigade for a matching packet type, optionally poll the socket for
|
|
|
|
* a packet first
|
2004-12-07 21:17:20 +00:00
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
int
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type,
|
2010-04-17 13:18:15 +02:00
|
|
|
unsigned char **data, size_t *data_len,
|
|
|
|
int match_ofs, const unsigned char *match_buf,
|
|
|
|
size_t match_len)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2009-08-20 00:56:05 +02:00
|
|
|
LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
2007-08-06 20:48:04 +00:00
|
|
|
"Looking for packet of type: %d", (int) packet_type);
|
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
while (packet) {
|
2007-08-06 20:48:04 +00:00
|
|
|
if (packet->data[0] == packet_type
|
2009-03-17 14:58:24 +00:00
|
|
|
&& (packet->data_len >= (match_ofs + match_len))
|
|
|
|
&& (!match_buf ||
|
|
|
|
(memcmp(packet->data + match_ofs, match_buf,
|
|
|
|
match_len) == 0))) {
|
2007-05-28 17:56:08 +00:00
|
|
|
*data = packet->data;
|
|
|
|
*data_len = packet->data_len;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-08-20 00:56:05 +02:00
|
|
|
/* unlink struct from session->packets */
|
|
|
|
_libssh2_list_remove(&packet->node);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
LIBSSH2_FREE(session, packet);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
return 0;
|
2007-02-02 16:21:20 +00:00
|
|
|
}
|
2009-08-20 00:56:05 +02:00
|
|
|
packet = _libssh2_list_next(&packet->node);
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
return -1;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-13 22:15:27 +00:00
|
|
|
/*
|
|
|
|
* libssh2_packet_askv
|
|
|
|
*
|
2007-02-02 16:21:20 +00:00
|
|
|
* Scan for any of a list of packet types in the brigade, optionally poll the
|
|
|
|
* socket for a packet first
|
2004-12-07 21:17:20 +00:00
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
int
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_packet_askv(LIBSSH2_SESSION * session,
|
|
|
|
const unsigned char *packet_types,
|
2010-04-17 13:18:15 +02:00
|
|
|
unsigned char **data, size_t *data_len,
|
|
|
|
int match_ofs,
|
2009-03-17 13:48:35 +00:00
|
|
|
const unsigned char *match_buf,
|
2010-04-17 13:18:15 +02:00
|
|
|
size_t match_len)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-08-06 20:48:04 +00:00
|
|
|
int i, packet_types_len = strlen((char *) packet_types);
|
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
for(i = 0; i < packet_types_len; i++) {
|
2009-03-17 13:48:35 +00:00
|
|
|
if (0 == _libssh2_packet_ask(session, packet_types[i], data,
|
2009-03-23 12:43:59 +00:00
|
|
|
data_len, match_ofs,
|
|
|
|
match_buf, match_len)) {
|
2007-05-28 17:56:08 +00:00
|
|
|
return 0;
|
2007-02-02 16:21:20 +00:00
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
return -1;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-13 22:15:27 +00:00
|
|
|
/*
|
2009-03-17 13:48:35 +00:00
|
|
|
* _libssh2_packet_require
|
2009-03-13 22:15:27 +00:00
|
|
|
*
|
2009-03-26 15:41:14 +00:00
|
|
|
* Loops _libssh2_transport_read() until the packet requested is available
|
2005-04-01 06:11:34 +00:00
|
|
|
* SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause a bailout
|
2007-02-02 16:21:20 +00:00
|
|
|
*
|
|
|
|
* Returns negative on error
|
|
|
|
* Returns 0 when it has taken care of the requested packet.
|
2004-12-07 21:17:20 +00:00
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
int
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type,
|
2010-04-17 13:18:15 +02:00
|
|
|
unsigned char **data, size_t *data_len,
|
|
|
|
int match_ofs,
|
2009-03-17 13:48:35 +00:00
|
|
|
const unsigned char *match_buf,
|
2010-04-17 13:18:15 +02:00
|
|
|
size_t match_len,
|
2009-03-23 12:43:59 +00:00
|
|
|
packet_require_state_t *state)
|
2004-12-07 21:17:20 +00:00
|
|
|
{
|
2007-06-06 12:34:06 +00:00
|
|
|
if (state->start == 0) {
|
2009-03-17 13:48:35 +00:00
|
|
|
if (_libssh2_packet_ask(session, packet_type, data, data_len,
|
2010-04-16 00:18:51 +02:00
|
|
|
match_ofs, match_buf,
|
|
|
|
match_len) == 0) {
|
2007-06-06 12:34:06 +00:00
|
|
|
/* A packet was available in the packet brigade */
|
|
|
|
return 0;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
state->start = time(NULL);
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
2009-08-24 23:57:15 +02:00
|
|
|
int ret = _libssh2_transport_read(session);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (ret == LIBSSH2_ERROR_EAGAIN)
|
2009-08-25 00:54:47 +02:00
|
|
|
return ret;
|
|
|
|
else if (ret < 0) {
|
2007-06-06 12:34:06 +00:00
|
|
|
state->start = 0;
|
2007-05-28 17:56:08 +00:00
|
|
|
/* an error which is not just because of blocking */
|
|
|
|
return ret;
|
2007-08-06 20:48:04 +00:00
|
|
|
} else if (ret == packet_type) {
|
2007-06-06 12:34:06 +00:00
|
|
|
/* Be lazy, let packet_ask pull it out of the brigade */
|
2009-03-17 13:48:35 +00:00
|
|
|
ret = _libssh2_packet_ask(session, packet_type, data, data_len,
|
2010-04-16 00:18:51 +02:00
|
|
|
match_ofs, match_buf, match_len);
|
2007-06-06 12:34:06 +00:00
|
|
|
state->start = 0;
|
2007-05-28 17:56:08 +00:00
|
|
|
return ret;
|
2007-08-06 20:48:04 +00:00
|
|
|
} else if (ret == 0) {
|
2007-06-06 12:34:06 +00:00
|
|
|
/* nothing available, wait until data arrives or we time out */
|
2010-11-09 14:32:02 +01:00
|
|
|
long left = LIBSSH2_READ_TIMEOUT - (long)(time(NULL) -
|
|
|
|
state->start);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-26 15:41:14 +00:00
|
|
|
if (left <= 0) {
|
2007-06-06 12:34:06 +00:00
|
|
|
state->start = 0;
|
2010-04-17 13:18:15 +02:00
|
|
|
return LIBSSH2_ERROR_TIMEOUT;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2009-08-25 00:54:47 +02:00
|
|
|
return -1; /* no packet available yet */
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
/* Only reached if the socket died */
|
2009-08-24 22:50:46 +02:00
|
|
|
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
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-23 12:43:59 +00:00
|
|
|
* _libssh2_packet_burn
|
2009-03-17 13:48:35 +00:00
|
|
|
*
|
2009-03-26 15:41:14 +00:00
|
|
|
* Loops _libssh2_transport_read() until any packet is available and promptly
|
2009-03-23 12:43:59 +00:00
|
|
|
* discards it.
|
2006-06-22 18:45:29 +00:00
|
|
|
* Used during KEX exchange to discard badly guessed KEX_INIT packets
|
|
|
|
*/
|
2007-08-06 20:48:04 +00:00
|
|
|
int
|
2009-03-17 13:48:35 +00:00
|
|
|
_libssh2_packet_burn(LIBSSH2_SESSION * session,
|
|
|
|
libssh2_nonblocking_states * state)
|
2006-06-22 18:45:29 +00:00
|
|
|
{
|
2007-05-28 17:56:08 +00:00
|
|
|
unsigned char *data;
|
2010-04-17 13:18:15 +02:00
|
|
|
size_t data_len;
|
2007-05-28 17:56:08 +00:00
|
|
|
unsigned char all_packets[255];
|
|
|
|
int i;
|
2007-06-06 12:34:06 +00:00
|
|
|
int ret;
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (*state == libssh2_NB_state_idle) {
|
|
|
|
for(i = 1; i < 256; i++) {
|
|
|
|
all_packets[i - 1] = i;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-17 13:48:35 +00:00
|
|
|
if (_libssh2_packet_askv(session, all_packets, &data, &data_len, 0,
|
2009-03-23 12:43:59 +00:00
|
|
|
NULL, 0) == 0) {
|
2007-06-06 12:34:06 +00:00
|
|
|
i = data[0];
|
|
|
|
/* A packet was available in the packet brigade, burn it */
|
|
|
|
LIBSSH2_FREE(session, data);
|
|
|
|
return i;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-12-08 08:52:03 +01:00
|
|
|
_libssh2_debug(session, LIBSSH2_TRACE_TRANS,
|
2007-08-06 20:48:04 +00:00
|
|
|
"Blocking until packet becomes available to burn");
|
2007-06-06 12:34:06 +00:00
|
|
|
*state = libssh2_NB_state_created;
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
while (session->socket_state == LIBSSH2_SOCKET_CONNECTED) {
|
2009-08-25 00:54:47 +02:00
|
|
|
ret = _libssh2_transport_read(session);
|
2010-04-17 13:18:15 +02:00
|
|
|
if (ret == LIBSSH2_ERROR_EAGAIN) {
|
2009-08-25 00:54:47 +02:00
|
|
|
return ret;
|
2007-08-06 20:48:04 +00:00
|
|
|
} else if (ret < 0) {
|
2007-06-06 12:34:06 +00:00
|
|
|
*state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return ret;
|
2007-08-06 20:48:04 +00:00
|
|
|
} else if (ret == 0) {
|
2007-05-28 17:56:08 +00:00
|
|
|
/* FIXME: this might busyloop */
|
|
|
|
continue;
|
2007-02-02 16:21:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
/* Be lazy, let packet_ask pull it out of the brigade */
|
2007-08-06 20:48:04 +00:00
|
|
|
if (0 ==
|
2009-03-23 12:43:59 +00:00
|
|
|
_libssh2_packet_ask(session, ret, &data, &data_len, 0, NULL, 0)) {
|
2007-05-28 17:56:08 +00:00
|
|
|
/* Smoke 'em if you got 'em */
|
|
|
|
LIBSSH2_FREE(session, data);
|
2007-06-06 12:34:06 +00:00
|
|
|
*state = libssh2_NB_state_idle;
|
2007-05-28 17:56:08 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
/* Only reached if the socket died */
|
2009-08-24 22:50:46 +02:00
|
|
|
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
2006-06-22 18:45:29 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
/*
|
2009-03-17 13:48:35 +00:00
|
|
|
* _libssh2_packet_requirev
|
2007-06-06 12:34:06 +00:00
|
|
|
*
|
2010-03-03 23:44:24 +01:00
|
|
|
* Loops _libssh2_transport_read() until one of a list of packet types
|
|
|
|
* requested is available. SSH_DISCONNECT or a SOCKET_DISCONNECTED will cause
|
|
|
|
* a bailout. packet_types is a null terminated list of packet_type numbers
|
2005-04-01 06:11:34 +00:00
|
|
|
*/
|
2004-12-07 21:17:20 +00:00
|
|
|
|
2007-08-06 20:48:04 +00:00
|
|
|
int
|
2010-04-17 13:18:15 +02:00
|
|
|
_libssh2_packet_requirev(LIBSSH2_SESSION *session,
|
2009-03-17 13:48:35 +00:00
|
|
|
const unsigned char *packet_types,
|
2010-04-17 13:18:15 +02:00
|
|
|
unsigned char **data, size_t *data_len,
|
|
|
|
int match_ofs,
|
|
|
|
const unsigned char *match_buf, size_t match_len,
|
2009-03-17 13:48:35 +00:00
|
|
|
packet_requirev_state_t * state)
|
2005-05-11 05:11:31 +00:00
|
|
|
{
|
2009-03-17 13:48:35 +00:00
|
|
|
if (_libssh2_packet_askv(session, packet_types, data, data_len, match_ofs,
|
2009-03-23 12:43:59 +00:00
|
|
|
match_buf, match_len) == 0) {
|
|
|
|
/* One of the packets listed was available in the packet brigade */
|
2007-06-06 12:34:06 +00:00
|
|
|
state->start = 0;
|
2007-05-28 17:56:08 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-06-06 12:34:06 +00:00
|
|
|
if (state->start == 0) {
|
|
|
|
state->start = time(NULL);
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
while (session->socket_state != LIBSSH2_SOCKET_DISCONNECTED) {
|
2009-03-26 15:41:14 +00:00
|
|
|
int ret = _libssh2_transport_read(session);
|
2010-04-17 13:18:15 +02:00
|
|
|
if ((ret < 0) && (ret != LIBSSH2_ERROR_EAGAIN)) {
|
2007-06-06 12:34:06 +00:00
|
|
|
state->start = 0;
|
2007-05-28 17:56:08 +00:00
|
|
|
return ret;
|
2007-02-02 16:21:20 +00:00
|
|
|
}
|
2007-05-28 17:56:08 +00:00
|
|
|
if (ret <= 0) {
|
2010-03-03 23:44:24 +01:00
|
|
|
long left = LIBSSH2_READ_TIMEOUT -
|
|
|
|
(long)(time(NULL) - state->start);
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2009-03-26 15:41:14 +00:00
|
|
|
if (left <= 0) {
|
2007-06-06 12:34:06 +00:00
|
|
|
state->start = 0;
|
2010-04-17 13:18:15 +02:00
|
|
|
return LIBSSH2_ERROR_TIMEOUT;
|
2009-03-26 15:41:14 +00:00
|
|
|
}
|
2010-04-17 13:18:15 +02:00
|
|
|
else if (ret == LIBSSH2_ERROR_EAGAIN) {
|
2009-08-25 00:54:47 +02:00
|
|
|
return ret;
|
2007-06-06 12:34:06 +00:00
|
|
|
}
|
2007-02-02 16:21:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
|
|
|
if (strchr((char *) packet_types, ret)) {
|
2007-06-06 12:34:06 +00:00
|
|
|
/* Be lazy, let packet_ask pull it out of the brigade */
|
2009-03-17 13:48:35 +00:00
|
|
|
return _libssh2_packet_askv(session, packet_types, data,
|
2009-03-23 12:43:59 +00:00
|
|
|
data_len, match_ofs, match_buf,
|
|
|
|
match_len);
|
2007-05-28 17:56:08 +00:00
|
|
|
}
|
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|
2007-05-28 17:56:08 +00:00
|
|
|
/* Only reached if the socket died */
|
2007-06-06 12:34:06 +00:00
|
|
|
state->start = 0;
|
2009-08-24 22:50:46 +02:00
|
|
|
return LIBSSH2_ERROR_SOCKET_DISCONNECT;
|
2004-12-07 21:17:20 +00:00
|
|
|
}
|
2007-08-06 20:48:04 +00:00
|
|
|
|