/* * packet_x11_open * * Accept a forwarded X11 connection */ static inline int packet_x11_open(LIBSSH2_SESSION * session, unsigned char *data, unsigned long datalen, packet_x11_open_state_t *x11open_state) { int failure_code = SSH_OPEN_CONNECT_FAILED; /* 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 = x11open_state->channel; int rc; (void) datalen; if (x11open_state->state == libssh2_NB_state_idle) { unsigned char *s = data + (sizeof("x11") - 1) + 5; 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); _libssh2_debug(session, LIBSSH2_TRACE_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_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); if (!channel) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "allocate a channel for new connection"); failure_code = SSH_OPEN_RESOURCE_SHORTAGE; goto x11_exit; } 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, "allocate a channel for new connection"); LIBSSH2_FREE(session, channel); failure_code = 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_TRACE_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_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); x11open_state->state = libssh2_NB_state_created; } if (x11open_state->state == libssh2_NB_state_created) { rc = _libssh2_transport_send(session, x11open_state->packet, 17, NULL, 0); if (rc == LIBSSH2_ERROR_EAGAIN) { return rc; } else if (rc) { x11open_state->state = libssh2_NB_state_idle; return _libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send channel open " "confirmation"); } /* Link the channel into the session */ _libssh2_list_add(&session->channels, &channel->node); /* * 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 = SSH_OPEN_RESOURCE_SHORTAGE; /* fall-trough */ x11_exit: p = x11open_state->packet; *(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_htonu32(p, 0); rc = _libssh2_transport_send(session, x11open_state->packet, packet_len, NULL, 0); if (rc == LIBSSH2_ERROR_EAGAIN) { return rc; } else if (rc) { x11open_state->state = libssh2_NB_state_idle; return _libssh2_error(session, rc, "Unable to send open failure"); } x11open_state->state = libssh2_NB_state_idle; return 0; }
/* * libssh2_packet_queue_listener * * Queue a connection request for a listener */ static inline int packet_queue_listener(LIBSSH2_SESSION * session, unsigned char *data, unsigned long datalen, packet_queue_listener_state_t *listen_state) { /* * Look for a matching listener */ /* 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 *listn = _libssh2_list_first(&session->listeners); char failure_code = SSH_OPEN_ADMINISTRATIVELY_PROHIBITED; int rc; (void) datalen; if (listen_state->state == libssh2_NB_state_idle) { unsigned char *s = data + (sizeof("forwarded-tcpip") - 1) + 5; 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); _libssh2_debug(session, LIBSSH2_TRACE_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 (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)) { /* This is our listener */ LIBSSH2_CHANNEL *channel = NULL; listen_state->channel = NULL; if (listen_state->state == libssh2_NB_state_allocated) { if (listn->queue_maxsize && (listn->queue_maxsize <= listn->queue_size)) { /* Queue is full */ failure_code = SSH_OPEN_RESOURCE_SHORTAGE; _libssh2_debug(session, LIBSSH2_TRACE_CONN, "Listener queue full, ignoring"); listen_state->state = libssh2_NB_state_sent; break; } channel = LIBSSH2_CALLOC(session, sizeof(LIBSSH2_CHANNEL)); if (!channel) { _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a channel for " "new connection"); failure_code = SSH_OPEN_RESOURCE_SHORTAGE; listen_state->state = libssh2_NB_state_sent; break; } listen_state->channel = 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"); LIBSSH2_FREE(session, channel); failure_code = 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_TRACE_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_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); listen_state->state = libssh2_NB_state_created; } if (listen_state->state == libssh2_NB_state_created) { rc = _libssh2_transport_send(session, listen_state->packet, 17, NULL, 0); if (rc == LIBSSH2_ERROR_EAGAIN) return rc; else if (rc) { listen_state->state = libssh2_NB_state_idle; return _libssh2_error(session, rc, "Unable to send channel " "open confirmation"); } /* Link the channel into the end of the queue list */ if (listen_state->channel) { _libssh2_list_add(&listn->queue, &listen_state->channel->node); listn->queue_size++; } listen_state->state = libssh2_NB_state_idle; return 0; } } listn = _libssh2_list_next(&listn->node); } listen_state->state = libssh2_NB_state_sent; } /* We're not listening to you */ p = listen_state->packet; *(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_htonu32(p, 0); rc = _libssh2_transport_send(session, listen_state->packet, packet_len, NULL, 0); if (rc == LIBSSH2_ERROR_EAGAIN) { return rc; } else if (rc) { listen_state->state = libssh2_NB_state_idle; return _libssh2_error(session, rc, "Unable to send open failure"); } listen_state->state = libssh2_NB_state_idle; return 0; }
static int agent_sign(LIBSSH2_SESSION *session, unsigned char **sig, size_t *sig_len, const unsigned char *data, size_t data_len, void **abstract) { LIBSSH2_AGENT *agent = (LIBSSH2_AGENT *) (*abstract); agent_transaction_ctx_t transctx = &agent->transctx; struct agent_publickey *identity = agent->identity; ssize_t len = 1 + 4 + identity->external.blob_len + 4 + data_len + 4; ssize_t method_len; unsigned char *s; int rc; /* Create a request to sign the data */ if (transctx->state == agent_NB_state_init) { s = transctx->request = LIBSSH2_ALLOC(session, len); if (!transctx->request) return _libssh2_error(session, LIBSSH2_ERROR_ALLOC, "out of memory"); *s++ = SSH2_AGENTC_SIGN_REQUEST; /* key blob */ _libssh2_store_str(&s, (const char *)identity->external.blob, identity->external.blob_len); /* data */ _libssh2_store_str(&s, (const char *)data, data_len); /* flags */ _libssh2_store_u32(&s, 0); transctx->request_len = s - transctx->request; transctx->state = agent_NB_state_request_created; } /* Make sure to be re-called as a result of EAGAIN. */ if (*transctx->request != SSH2_AGENTC_SIGN_REQUEST) return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, "illegal request"); if (!agent->ops) /* if no agent has been connected, bail out */ return _libssh2_error(session, LIBSSH2_ERROR_BAD_USE, "agent not connected"); rc = agent->ops->transact(agent, transctx); if (rc) { goto error; } LIBSSH2_FREE(session, transctx->request); transctx->request = NULL; len = transctx->response_len; s = transctx->response; len--; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } if (*s != SSH2_AGENT_SIGN_RESPONSE) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } s++; /* Skip the entire length of the signature */ len -= 4; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } s += 4; /* Skip signing method */ len -= 4; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } method_len = _libssh2_ntohu32(s); s += 4; len -= method_len; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } s += method_len; /* Read the signature */ len -= 4; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } *sig_len = _libssh2_ntohu32(s); s += 4; len -= *sig_len; if (len < 0) { rc = LIBSSH2_ERROR_AGENT_PROTOCOL; goto error; } *sig = LIBSSH2_ALLOC(session, *sig_len); if (!*sig) { rc = LIBSSH2_ERROR_ALLOC; goto error; } memcpy(*sig, s, *sig_len); error: LIBSSH2_FREE(session, transctx->request); transctx->request = NULL; LIBSSH2_FREE(session, transctx->response); transctx->response = NULL; return _libssh2_error(session, rc, "agent sign failure"); }