/* {{{ libssh2_packet_queue_listener * Queue a connection request for a listener */ inline int libssh2_packet_queue_listener(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen) { /* Look for a matching listener */ unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5; unsigned long packet_len = 17 + (sizeof("Forward not requested") - 1); unsigned char *p, packet[17 + (sizeof("Forward not requested") - 1)]; /* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ LIBSSH2_LISTENER *l = session->listeners; char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */ unsigned long sender_channel, initial_window_size, packet_size; unsigned char *host, *shost; unsigned long port, sport, host_len, shost_len; sender_channel = libssh2_ntohu32(s); s += 4; initial_window_size = libssh2_ntohu32(s); s += 4; packet_size = libssh2_ntohu32(s); s += 4; host_len = libssh2_ntohu32(s); s += 4; host = s; s += host_len; port = libssh2_ntohu32(s); s += 4; shost_len = libssh2_ntohu32(s); s += 4; shost = s; s += shost_len; sport = libssh2_ntohu32(s); s += 4; #ifdef LIBSSH2_DEBUG_CONNECTION _libssh2_debug(session, LIBSSH2_DBG_CONN, "Remote received connection from %s:%ld to %s:%ld", shost, sport, host, port); #endif while (l) { if ((l->port == port) && (strlen(l->host) == host_len) && (memcmp(l->host, host, host_len) == 0)) { /* This is our listener */ LIBSSH2_CHANNEL *channel, *last_queued = l->queue; if (l->queue_maxsize && (l->queue_maxsize <= l->queue_size)) { /* Queue is full */ failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ #ifdef LIBSSH2_DEBUG_CONNECTION _libssh2_debug(session, LIBSSH2_DBG_CONN, "Listener queue full, ignoring"); #endif break; } channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); if (!channel) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0); failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ break; } memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); channel->session = session; channel->channel_type_len = sizeof("forwarded-tcpip") - 1; channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1); if (!channel->channel_type) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0); LIBSSH2_FREE(session, channel); failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ break; } memcpy(channel->channel_type, "forwarded-tcpip", channel->channel_type_len + 1); channel->remote.id = sender_channel; 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; channel->local.id = libssh2_channel_nextid(session); channel->local.window_size_initial = initial_window_size; channel->local.window_size = initial_window_size; channel->local.packet_size = packet_size; #ifdef LIBSSH2_DEBUG_CONNECTION _libssh2_debug(session, LIBSSH2_DBG_CONN, "Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, channel->remote.packet_size); #endif p = packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; libssh2_htonu32(p, channel->remote.id); p += 4; libssh2_htonu32(p, channel->local.id); p += 4; libssh2_htonu32(p, channel->remote.window_size_initial); p += 4; libssh2_htonu32(p, channel->remote.packet_size); p += 4; if (libssh2_packet_write(session, packet, 17)) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0); return -1; } /* Link the channel into the end of the queue list */ if (!last_queued) { l->queue = channel; return 0; } while (last_queued->next) last_queued = last_queued->next; last_queued->next = channel; channel->prev = last_queued; l->queue_size++; return 0; } l = l->next; } /* We're not listening to you */ { p = packet; *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; libssh2_htonu32(p, sender_channel); p += 4; libssh2_htonu32(p, failure_code); p += 4; libssh2_htonu32(p, sizeof("Forward not requested") - 1); p += 4; memcpy(s, "Forward not requested", sizeof("Forward not requested") - 1); p += sizeof("Forward not requested") - 1; libssh2_htonu32(p, 0); if (libssh2_packet_write(session, packet, packet_len)) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0); return -1; } return 0; } }
/* {{{ libssh2_packet_queue_listener * Queue a connection request for a listener */ static inline int libssh2_packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, unsigned long datalen, packet_queue_listener_state_t * listen_state) { /* * Look for a matching listener */ unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5; /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ unsigned long packet_len = 17 + (sizeof(FwdNotReq) - 1); unsigned char *p; LIBSSH2_LISTENER *listen = session->listeners; char failure_code = 1; /* SSH_OPEN_ADMINISTRATIVELY_PROHIBITED */ int rc; (void) datalen; if (listen_state->state == libssh2_NB_state_idle) { listen_state->sender_channel = libssh2_ntohu32(s); s += 4; listen_state->initial_window_size = libssh2_ntohu32(s); s += 4; listen_state->packet_size = libssh2_ntohu32(s); s += 4; listen_state->host_len = libssh2_ntohu32(s); s += 4; listen_state->host = s; s += listen_state->host_len; listen_state->port = libssh2_ntohu32(s); s += 4; listen_state->shost_len = libssh2_ntohu32(s); s += 4; listen_state->shost = s; s += listen_state->shost_len; listen_state->sport = libssh2_ntohu32(s); s += 4; _libssh2_debug(session, LIBSSH2_DBG_CONN, "Remote received connection from %s:%ld to %s:%ld", listen_state->shost, listen_state->sport, listen_state->host, listen_state->port); listen_state->state = libssh2_NB_state_allocated; } if (listen_state->state != libssh2_NB_state_sent) { while (listen) { if ((listen->port == (int) listen_state->port) && (strlen(listen->host) == listen_state->host_len) && (memcmp (listen->host, listen_state->host, listen_state->host_len) == 0)) { /* This is our listener */ LIBSSH2_CHANNEL *channel, *last_queued = listen->queue; last_queued = listen->queue; if (listen_state->state == libssh2_NB_state_allocated) { if (listen->queue_maxsize && (listen->queue_maxsize <= listen->queue_size)) { /* Queue is full */ failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ _libssh2_debug(session, LIBSSH2_DBG_CONN, "Listener queue full, ignoring"); listen_state->state = libssh2_NB_state_sent; break; } channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); if (!channel) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0); failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ listen_state->state = libssh2_NB_state_sent; break; } memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); channel->session = session; channel->channel_type_len = sizeof("forwarded-tcpip") - 1; channel->channel_type = LIBSSH2_ALLOC(session, channel-> channel_type_len + 1); if (!channel->channel_type) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0); LIBSSH2_FREE(session, channel); failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ listen_state->state = libssh2_NB_state_sent; break; } memcpy(channel->channel_type, "forwarded-tcpip", channel->channel_type_len + 1); channel->remote.id = listen_state->sender_channel; 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; channel->local.id = libssh2_channel_nextid(session); channel->local.window_size_initial = listen_state->initial_window_size; channel->local.window_size = listen_state->initial_window_size; channel->local.packet_size = listen_state->packet_size; _libssh2_debug(session, LIBSSH2_DBG_CONN, "Connection queued: channel %lu/%lu win %lu/%lu packet %lu/%lu", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, channel->remote.packet_size); p = listen_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; libssh2_htonu32(p, channel->remote.id); p += 4; libssh2_htonu32(p, channel->local.id); p += 4; libssh2_htonu32(p, channel->remote.window_size_initial); p += 4; libssh2_htonu32(p, channel->remote.packet_size); p += 4; listen_state->state = libssh2_NB_state_created; } if (listen_state->state == libssh2_NB_state_created) { rc = libssh2_packet_write(session, listen_state->packet, 17); if (rc == PACKET_EAGAIN) { return PACKET_EAGAIN; } else if (rc) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0); listen_state->state = libssh2_NB_state_idle; return -1; } /* Link the channel into the end of the queue list */ if (!last_queued) { listen->queue = channel; listen_state->state = libssh2_NB_state_idle; return 0; } while (last_queued->next) { last_queued = last_queued->next; } last_queued->next = channel; channel->prev = last_queued; listen->queue_size++; listen_state->state = libssh2_NB_state_idle; return 0; } } listen = listen->next; } listen_state->state = libssh2_NB_state_sent; } /* We're not listening to you */ { p = listen_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; libssh2_htonu32(p, listen_state->sender_channel); p += 4; libssh2_htonu32(p, failure_code); p += 4; libssh2_htonu32(p, sizeof(FwdNotReq) - 1); p += 4; memcpy(s, FwdNotReq, sizeof(FwdNotReq) - 1); p += sizeof(FwdNotReq) - 1; libssh2_htonu32(p, 0); rc = libssh2_packet_write(session, listen_state->packet, packet_len); if (rc == PACKET_EAGAIN) { return PACKET_EAGAIN; } else if (rc) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0); listen_state->state = libssh2_NB_state_idle; return -1; } listen_state->state = libssh2_NB_state_idle; return 0; } }
/* {{{ libssh2_packet_x11_open * Accept a forwarded X11 connection */ inline int libssh2_packet_x11_open(LIBSSH2_SESSION *session, unsigned char *data, unsigned long datalen) { int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */ unsigned char *s = data + (sizeof("x11") - 1) + 5; unsigned long packet_len = 17 + (sizeof("X11 Forward Unavailable") - 1); unsigned char *p, packet[17 + (sizeof("X11 Forward Unavailable") - 1)]; /* packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ LIBSSH2_CHANNEL *channel; unsigned long sender_channel, initial_window_size, packet_size; unsigned char *shost; unsigned long sport, shost_len; sender_channel = libssh2_ntohu32(s); s += 4; initial_window_size = libssh2_ntohu32(s); s += 4; packet_size = libssh2_ntohu32(s); s += 4; shost_len = libssh2_ntohu32(s); s += 4; shost = s; s += shost_len; sport = libssh2_ntohu32(s); s += 4; #ifdef LIBSSH2_DEBUG_CONNECTION _libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection Received from %s:%ld on channel %lu", shost, sport, sender_channel); #endif if (session->x11) { channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); if (!channel) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0); failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ goto x11_exit; } memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); channel->session = session; channel->channel_type_len = sizeof("x11") - 1; channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1); if (!channel->channel_type) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0); LIBSSH2_FREE(session, channel); failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ goto x11_exit; } memcpy(channel->channel_type, "x11", channel->channel_type_len + 1); channel->remote.id = sender_channel; 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; channel->local.id = libssh2_channel_nextid(session); channel->local.window_size_initial = initial_window_size; channel->local.window_size = initial_window_size; channel->local.packet_size = packet_size; #ifdef LIBSSH2_DEBUG_CONNECTION _libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, channel->remote.packet_size); #endif p = packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; libssh2_htonu32(p, channel->remote.id); p += 4; libssh2_htonu32(p, channel->local.id); p += 4; libssh2_htonu32(p, channel->remote.window_size_initial); p += 4; libssh2_htonu32(p, channel->remote.packet_size); p += 4; if (libssh2_packet_write(session, packet, 17)) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0); return -1; } /* Link the channel into the session */ if (session->channels.tail) { session->channels.tail->next = channel; channel->prev = session->channels.tail; } else { session->channels.head = channel; channel->prev = NULL; } channel->next = NULL; session->channels.tail = channel; /* Pass control to the callback, they may turn right around and free the channel, or actually use it */ LIBSSH2_X11_OPEN(channel, shost, sport); return 0; } else { failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ } x11_exit: p = packet; *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; libssh2_htonu32(p, sender_channel); p += 4; libssh2_htonu32(p, failure_code); p += 4; libssh2_htonu32(p, sizeof("X11 Forward Unavailable") - 1); p += 4; memcpy(s, "X11 Forward Unavailable", sizeof("X11 Forward Unavailable") - 1); p += sizeof("X11 Forward Unavailable") - 1; libssh2_htonu32(p, 0); if (libssh2_packet_write(session, packet, packet_len)) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0); return -1; } return 0; }
/* {{{ libssh2_packet_x11_open * Accept a forwarded X11 connection */ static inline int libssh2_packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, unsigned long datalen, packet_x11_open_state_t * x11open_state) { int failure_code = 2; /* SSH_OPEN_CONNECT_FAILED */ unsigned char *s = data + (sizeof("x11") - 1) + 5; /* 17 = packet_type(1) + channel(4) + reason(4) + descr(4) + lang(4) */ unsigned long packet_len = 17 + (sizeof(X11FwdUnAvil) - 1); unsigned char *p; LIBSSH2_CHANNEL *channel; int rc; (void) datalen; if (x11open_state->state == libssh2_NB_state_idle) { x11open_state->sender_channel = libssh2_ntohu32(s); s += 4; x11open_state->initial_window_size = libssh2_ntohu32(s); s += 4; x11open_state->packet_size = libssh2_ntohu32(s); s += 4; x11open_state->shost_len = libssh2_ntohu32(s); s += 4; x11open_state->shost = s; s += x11open_state->shost_len; x11open_state->sport = libssh2_ntohu32(s); s += 4; _libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection Received from %s:%ld on channel %lu", x11open_state->shost, x11open_state->sport, x11open_state->sender_channel); x11open_state->state = libssh2_NB_state_allocated; } if (session->x11) { if (x11open_state->state == libssh2_NB_state_allocated) { channel = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_CHANNEL)); if (!channel) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0); failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ goto x11_exit; } memset(channel, 0, sizeof(LIBSSH2_CHANNEL)); channel->session = session; channel->channel_type_len = sizeof("x11") - 1; channel->channel_type = LIBSSH2_ALLOC(session, channel->channel_type_len + 1); if (!channel->channel_type) { libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for new connection", 0); LIBSSH2_FREE(session, channel); failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ goto x11_exit; } memcpy(channel->channel_type, "x11", channel->channel_type_len + 1); channel->remote.id = x11open_state->sender_channel; 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; channel->local.id = libssh2_channel_nextid(session); channel->local.window_size_initial = x11open_state->initial_window_size; channel->local.window_size = x11open_state->initial_window_size; channel->local.packet_size = x11open_state->packet_size; _libssh2_debug(session, LIBSSH2_DBG_CONN, "X11 Connection established: channel %lu/%lu win %lu/%lu packet %lu/%lu", channel->local.id, channel->remote.id, channel->local.window_size, channel->remote.window_size, channel->local.packet_size, channel->remote.packet_size); p = x11open_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_CONFIRMATION; libssh2_htonu32(p, channel->remote.id); p += 4; libssh2_htonu32(p, channel->local.id); p += 4; libssh2_htonu32(p, channel->remote.window_size_initial); p += 4; libssh2_htonu32(p, channel->remote.packet_size); p += 4; x11open_state->state = libssh2_NB_state_created; } if (x11open_state->state == libssh2_NB_state_created) { rc = libssh2_packet_write(session, x11open_state->packet, 17); if (rc == PACKET_EAGAIN) { return PACKET_EAGAIN; } else if (rc) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open confirmation", 0); x11open_state->state = libssh2_NB_state_idle; return -1; } /* Link the channel into the session */ if (session->channels.tail) { session->channels.tail->next = channel; channel->prev = session->channels.tail; } else { session->channels.head = channel; channel->prev = NULL; } channel->next = NULL; session->channels.tail = channel; /* * Pass control to the callback, they may turn right around and * free the channel, or actually use it */ LIBSSH2_X11_OPEN(channel, (char *) x11open_state->shost, x11open_state->sport); x11open_state->state = libssh2_NB_state_idle; return 0; } } else { failure_code = 4; /* SSH_OPEN_RESOURCE_SHORTAGE */ } x11_exit: p = x11open_state->packet; *(p++) = SSH_MSG_CHANNEL_OPEN_FAILURE; libssh2_htonu32(p, x11open_state->sender_channel); p += 4; libssh2_htonu32(p, failure_code); p += 4; libssh2_htonu32(p, sizeof(X11FwdUnAvil) - 1); p += 4; memcpy(s, X11FwdUnAvil, sizeof(X11FwdUnAvil) - 1); p += sizeof(X11FwdUnAvil) - 1; libssh2_htonu32(p, 0); rc = libssh2_packet_write(session, x11open_state->packet, packet_len); if (rc == PACKET_EAGAIN) { return PACKET_EAGAIN; } else if (rc) { libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send open failure", 0); x11open_state->state = libssh2_NB_state_idle; return -1; } x11open_state->state = libssh2_NB_state_idle; return 0; }