summaryrefslogtreecommitdiff
path: root/libs/libssh2/src/channel.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libssh2/src/channel.c')
-rw-r--r--libs/libssh2/src/channel.c574
1 files changed, 456 insertions, 118 deletions
diff --git a/libs/libssh2/src/channel.c b/libs/libssh2/src/channel.c
index 7bbeeb88f6..c35658a04e 100644
--- a/libs/libssh2/src/channel.c
+++ b/libs/libssh2/src/channel.c
@@ -1,7 +1,6 @@
-/* Copyright (c) 2004-2007 Sara Golemon <sarag@libssh2.org>
- * Copyright (c) 2005 Mikhail Gusarov <dottedmag@dottedmag.net>
- * Copyright (c) 2008-2019 by Daniel Stenberg
- *
+/* Copyright (C) Sara Golemon <sarag@libssh2.org>
+ * Copyright (C) Mikhail Gusarov <dottedmag@dottedmag.net>
+ * Copyright (C) Daniel Stenberg
* All rights reserved.
*
* Redistribution and use in source and binary forms,
@@ -36,16 +35,19 @@
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
*/
#include "libssh2_priv.h"
+
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
-#include <fcntl.h>
#ifdef HAVE_INTTYPES_H
#include <inttypes.h>
#endif
+
#include <assert.h>
#include "channel.h"
@@ -81,8 +83,8 @@ _libssh2_channel_nextid(LIBSSH2_SESSION * session)
* told...
*/
session->next_channel = id + 1;
- _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Allocated new channel ID#%lu",
- id);
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
+ "Allocated new channel ID#%lu", id));
return id;
}
@@ -154,9 +156,9 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
memset(&session->open_packet_requirev_state, 0,
sizeof(session->open_packet_requirev_state));
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Opening Channel - win %d pack %d", window_size,
- packet_size);
+ packet_size));
session->open_channel =
LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL));
if(!session->open_channel) {
@@ -236,6 +238,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
return NULL;
}
else if(rc) {
+ _libssh2_error(session, rc, "Unexpected error");
goto channel_error;
}
@@ -261,7 +264,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
_libssh2_ntohu32(session->open_data + 9);
session->open_channel->local.packet_size =
_libssh2_ntohu32(session->open_data + 13);
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Connection Established - ID: %lu/%lu win: %lu/%lu"
" pack: %lu/%lu",
session->open_channel->local.id,
@@ -269,7 +272,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
session->open_channel->local.window_size,
session->open_channel->remote.window_size,
session->open_channel->local.packet_size,
- session->open_channel->remote.packet_size);
+ session->open_channel->remote.packet_size));
LIBSSH2_FREE(session, session->open_packet);
session->open_packet = NULL;
LIBSSH2_FREE(session, session->open_data);
@@ -307,7 +310,7 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
}
}
- channel_error:
+channel_error:
if(session->open_data) {
LIBSSH2_FREE(session, session->open_data);
@@ -326,14 +329,14 @@ _libssh2_channel_open(LIBSSH2_SESSION * session, const char *channel_type,
/* Clear out packets meant for this channel */
_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,
- channel_id, 4) >= 0)
- ||
- (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA,
- &session->open_data,
- &session->open_data_len, 1,
- channel_id, 4) >= 0)) {
+ &session->open_data,
+ &session->open_data_len, 1,
+ channel_id, 4) >= 0)
+ ||
+ (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA,
+ &session->open_data,
+ &session->open_data_len, 1,
+ channel_id, 4) >= 0)) {
LIBSSH2_FREE(session, session->open_data);
session->open_data = NULL;
}
@@ -389,9 +392,9 @@ channel_direct_tcpip(LIBSSH2_SESSION * session, const char *host,
session->direct_message_len =
session->direct_host_len + session->direct_shost_len + 16;
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Requesting direct-tcpip session from %s:%d to %s:%d",
- shost, sport, host, port);
+ shost, sport, host, port));
s = session->direct_message =
LIBSSH2_ALLOC(session, session->direct_message_len);
@@ -452,6 +455,85 @@ libssh2_channel_direct_tcpip_ex(LIBSSH2_SESSION *session, const char *host,
}
/*
+ * libssh2_channel_direct_streamlocal_ex
+ *
+ * Tunnel TCP/IP connect through the SSH session to direct UNIX socket
+ */
+static LIBSSH2_CHANNEL *
+channel_direct_streamlocal(LIBSSH2_SESSION * session, const char *socket_path,
+ const char *shost, int sport)
+{
+ LIBSSH2_CHANNEL *channel;
+ unsigned char *s;
+
+ if(session->direct_state == libssh2_NB_state_idle) {
+ session->direct_host_len = strlen(socket_path);
+ session->direct_shost_len = strlen(shost);
+ session->direct_message_len =
+ session->direct_host_len + session->direct_shost_len + 12;
+
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
+ "Requesting direct-streamlocal session to %s",
+ socket_path));
+
+ s = session->direct_message =
+ LIBSSH2_ALLOC(session, session->direct_message_len);
+ if(!session->direct_message) {
+ _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for direct-streamlocal connection");
+ return NULL;
+ }
+ _libssh2_store_str(&s, socket_path, session->direct_host_len);
+ _libssh2_store_str(&s, shost, session->direct_shost_len);
+ _libssh2_store_u32(&s, sport);
+ }
+
+ channel =
+ _libssh2_channel_open(session, "direct-streamlocal@openssh.com",
+ sizeof("direct-streamlocal@openssh.com") - 1,
+ LIBSSH2_CHANNEL_WINDOW_DEFAULT,
+ LIBSSH2_CHANNEL_PACKET_DEFAULT,
+ session->direct_message,
+ session->direct_message_len);
+
+ 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;
+ }
+ /* by default we set (keep?) idle state... */
+ session->direct_state = libssh2_NB_state_idle;
+
+ LIBSSH2_FREE(session, session->direct_message);
+ session->direct_message = NULL;
+
+ return channel;
+}
+
+/*
+ * libssh2_channel_direct_streamlocal_ex
+ *
+ * Tunnel TCP/IP connect through the SSH session to direct UNIX socket
+ */
+LIBSSH2_API LIBSSH2_CHANNEL *
+libssh2_channel_direct_streamlocal_ex(LIBSSH2_SESSION * session,
+ const char *socket_path,
+ const char *shost, int sport)
+{
+ LIBSSH2_CHANNEL *ptr;
+
+ if(!session)
+ return NULL;
+
+ BLOCK_ADJUST_ERRNO(ptr, session,
+ channel_direct_streamlocal(session,
+ socket_path, shost, sport));
+ return ptr;
+}
+
+/*
* channel_forward_listen
*
* Bind a port on the remote host and listen for connections
@@ -469,19 +551,20 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host,
host = "0.0.0.0";
if(session->fwdLstn_state == libssh2_NB_state_idle) {
- session->fwdLstn_host_len = strlen(host);
+ session->fwdLstn_host_len = (uint32_t)strlen(host);
/* 14 = packet_type(1) + request_len(4) + want_replay(1) + host_len(4)
+ port(4) */
session->fwdLstn_packet_len =
- session->fwdLstn_host_len + (sizeof("tcpip-forward") - 1) + 14;
+ session->fwdLstn_host_len +
+ (uint32_t)(sizeof("tcpip-forward") - 1) + 14;
/* Zero the whole thing out */
memset(&session->fwdLstn_packet_requirev_state, 0,
sizeof(session->fwdLstn_packet_requirev_state));
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Requesting tcpip-forward session for %s:%d", host,
- port);
+ port));
s = session->fwdLstn_packet =
LIBSSH2_ALLOC(session, session->fwdLstn_packet_len);
@@ -566,10 +649,10 @@ channel_forward_listen(LIBSSH2_SESSION * session, const char *host,
listener->host[session->fwdLstn_host_len] = 0;
if(data_len >= 5 && !port) {
listener->port = _libssh2_ntohu32(data + 1);
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Dynamic tcpip-forward port "
"allocated: %d",
- listener->port);
+ listener->port));
}
else
listener->port = port;
@@ -646,9 +729,9 @@ int _libssh2_channel_forward_cancel(LIBSSH2_LISTENER *listener)
int retcode = 0;
if(listener->chanFwdCncl_state == libssh2_NB_state_idle) {
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Cancelling tcpip-forward session for %s:%d",
- listener->host, listener->port);
+ listener->host, listener->port));
s = packet = LIBSSH2_ALLOC(session, packet_len);
if(!packet) {
@@ -817,10 +900,10 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel,
memset(&channel->setenv_packet_requirev_state, 0,
sizeof(channel->setenv_packet_requirev_state));
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Setting remote environment variable: %s=%s on "
"channel %lu/%lu",
- varname, value, channel->local.id, channel->remote.id);
+ varname, value, channel->local.id, channel->remote.id));
s = channel->setenv_packet =
LIBSSH2_ALLOC(session, channel->setenv_packet_len);
@@ -876,7 +959,9 @@ static int channel_setenv(LIBSSH2_CHANNEL *channel,
}
if(rc) {
channel->setenv_state = libssh2_NB_state_idle;
- return rc;
+ return _libssh2_error(session, rc,
+ "Failed getting response for "
+ "channel-setenv");
}
else if(data_len < 1) {
channel->setenv_state = libssh2_NB_state_idle;
@@ -950,9 +1035,9 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
memset(&channel->reqPTY_packet_requirev_state, 0,
sizeof(channel->reqPTY_packet_requirev_state));
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Allocating tty on channel %lu/%lu", channel->local.id,
- channel->remote.id);
+ channel->remote.id));
s = channel->reqPTY_packet;
@@ -1021,6 +1106,164 @@ static int channel_request_pty(LIBSSH2_CHANNEL *channel,
"channel request-pty");
}
+/**
+ * channel_request_auth_agent
+ * The actual re-entrant method which requests an auth agent.
+ * */
+static int channel_request_auth_agent(LIBSSH2_CHANNEL *channel,
+ const char *request_str,
+ int request_str_len)
+{
+ LIBSSH2_SESSION *session = channel->session;
+ unsigned char *s;
+ static const unsigned char reply_codes[3] =
+ { SSH_MSG_CHANNEL_SUCCESS, SSH_MSG_CHANNEL_FAILURE, 0 };
+ int rc;
+
+ if(channel->req_auth_agent_state == libssh2_NB_state_idle) {
+ /* Only valid options are "auth-agent-req" and
+ * "auth-agent-req_at_openssh.com" so we make sure it is not
+ * actually longer than the longest possible. */
+ if(request_str_len > 26) {
+ return _libssh2_error(session, LIBSSH2_ERROR_INVAL,
+ "request_str length too large");
+ }
+
+ /*
+ * Length: 24 or 36 = packet_type(1) + channel(4) + req_len(4) +
+ * request_str (variable) + want_reply (1) */
+ channel->req_auth_agent_packet_len = 10 + request_str_len;
+
+ /* Zero out the requireev state to reset */
+ memset(&channel->req_auth_agent_requirev_state, 0,
+ sizeof(channel->req_auth_agent_requirev_state));
+
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
+ "Requesting auth agent on channel %lu/%lu",
+ channel->local.id, channel->remote.id));
+
+ /*
+ * byte SSH_MSG_CHANNEL_REQUEST
+ * uint32 recipient channel
+ * string "auth-agent-req"
+ * boolean want reply
+ * */
+ s = channel->req_auth_agent_packet;
+ *(s++) = SSH_MSG_CHANNEL_REQUEST;
+ _libssh2_store_u32(&s, channel->remote.id);
+ _libssh2_store_str(&s, (char *)request_str, request_str_len);
+ *(s++) = 0x01;
+
+ channel->req_auth_agent_state = libssh2_NB_state_created;
+ }
+
+ if(channel->req_auth_agent_state == libssh2_NB_state_created) {
+ /* Send the packet, we can use sizeof() on the packet because it
+ * is always completely filled; there are no variable length fields. */
+ rc = _libssh2_transport_send(session, channel->req_auth_agent_packet,
+ channel->req_auth_agent_packet_len,
+ NULL, 0);
+
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ _libssh2_error(session, rc,
+ "Would block sending auth-agent request");
+ return rc;
+ }
+ else if(rc) {
+ channel->req_auth_agent_state = libssh2_NB_state_idle;
+ return _libssh2_error(session, rc,
+ "Unable to send auth-agent request");
+ }
+ _libssh2_htonu32(channel->req_auth_agent_local_channel,
+ channel->local.id);
+ channel->req_auth_agent_state = libssh2_NB_state_sent;
+ }
+
+ if(channel->req_auth_agent_state == libssh2_NB_state_sent) {
+ unsigned char *data;
+ size_t data_len;
+ unsigned char code;
+
+ rc = _libssh2_packet_requirev(session, reply_codes, &data, &data_len,
+ 1, channel->req_auth_agent_local_channel,
+ 4,
+ &channel->req_auth_agent_requirev_state);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ return rc;
+ }
+ else if(rc) {
+ channel->req_auth_agent_state = libssh2_NB_state_idle;
+ return _libssh2_error(session, LIBSSH2_ERROR_PROTO,
+ "Failed to request auth-agent");
+ }
+
+ code = data[0];
+
+ LIBSSH2_FREE(session, data);
+ channel->req_auth_agent_state = libssh2_NB_state_idle;
+
+ if(code == SSH_MSG_CHANNEL_SUCCESS)
+ return 0;
+ }
+
+ return _libssh2_error(session, LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED,
+ "Unable to complete request for auth-agent");
+}
+
+/*
+ * libssh2_channel_request_auth_agent
+ *
+ * Requests that agent forwarding be enabled for the session. The
+ * request must be sent over a specific channel, which starts the agent
+ * listener on the remote side. Once the channel is closed, the agent
+ * listener continues to exist.
+ */
+LIBSSH2_API int
+libssh2_channel_request_auth_agent(LIBSSH2_CHANNEL *channel)
+{
+ int rc;
+
+ if(!channel)
+ return LIBSSH2_ERROR_BAD_USE;
+
+ rc = LIBSSH2_ERROR_CHANNEL_UNKNOWN;
+
+ /* The current RFC draft for agent forwarding says you're supposed to
+ * send "auth-agent-req," but most SSH servers out there right now
+ * actually expect "auth-agent-req@openssh.com", so we try that
+ * first. */
+ if(channel->req_auth_agent_try_state == libssh2_NB_state_idle) {
+ BLOCK_ADJUST(rc, channel->session,
+ channel_request_auth_agent(channel,
+ "auth-agent-req@openssh.com",
+ 26));
+
+ /* If we failed (but not with EAGAIN), then we move onto
+ * the next step to try another request type. */
+ if(rc != LIBSSH2_ERROR_NONE &&
+ rc != LIBSSH2_ERROR_EAGAIN)
+ channel->req_auth_agent_try_state = libssh2_NB_state_sent;
+ }
+
+ if(channel->req_auth_agent_try_state == libssh2_NB_state_sent) {
+ BLOCK_ADJUST(rc, channel->session,
+ channel_request_auth_agent(channel,
+ "auth-agent-req", 14));
+
+ /* If we failed without an EAGAIN, then move on with this
+ * state machine. */
+ if(rc != LIBSSH2_ERROR_NONE &&
+ rc != LIBSSH2_ERROR_EAGAIN)
+ channel->req_auth_agent_try_state = libssh2_NB_state_sent1;
+ }
+
+ /* If things are good, reset the try state. */
+ if(rc == LIBSSH2_ERROR_NONE)
+ channel->req_auth_agent_try_state = libssh2_NB_state_idle;
+
+ return rc;
+}
+
/*
* libssh2_channel_request_pty_ex
* Duh... Request a PTY
@@ -1059,10 +1302,10 @@ channel_request_pty_size(LIBSSH2_CHANNEL * channel, int width,
memset(&channel->reqPTY_packet_requirev_state, 0,
sizeof(channel->reqPTY_packet_requirev_state));
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
- "changing tty size on channel %lu/%lu",
- channel->local.id,
- channel->remote.id);
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
+ "changing tty size on channel %lu/%lu",
+ channel->local.id,
+ channel->remote.id));
s = channel->reqPTY_packet;
@@ -1148,13 +1391,13 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
memset(&channel->reqX11_packet_requirev_state, 0,
sizeof(channel->reqX11_packet_requirev_state));
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Requesting x11-req for channel %lu/%lu: single=%d "
"proto=%s cookie=%s screen=%d",
channel->local.id, channel->remote.id,
single_connection,
auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1",
- auth_cookie ? auth_cookie : "<random>", screen_number);
+ auth_cookie ? auth_cookie : "<random>", screen_number));
s = channel->reqX11_packet =
LIBSSH2_ALLOC(session, channel->reqX11_packet_len);
@@ -1173,7 +1416,7 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
_libssh2_store_str(&s, auth_proto ? auth_proto : "MIT-MAGIC-COOKIE-1",
proto_len);
- _libssh2_store_u32(&s, cookie_len);
+ _libssh2_store_u32(&s, (uint32_t)cookie_len);
if(auth_cookie) {
memcpy(s, auth_cookie, cookie_len);
}
@@ -1185,7 +1428,11 @@ channel_x11_req(LIBSSH2_CHANNEL *channel, int single_connection,
border */
unsigned char buffer[(LIBSSH2_X11_RANDOM_COOKIE_LEN / 2) + 1];
- _libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2);
+ if(_libssh2_random(buffer, LIBSSH2_X11_RANDOM_COOKIE_LEN / 2)) {
+ return _libssh2_error(session, LIBSSH2_ERROR_RANDGEN,
+ "Unable to get random bytes "
+ "for x11-req cookie");
+ }
for(i = 0; i < (LIBSSH2_X11_RANDOM_COOKIE_LEN / 2); i++) {
snprintf((char *)&s[i*2], 3, "%02X", buffer[i]);
}
@@ -1302,10 +1549,10 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
if(message)
channel->process_packet_len += + 4;
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"starting request(%s) on channel %lu/%lu, message=%s",
request, channel->local.id, channel->remote.id,
- message ? message : "<null>");
+ message ? message : "<null>"));
s = channel->process_packet =
LIBSSH2_ALLOC(session, channel->process_packet_len);
if(!channel->process_packet)
@@ -1319,7 +1566,7 @@ _libssh2_channel_process_startup(LIBSSH2_CHANNEL *channel,
*(s++) = 0x01;
if(message)
- _libssh2_store_u32(&s, message_len);
+ _libssh2_store_u32(&s, (uint32_t)message_len);
channel->process_state = libssh2_NB_state_created;
}
@@ -1410,7 +1657,7 @@ LIBSSH2_API void
libssh2_channel_set_blocking(LIBSSH2_CHANNEL * channel, int blocking)
{
if(channel)
- (void) _libssh2_session_set_blocking(channel->session, blocking);
+ (void)_libssh2_session_set_blocking(channel->session, blocking);
}
/*
@@ -1434,8 +1681,8 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid)
if(packet->data_len < 1) {
packet = next;
- _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
- "Unexpected packet length");
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR,
+ "Unexpected packet length"));
continue;
}
@@ -1471,11 +1718,11 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid)
size_t bytes_to_flush = packet->data_len -
packet->data_head;
- _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN,
"Flushing %d bytes of data from stream "
"%lu on channel %lu/%lu",
bytes_to_flush, packet_stream_id,
- channel->local.id, channel->remote.id);
+ channel->local.id, channel->remote.id));
/* It's one of the streams we wanted to flush */
channel->flush_refund_bytes += packet->data_len - 13;
@@ -1495,20 +1742,20 @@ _libssh2_channel_flush(LIBSSH2_CHANNEL *channel, int streamid)
}
channel->read_avail -= channel->flush_flush_bytes;
- channel->remote.window_size -= channel->flush_flush_bytes;
+ channel->remote.window_size -= (uint32_t)channel->flush_flush_bytes;
if(channel->flush_refund_bytes) {
int rc =
_libssh2_channel_receive_window_adjust(channel,
- channel->flush_refund_bytes,
- 1, NULL);
+ (uint32_t)channel->flush_refund_bytes,
+ 1, NULL);
if(rc == LIBSSH2_ERROR_EAGAIN)
return rc;
}
channel->flush_state = libssh2_NB_state_idle;
- return channel->flush_flush_bytes;
+ return (int)channel->flush_flush_bytes;
}
/*
@@ -1577,7 +1824,7 @@ libssh2_channel_get_exit_signal(LIBSSH2_CHANNEL *channel,
*exitsignal = LIBSSH2_ALLOC(session, namelen + 1);
if(!*exitsignal) {
return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
- "Unable to allocate memory for signal name");
+ "Unable to allocate memory for signal name");
}
memcpy(*exitsignal, channel->exit_signal, namelen);
(*exitsignal)[namelen] = '\0';
@@ -1634,10 +1881,10 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
if(!force
&& (adjustment + channel->adjust_queue <
LIBSSH2_CHANNEL_MINADJUST)) {
- _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN,
"Queueing %lu bytes for receive window adjustment "
"for channel %lu/%lu",
- adjustment, channel->local.id, channel->remote.id);
+ adjustment, channel->local.id, channel->remote.id));
channel->adjust_queue += adjustment;
return 0;
}
@@ -1653,10 +1900,10 @@ _libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL * channel,
channel->adjust_adjust[0] = SSH_MSG_CHANNEL_WINDOW_ADJUST;
_libssh2_htonu32(&channel->adjust_adjust[1], channel->remote.id);
_libssh2_htonu32(&channel->adjust_adjust[5], adjustment);
- _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN,
"Adjusting window %lu bytes for data on "
"channel %lu/%lu",
- adjustment, channel->local.id, channel->remote.id);
+ adjustment, channel->local.id, channel->remote.id));
channel->adjust_state = libssh2_NB_state_created;
}
@@ -1708,7 +1955,8 @@ libssh2_channel_receive_window_adjust(LIBSSH2_CHANNEL *channel,
return (unsigned long)LIBSSH2_ERROR_BAD_USE;
BLOCK_ADJUST(rc, channel->session,
- _libssh2_channel_receive_window_adjust(channel, adj,
+ _libssh2_channel_receive_window_adjust(channel,
+ (uint32_t)adj,
force, &window));
/* stupid - but this is how it was made to work before and this is just
@@ -1739,8 +1987,9 @@ libssh2_channel_receive_window_adjust2(LIBSSH2_CHANNEL *channel,
return LIBSSH2_ERROR_BAD_USE;
BLOCK_ADJUST(rc, channel->session,
- _libssh2_channel_receive_window_adjust(channel, adj, force,
- window));
+ _libssh2_channel_receive_window_adjust(channel,
+ (uint32_t)adj,
+ force, window));
return rc;
}
@@ -1748,10 +1997,10 @@ int
_libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode)
{
if(channel->extData2_state == libssh2_NB_state_idle) {
- _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN,
"Setting channel %lu/%lu handle_extended_data"
" mode to %d",
- channel->local.id, channel->remote.id, ignore_mode);
+ channel->local.id, channel->remote.id, ignore_mode));
channel->remote.extended_data_ignore_mode = (char)ignore_mode;
channel->extData2_state = libssh2_NB_state_created;
@@ -1772,7 +2021,7 @@ _libssh2_channel_extended_data(LIBSSH2_CHANNEL *channel, int ignore_mode)
}
/*
- * libssh2_channel_handle_extended_data2()
+ * libssh2_channel_handle_extended_data2
*
*/
LIBSSH2_API int
@@ -1831,19 +2080,19 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
LIBSSH2_PACKET *read_packet;
LIBSSH2_PACKET *read_next;
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"channel_read() wants %d bytes from channel %lu/%lu "
"stream #%d",
(int) buflen, channel->local.id, channel->remote.id,
- stream_id);
+ stream_id));
/* expand the receiving window first if it has become too narrow */
if((channel->read_state == libssh2_NB_state_jump1) ||
(channel->remote.window_size <
- channel->remote.window_size_initial / 4 * 3 + buflen) ) {
+ channel->remote.window_size_initial / 4 * 3 + buflen)) {
- uint32_t adjustment = channel->remote.window_size_initial + buflen -
- channel->remote.window_size;
+ uint32_t adjustment = (uint32_t)(channel->remote.window_size_initial +
+ buflen - channel->remote.window_size);
if(adjustment < LIBSSH2_CHANNEL_MINADJUST)
adjustment = LIBSSH2_CHANNEL_MINADJUST;
@@ -1884,8 +2133,13 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
if(readpkt->data_len < 5) {
read_packet = read_next;
- _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
- "Unexpected packet length");
+
+ if(readpkt->data_len != 1 ||
+ readpkt->data[0] != SSH_MSG_REQUEST_FAILURE) {
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR,
+ "Unexpected packet length"));
+ }
+
continue;
}
@@ -1923,11 +2177,11 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
unlink_packet = TRUE;
}
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"channel_read() got %d of data from %lu/%lu/%d%s",
bytes_want, channel->local.id,
channel->remote.id, stream_id,
- unlink_packet?" [ul]":"");
+ unlink_packet?" [ul]":""));
/* copy data from this struct to the target buffer */
memcpy(&buf[bytes_read],
@@ -1966,7 +2220,7 @@ ssize_t _libssh2_channel_read(LIBSSH2_CHANNEL *channel, int stream_id,
}
channel->read_avail -= bytes_read;
- channel->remote.window_size -= bytes_read;
+ channel->remote.window_size -= (uint32_t)bytes_read;
return bytes_read;
}
@@ -1989,7 +2243,7 @@ LIBSSH2_API ssize_t
libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf,
size_t buflen)
{
- int rc;
+ ssize_t rc;
unsigned long recv_window;
if(!channel)
@@ -1999,8 +2253,8 @@ libssh2_channel_read_ex(LIBSSH2_CHANNEL *channel, int stream_id, char *buf,
if(buflen > recv_window) {
BLOCK_ADJUST(rc, channel->session,
- _libssh2_channel_receive_window_adjust(channel, buflen,
- 1, NULL));
+ _libssh2_channel_receive_window_adjust(channel,
+ (uint32_t)buflen, 1, NULL));
}
BLOCK_ADJUST(rc, channel->session,
@@ -2023,7 +2277,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
uint32_t read_local_id;
read_packet = _libssh2_list_first(&session->packets);
- if(read_packet == NULL)
+ if(!read_packet)
return 0;
while(read_packet) {
@@ -2032,8 +2286,8 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
if(read_packet->data_len < 5) {
read_packet = next_packet;
- _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
- "Unexpected packet length");
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR,
+ "Unexpected packet length"));
continue;
}
@@ -2061,7 +2315,7 @@ _libssh2_channel_packet_data_len(LIBSSH2_CHANNEL * channel, int stream_id)
&& (channel->local.id == read_local_id)
&& (channel->remote.extended_data_ignore_mode
== LIBSSH2_CHANNEL_EXTENDED_DATA_MERGE))) {
- return (read_packet->data_len - read_packet->data_head);
+ return read_packet->data_len - read_packet->data_head;
}
read_packet = next_packet;
@@ -2101,15 +2355,15 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
if(channel->write_state == libssh2_NB_state_idle) {
unsigned char *s = channel->write_packet;
- _libssh2_debug(channel->session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_CONN,
"Writing %d bytes on channel %lu/%lu, stream #%d",
(int) buflen, channel->local.id, channel->remote.id,
- stream_id);
+ stream_id));
if(channel->local.close)
return _libssh2_error(channel->session,
LIBSSH2_ERROR_CHANNEL_CLOSED,
- "We've already closed this channel");
+ "We have already closed this channel");
else if(channel->local.eof)
return _libssh2_error(channel->session,
LIBSSH2_ERROR_CHANNEL_EOF_SENT,
@@ -2136,7 +2390,7 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
*/
session->socket_block_directions = LIBSSH2_SESSION_BLOCK_INBOUND;
- return (rc == LIBSSH2_ERROR_EAGAIN?rc:0);
+ return rc == LIBSSH2_ERROR_EAGAIN ? rc : 0;
}
channel->write_bufwrite = buflen;
@@ -2150,30 +2404,30 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
/* Don't exceed the remote end's limits */
/* REMEMBER local means local as the SOURCE of the data */
if(channel->write_bufwrite > channel->local.window_size) {
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Splitting write block due to %lu byte "
"window_size on %lu/%lu/%d",
channel->local.window_size, channel->local.id,
- channel->remote.id, stream_id);
+ channel->remote.id, stream_id));
channel->write_bufwrite = channel->local.window_size;
}
if(channel->write_bufwrite > channel->local.packet_size) {
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Splitting write block due to %lu byte "
"packet_size on %lu/%lu/%d",
channel->local.packet_size, channel->local.id,
- channel->remote.id, stream_id);
+ channel->remote.id, stream_id));
channel->write_bufwrite = channel->local.packet_size;
}
/* store the size here only, the buffer is passed in as-is to
_libssh2_transport_send() */
- _libssh2_store_u32(&s, channel->write_bufwrite);
+ _libssh2_store_u32(&s, (uint32_t)channel->write_bufwrite);
channel->write_packet_len = s - channel->write_packet;
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Sending %d bytes on channel %lu/%lu, stream_id=%d",
(int) channel->write_bufwrite, channel->local.id,
- channel->remote.id, stream_id);
+ channel->remote.id, stream_id));
channel->write_state = libssh2_NB_state_created;
}
@@ -2192,7 +2446,7 @@ _libssh2_channel_write(LIBSSH2_CHANNEL *channel, int stream_id,
"Unable to send channel data");
}
/* Shrink local window size */
- channel->local.window_size -= channel->write_bufwrite;
+ channel->local.window_size -= (uint32_t)channel->write_bufwrite;
wrote += channel->write_bufwrite;
@@ -2245,9 +2499,9 @@ static int channel_send_eof(LIBSSH2_CHANNEL *channel)
unsigned char packet[5]; /* packet_type(1) + channelno(4) */
int rc;
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Sending EOF on channel %lu/%lu",
- channel->local.id, channel->remote.id);
+ channel->local.id, channel->remote.id));
packet[0] = SSH_MSG_CHANNEL_EOF;
_libssh2_htonu32(packet + 1, channel->remote.id);
rc = _libssh2_transport_send(session, packet, 5, NULL, 0);
@@ -2306,8 +2560,8 @@ libssh2_channel_eof(LIBSSH2_CHANNEL * channel)
if(packet->data_len < 1) {
packet = next_packet;
- _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
- "Unexpected packet length");
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR,
+ "Unexpected packet length"));
continue;
}
@@ -2335,9 +2589,9 @@ static int channel_wait_eof(LIBSSH2_CHANNEL *channel)
int rc;
if(channel->wait_eof_state == libssh2_NB_state_idle) {
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Awaiting EOF for channel %lu/%lu", channel->local.id,
- channel->remote.id);
+ channel->remote.id));
channel->wait_eof_state = libssh2_NB_state_created;
}
@@ -2364,7 +2618,7 @@ static int channel_wait_eof(LIBSSH2_CHANNEL *channel)
else if(rc < 0) {
channel->wait_eof_state = libssh2_NB_state_idle;
return _libssh2_error(session, rc,
- "_libssh2_transport_read() bailed out!");
+ "_libssh2_transport_read() bailed out");
}
} while(1);
@@ -2409,7 +2663,7 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel)
return rc;
}
_libssh2_error(session, rc,
- "Unable to send EOF, but closing channel anyway");
+ "Unable to send EOF, but closing channel anyway");
}
}
@@ -2417,8 +2671,8 @@ int _libssh2_channel_close(LIBSSH2_CHANNEL * channel)
late for us to wait for it. Continue closing! */
if(channel->close_state == libssh2_NB_state_idle) {
- _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Closing channel %lu/%lu",
- channel->local.id, channel->remote.id);
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Closing channel %lu/%lu",
+ channel->local.id, channel->remote.id));
channel->close_packet[0] = SSH_MSG_CHANNEL_CLOSE;
_libssh2_htonu32(channel->close_packet + 1, channel->remote.id);
@@ -2486,7 +2740,7 @@ libssh2_channel_close(LIBSSH2_CHANNEL *channel)
if(!channel)
return LIBSSH2_ERROR_BAD_USE;
- BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel) );
+ BLOCK_ADJUST(rc, channel->session, _libssh2_channel_close(channel));
return rc;
}
@@ -2507,9 +2761,9 @@ static int channel_wait_closed(LIBSSH2_CHANNEL *channel)
}
if(channel->wait_closed_state == libssh2_NB_state_idle) {
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Awaiting close of channel %lu/%lu", channel->local.id,
- channel->remote.id);
+ channel->remote.id));
channel->wait_closed_state = libssh2_NB_state_created;
}
@@ -2570,9 +2824,9 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel)
assert(session);
if(channel->free_state == libssh2_NB_state_idle) {
- _libssh2_debug(session, LIBSSH2_TRACE_CONN,
+ _libssh2_debug((session, LIBSSH2_TRACE_CONN,
"Freeing channel %lu/%lu resources", channel->local.id,
- channel->remote.id);
+ channel->remote.id));
channel->free_state = libssh2_NB_state_created;
}
@@ -2604,10 +2858,10 @@ int _libssh2_channel_free(LIBSSH2_CHANNEL *channel)
/* Clear out packets meant for this channel */
_libssh2_htonu32(channel_id, channel->local.id);
while((_libssh2_packet_ask(session, SSH_MSG_CHANNEL_DATA, &data,
- &data_len, 1, channel_id, 4) >= 0)
- ||
- (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data,
- &data_len, 1, channel_id, 4) >= 0)) {
+ &data_len, 1, channel_id, 4) >= 0)
+ ||
+ (_libssh2_packet_ask(session, SSH_MSG_CHANNEL_EXTENDED_DATA, &data,
+ &data_len, 1, channel_id, 4) >= 0)) {
LIBSSH2_FREE(session, data);
}
@@ -2667,7 +2921,7 @@ libssh2_channel_free(LIBSSH2_CHANNEL *channel)
*/
LIBSSH2_API unsigned long
libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel,
- unsigned long *read_avail,
+ /* FIXME: -> size_t */ unsigned long *read_avail,
unsigned long *window_size_initial)
{
if(!channel)
@@ -2689,8 +2943,8 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel,
if(packet->data_len < 1) {
packet = next_packet;
- _libssh2_debug(channel->session, LIBSSH2_TRACE_ERROR,
- "Unexpected packet length");
+ _libssh2_debug((channel->session, LIBSSH2_TRACE_ERROR,
+ "Unexpected packet length"));
continue;
}
@@ -2707,7 +2961,7 @@ libssh2_channel_window_read_ex(LIBSSH2_CHANNEL *channel,
packet = next_packet;
}
- *read_avail = bytes_queued;
+ *read_avail = (unsigned long)bytes_queued;
}
return channel->remote.window_size;
@@ -2736,3 +2990,87 @@ libssh2_channel_window_write_ex(LIBSSH2_CHANNEL *channel,
return channel->local.window_size;
}
+
+/* A signal can be delivered to the remote process/service using the
+ following message. Some systems may not implement signals, in which
+ case they SHOULD ignore this message.
+
+ byte SSH_MSG_CHANNEL_REQUEST
+ uint32 recipient channel
+ string "signal"
+ boolean FALSE
+ string signal name (without the "SIG" prefix)
+
+ 'signal name' values will be encoded as discussed in the passage
+ describing SSH_MSG_CHANNEL_REQUEST messages using "exit-signal" in
+ this section.
+ */
+static int channel_signal(LIBSSH2_CHANNEL *channel,
+ const char *signame,
+ size_t signame_len)
+{
+ LIBSSH2_SESSION *session = channel->session;
+ int retcode = LIBSSH2_ERROR_PROTO;
+
+ if(channel->sendsignal_state == libssh2_NB_state_idle) {
+ unsigned char *s;
+
+ /* 20 = packet_type(1) + channel(4) +
+ signal_len + sizeof(signal) - 1 + want_reply(1) +
+ signame_len_len(4) */
+ channel->sendsignal_packet_len = 20 + signame_len;
+
+ s = channel->sendsignal_packet =
+ LIBSSH2_ALLOC(session, channel->sendsignal_packet_len);
+ if(!channel->sendsignal_packet)
+ return _libssh2_error(session, LIBSSH2_ERROR_ALLOC,
+ "Unable to allocate memory for "
+ "signal request");
+
+ *(s++) = SSH_MSG_CHANNEL_REQUEST;
+ _libssh2_store_u32(&s, channel->remote.id);
+ _libssh2_store_str(&s, "signal", sizeof("signal") - 1);
+ *(s++) = 0x00; /* Don't reply */
+ _libssh2_store_str(&s, signame, signame_len);
+
+ channel->sendsignal_state = libssh2_NB_state_created;
+ }
+
+ if(channel->sendsignal_state == libssh2_NB_state_created) {
+ int rc;
+
+ rc = _libssh2_transport_send(session, channel->sendsignal_packet,
+ channel->sendsignal_packet_len,
+ NULL, 0);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ _libssh2_error(session, rc, "Would block sending signal request");
+ return rc;
+ }
+ else if(rc) {
+ LIBSSH2_FREE(session, channel->sendsignal_packet);
+ channel->sendsignal_state = libssh2_NB_state_idle;
+ return _libssh2_error(session, rc, "Unable to send signal packet");
+ }
+ LIBSSH2_FREE(session, channel->sendsignal_packet);
+ retcode = LIBSSH2_ERROR_NONE;
+ }
+
+ channel->sendsignal_state = libssh2_NB_state_idle;
+
+ return retcode;
+}
+
+LIBSSH2_API int
+libssh2_channel_signal_ex(LIBSSH2_CHANNEL *channel,
+ const char *signame,
+ size_t signame_len)
+{
+ int rc;
+
+ if(!channel)
+ return LIBSSH2_ERROR_BAD_USE;
+
+ BLOCK_ADJUST(rc, channel->session,
+ channel_signal(channel, signame, signame_len));
+ return rc;
+}