diff options
Diffstat (limited to 'libs/libssh2/src/packet.c')
-rw-r--r-- | libs/libssh2/src/packet.c | 252 |
1 files changed, 174 insertions, 78 deletions
diff --git a/libs/libssh2/src/packet.c b/libs/libssh2/src/packet.c index e3ccf814d4..6da14e9fa1 100644 --- a/libs/libssh2/src/packet.c +++ b/libs/libssh2/src/packet.c @@ -71,14 +71,14 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, * Look for a matching listener */ /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - size_t packet_len = 17 + (sizeof(FwdNotReq) - 1); + size_t packet_len = 17 + strlen(FwdNotReq); unsigned char *p; LIBSSH2_LISTENER *listn = _libssh2_list_first(&session->listeners); char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; int rc; if(listen_state->state == libssh2_NB_state_idle) { - size_t offset = (sizeof("forwarded-tcpip") - 1) + 5; + size_t offset = strlen("forwarded-tcpip") + 5; size_t temp_len = 0; struct string_buf buf; buf.data = data; @@ -126,7 +126,7 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, } _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Remote received connection from %s:%ld to %s:%ld", + "Remote received connection from %s:%u to %s:%u", listen_state->shost, listen_state->sport, listen_state->host, listen_state->port)); @@ -137,8 +137,8 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, while(listn) { if((listn->port == (int) listen_state->port) && (strlen(listn->host) == listen_state->host_len) && - (memcmp (listn->host, listen_state->host, - listen_state->host_len) == 0)) { + (memcmp(listn->host, listen_state->host, + listen_state->host_len) == 0)) { /* This is our listener */ LIBSSH2_CHANNEL *channel = NULL; listen_state->channel = NULL; @@ -166,7 +166,7 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, listen_state->channel = channel; channel->session = session; - channel->channel_type_len = sizeof("forwarded-tcpip") - 1; + channel->channel_type_len = strlen("forwarded-tcpip"); channel->channel_type = LIBSSH2_ALLOC(session, channel-> channel_type_len + @@ -199,8 +199,8 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, channel->local.packet_size = listen_state->packet_size; _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Connection queued: channel %lu/%lu " - "win %lu/%lu packet %lu/%lu", + "Connection queued: channel %u/%u " + "win %u/%u packet %u/%u", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, @@ -253,7 +253,7 @@ packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; _libssh2_store_u32(&p, listen_state->sender_channel); _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, FwdNotReq, sizeof(FwdNotReq) - 1); + _libssh2_store_str(&p, FwdNotReq, strlen(FwdNotReq)); _libssh2_htonu32(p, 0); rc = _libssh2_transport_send(session, listen_state->packet, @@ -282,14 +282,14 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, { int failure_code = SSH_OPEN_CONNECT_FAILED; /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - size_t packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); + size_t packet_len = 17 + strlen(X11FwdUnAvil); unsigned char *p; LIBSSH2_CHANNEL *channel = x11open_state->channel; int rc; if(x11open_state->state == libssh2_NB_state_idle) { - size_t offset = (sizeof("x11") - 1) + 5; + size_t offset = strlen("x11") + 5; size_t temp_len = 0; struct string_buf buf; buf.data = data; @@ -339,7 +339,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, } _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "X11 Connection Received from %s:%ld on channel %lu", + "X11 Connection Received from %s:%u on channel %u", x11open_state->shost, x11open_state->sport, x11open_state->sender_channel)); @@ -357,7 +357,7 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, } channel->session = session; - channel->channel_type_len = sizeof("x11") - 1; + channel->channel_type_len = strlen("x11"); channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1); @@ -384,8 +384,8 @@ packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, channel->local.packet_size = x11open_state->packet_size; _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "X11 Connection established: channel %lu/%lu " - "win %lu/%lu packet %lu/%lu", + "X11 Connection established: channel %u/%u " + "win %u/%u packet %u/%u", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, @@ -436,7 +436,7 @@ x11_exit: *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; _libssh2_store_u32(&p, x11open_state->sender_channel); _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1); + _libssh2_store_str(&p, X11FwdUnAvil, strlen(X11FwdUnAvil)); _libssh2_htonu32(p, 0); rc = _libssh2_transport_send(session, x11open_state->packet, packet_len, @@ -464,23 +464,40 @@ packet_authagent_open(LIBSSH2_SESSION * session, { int failure_code = SSH_OPEN_CONNECT_FAILED; /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ - size_t packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); + size_t packet_len = 17 + strlen(X11FwdUnAvil); unsigned char *p; LIBSSH2_CHANNEL *channel = authagent_state->channel; int rc; + struct string_buf buf; + size_t offset = strlen("auth-agent@openssh.org") + 5; - (void)datalen; + buf.data = data; + buf.dataptr = buf.data; + buf.len = datalen; + + buf.dataptr += offset; + + if(datalen < offset) { + return _libssh2_error(session, LIBSSH2_ERROR_OUT_OF_BOUNDARY, + "Unexpected packet size"); + } if(authagent_state->state == libssh2_NB_state_idle) { - unsigned char *s = data + (sizeof("auth-agent@openssh.org") - 1) + 5; - authagent_state->sender_channel = _libssh2_ntohu32(s); - s += 4; - authagent_state->initial_window_size = _libssh2_ntohu32(s); - s += 4; - authagent_state->packet_size = _libssh2_ntohu32(s); + if(_libssh2_get_u32(&buf, &(authagent_state->sender_channel))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting channel"); + } + if(_libssh2_get_u32(&buf, &(authagent_state->initial_window_size))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting window size"); + } + if(_libssh2_get_u32(&buf, &(authagent_state->packet_size))) { + return _libssh2_error(session, LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting packet"); + } _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Auth Agent Connection Received on channel %lu", + "Auth Agent Connection Received on channel %u", authagent_state->sender_channel)); authagent_state->state = libssh2_NB_state_allocated; @@ -500,7 +517,7 @@ packet_authagent_open(LIBSSH2_SESSION * session, memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); channel->session = session; - channel->channel_type_len = sizeof("auth agent") - 1; + channel->channel_type_len = strlen("auth agent"); channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1); @@ -528,7 +545,7 @@ packet_authagent_open(LIBSSH2_SESSION * session, _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Auth Agent Connection established: channel " - "%lu/%lu win %lu/%lu packet %lu/%lu", + "%u/%u win %u/%u packet %u/%u", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, @@ -584,7 +601,7 @@ authagent_exit: *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; _libssh2_store_u32(&p, authagent_state->sender_channel); _libssh2_store_u32(&p, failure_code); - _libssh2_store_str(&p, AuthAgentUnavail, sizeof(AuthAgentUnavail) - 1); + _libssh2_store_str(&p, AuthAgentUnavail, strlen(AuthAgentUnavail)); _libssh2_htonu32(p, 0); rc = _libssh2_transport_send(session, authagent_state->packet, packet_len, @@ -607,14 +624,13 @@ authagent_exit: * layer when it has received a packet. * * 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. - * The only exception is when the return code is LIBSSH2_ERROR_EAGAIN. + * will be freed unless return the code is LIBSSH2_ERROR_EAGAIN. * * This function will always be called with 'datalen' greater than zero. */ int _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, - size_t datalen, int macstate) + size_t datalen, int macstate, uint32_t seq) { int rc = 0; unsigned char *message = NULL; @@ -628,8 +644,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, switch(session->packAdd_state) { case libssh2_NB_state_idle: _libssh2_debug((session, LIBSSH2_TRACE_TRANS, - "Packet type %d received, length=%d", - (int) msg, (int) datalen)); + "Packet type %u received, length=%ld", + (unsigned int) msg, (long) datalen)); if((macstate == LIBSSH2_MAC_INVALID) && (!session->macerror || @@ -659,6 +675,70 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, break; } + if(session->state & LIBSSH2_STATE_INITIAL_KEX) { + if(msg == SSH_MSG_KEXINIT) { + if(!session->kex_strict) { + if(datalen < 17) { + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return _libssh2_error(session, + LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Data too short extracting kex"); + } + else { + const unsigned char *strict = + (unsigned char *)"kex-strict-s-v00@openssh.com"; + struct string_buf buf; + unsigned char *algs = NULL; + size_t algs_len = 0; + + buf.data = (unsigned char *)data; + buf.dataptr = buf.data; + buf.len = datalen; + buf.dataptr += 17; /* advance past type and cookie */ + + if(_libssh2_get_string(&buf, &algs, &algs_len)) { + LIBSSH2_FREE(session, data); + session->packAdd_state = libssh2_NB_state_idle; + return _libssh2_error(session, + LIBSSH2_ERROR_BUFFER_TOO_SMALL, + "Algs too short"); + } + + if(algs_len == 0 || + _libssh2_kex_agree_instr(algs, algs_len, strict, 28)) { + session->kex_strict = 1; + } + } + } + + if(session->kex_strict && seq) { + LIBSSH2_FREE(session, data); + session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; + session->packAdd_state = libssh2_NB_state_idle; + libssh2_session_disconnect(session, "strict KEX violation: " + "KEXINIT was not the first packet"); + + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "strict KEX violation: " + "KEXINIT was not the first packet"); + } + } + + if(session->kex_strict && session->fullpacket_required_type && + session->fullpacket_required_type != msg) { + LIBSSH2_FREE(session, data); + session->socket_state = LIBSSH2_SOCKET_DISCONNECTED; + session->packAdd_state = libssh2_NB_state_idle; + libssh2_session_disconnect(session, "strict KEX violation: " + "unexpected packet type"); + + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "strict KEX violation: " + "unexpected packet type"); + } + } + if(session->packAdd_state == libssh2_NB_state_allocated) { /* A couple exceptions to the packet adding rule: */ switch(msg) { @@ -795,7 +875,8 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, _libssh2_debug((session, LIBSSH2_TRACE_KEX, "Server to Client extension %.*s: %.*s", - name_len, name, value_len, value)); + (int)name_len, name, + (int)value_len, value)); } if(name_len == 15 && @@ -843,7 +924,7 @@ _libssh2_packet_add(LIBSSH2_SESSION * session, unsigned char *data, _libssh2_debug((session, LIBSSH2_TRACE_CONN, "Received global request type %.*s (wr %X)", - len, data + 5, want_reply)); + (int)len, data + 5, want_reply)); } @@ -872,7 +953,7 @@ libssh2_packet_add_jump_point5: /* streamid(4) */ data_head += 4; - /* fall-through */ + LIBSSH2_FALLTHROUGH(); /* byte SSH_MSG_CHANNEL_DATA @@ -903,8 +984,8 @@ libssh2_packet_add_jump_point5: stream_id = _libssh2_ntohu32(data + 5); _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "%d bytes packet_add() for %lu/%lu/%lu", - (int) (datalen - data_head), + "%ld bytes packet_add() for %u/%u/%u", + (long) (datalen - data_head), channelp->local.id, channelp->remote.id, stream_id)); @@ -917,8 +998,8 @@ libssh2_packet_add_jump_point5: LIBSSH2_FREE(session, data); _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Ignoring extended data and refunding %d bytes", - (int) (datalen - 13))); + "Ignoring extended data and refunding %ld bytes", + (long) (datalen - 13))); if(channelp->read_avail + datalen - data_head >= channelp->remote.window_size) datalen = channelp->remote.window_size - @@ -927,11 +1008,11 @@ libssh2_packet_add_jump_point5: channelp->remote.window_size -= (uint32_t)(datalen - data_head); _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "shrinking window size by %lu bytes to %lu, " - "read_avail %lu", - datalen - data_head, + "shrinking window size by %ld bytes to %u, " + "read_avail %ld", + (long) (datalen - data_head), channelp->remote.window_size, - channelp->read_avail)); + (long) channelp->read_avail)); session->packAdd_channelp = channelp; @@ -993,10 +1074,10 @@ libssh2_packet_add_jump_point1: channelp->read_avail += datalen - data_head; _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "increasing read_avail by %lu bytes to %lu/%lu", + "increasing read_avail by %ld bytes to %ld/%u", (long)(datalen - data_head), (long)channelp->read_avail, - (long)channelp->remote.window_size)); + channelp->remote.window_size)); break; @@ -1016,7 +1097,7 @@ libssh2_packet_add_jump_point1: else { _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "EOF received for channel %lu/%lu", + "EOF received for channel %u/%u", channelp->local.id, channelp->remote.id)); channelp->remote.eof = 1; @@ -1044,43 +1125,45 @@ libssh2_packet_add_jump_point1: _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Channel %d received request type %.*s (wr %X)", - channel, len, data + 9, want_reply)); + "Channel %u received request type %.*s (wr %X)", + channel, (int)len, data + 9, want_reply)); - if(len == sizeof("exit-status") - 1 - && (sizeof("exit-status") - 1 + 9) <= datalen + if(len == strlen("exit-status") + && (strlen("exit-status") + 9) <= datalen && !memcmp("exit-status", data + 9, - sizeof("exit-status") - 1)) { + strlen("exit-status"))) { /* we've got "exit-status" packet. Set the session value */ if(datalen >= 20) channelp = _libssh2_channel_locate(session, channel); - if(channelp && (sizeof("exit-status") + 13) <= datalen) { + if(channelp && (strlen("exit-status") + 14) <= datalen) { channelp->exit_status = - _libssh2_ntohu32(data + 9 + sizeof("exit-status")); + _libssh2_ntohu32(data + 10 + + strlen("exit-status")); _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Exit status %lu received for " - "channel %lu/%lu", + "Exit status %d received for " + "channel %u/%u", channelp->exit_status, channelp->local.id, channelp->remote.id)); } } - else if(len == sizeof("exit-signal") - 1 - && (sizeof("exit-signal") - 1 + 9) <= datalen + else if(len == strlen("exit-signal") + && (strlen("exit-signal") + 9) <= datalen && !memcmp("exit-signal", data + 9, - sizeof("exit-signal") - 1)) { + strlen("exit-signal"))) { /* command terminated due to signal */ if(datalen >= 20) channelp = _libssh2_channel_locate(session, channel); - if(channelp && (sizeof("exit-signal") + 13) <= datalen) { + if(channelp && (strlen("exit-signal") + 14) <= datalen) { /* set signal name (without SIG prefix) */ uint32_t namelen = - _libssh2_ntohu32(data + 9 + sizeof("exit-signal")); + _libssh2_ntohu32(data + 10 + + strlen("exit-signal")); if(namelen <= UINT_MAX - 1) { channelp->exit_signal = @@ -1093,15 +1176,15 @@ libssh2_packet_add_jump_point1: if(!channelp->exit_signal) rc = _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "memory for signal name"); - else if((sizeof("exit-signal") + 13 + namelen <= + else if((strlen("exit-signal") + 14 + namelen <= datalen)) { memcpy(channelp->exit_signal, - data + 13 + sizeof("exit-signal"), namelen); + data + 14 + strlen("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", + "channel %u/%u", channelp->exit_signal, channelp->local.id, channelp->remote.id)); @@ -1142,7 +1225,7 @@ libssh2_packet_add_jump_point4: return 0; } _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Close received for channel %lu/%lu", + "Close received for channel %u/%u", channelp->local.id, channelp->remote.id)); @@ -1164,12 +1247,12 @@ libssh2_packet_add_jump_point4: case SSH_MSG_CHANNEL_OPEN: if(datalen < 17) ; - else if((datalen >= (sizeof("forwarded-tcpip") + 4)) && - ((sizeof("forwarded-tcpip") - 1) == + else if((datalen >= (strlen("forwarded-tcpip") + 5)) && + (strlen("forwarded-tcpip") == _libssh2_ntohu32(data + 1)) && (memcmp(data + 5, "forwarded-tcpip", - sizeof("forwarded-tcpip") - 1) == 0)) { + strlen("forwarded-tcpip")) == 0)) { /* init the state struct */ memset(&session->packAdd_Qlstn_state, 0, @@ -1180,9 +1263,9 @@ libssh2_packet_add_jump_point2: rc = packet_queue_listener(session, data, datalen, &session->packAdd_Qlstn_state); } - else if((datalen >= (sizeof("x11") + 4)) && - ((sizeof("x11") - 1) == _libssh2_ntohu32(data + 1)) && - (memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) { + else if((datalen >= (strlen("x11") + 5)) && + ((strlen("x11")) == _libssh2_ntohu32(data + 1)) && + (memcmp(data + 5, "x11", strlen("x11")) == 0)) { /* init the state struct */ memset(&session->packAdd_x11open_state, 0, @@ -1193,11 +1276,11 @@ libssh2_packet_add_jump_point3: rc = packet_x11_open(session, data, datalen, &session->packAdd_x11open_state); } - else if((datalen >= (sizeof("auth-agent@openssh.com") + 4)) && - ((sizeof("auth-agent@openssh.com") - 1) == + else if((datalen >= (strlen("auth-agent@openssh.com") + 5)) && + (strlen("auth-agent@openssh.com") == _libssh2_ntohu32(data + 1)) && (memcmp(data + 5, "auth-agent@openssh.com", - sizeof("auth-agent@openssh.com") - 1) == 0)) { + strlen("auth-agent@openssh.com")) == 0)) { /* init the state struct */ memset(&session->packAdd_authagent_state, 0, @@ -1232,8 +1315,8 @@ libssh2_packet_add_jump_authagent: channelp->local.window_size += bytestoadd; _libssh2_debug((session, LIBSSH2_TRACE_CONN, - "Window adjust for channel %lu/%lu, " - "adding %lu bytes, new window_size=%lu", + "Window adjust for channel %u/%u, " + "adding %u bytes, new window_size=%u", channelp->local.id, channelp->remote.id, bytestoadd, @@ -1325,7 +1408,8 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, LIBSSH2_PACKET *packet = _libssh2_list_first(&session->packets); _libssh2_debug((session, LIBSSH2_TRACE_TRANS, - "Looking for packet of type: %d", (int) packet_type)); + "Looking for packet of type: %u", + (unsigned int)packet_type)); while(packet) { if(packet->data[0] == packet_type @@ -1343,6 +1427,15 @@ _libssh2_packet_ask(LIBSSH2_SESSION * session, unsigned char packet_type, return 0; } + else if(session->kex_strict && + (session->state & LIBSSH2_STATE_INITIAL_KEX)) { + libssh2_session_disconnect(session, "strict KEX violation: " + "unexpected packet type"); + + return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_DISCONNECT, + "strict KEX violation: " + "unexpected packet type"); + } packet = _libssh2_list_next(&packet->node); } return -1; @@ -1404,7 +1497,10 @@ _libssh2_packet_require(LIBSSH2_SESSION * session, unsigned char packet_type, } while(session->socket_state == LIBSSH2_SOCKET_CONNECTED) { - int ret = _libssh2_transport_read(session); + int ret; + session->fullpacket_required_type = packet_type; + ret = _libssh2_transport_read(session); + session->fullpacket_required_type = 0; if(ret == LIBSSH2_ERROR_EAGAIN) return ret; else if(ret < 0) { |