Example #1
0
/* {{{ libssh2_publickey_response_success
 * Generic helper routine to wait for success response and nothing else
 */
static int libssh2_publickey_response_success(LIBSSH2_PUBLICKEY *pkey)
{
	LIBSSH2_SESSION *session = pkey->channel->session;
	unsigned char *data, *s;
	unsigned long data_len, response;

	while (1) {
		if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
			return -1;
		}

		s = data;
		if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
			libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
			LIBSSH2_FREE(session, data);
			return -1;
		}

		switch (response) {
			case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
			/* Error, or processing complete */
			{
				unsigned long status, descr_len, lang_len;
				unsigned char *descr, *lang;
				
				status = libssh2_ntohu32(s);					s += 4;
				descr_len = libssh2_ntohu32(s);					s += 4;
				descr = s;										s += descr_len;
				lang_len = libssh2_ntohu32(s);					s += 4;
				lang = s;										s += lang_len;

				if (s > data + data_len) {
					libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
					LIBSSH2_FREE(session, data);
					return -1;
				}

				if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
					LIBSSH2_FREE(session, data);
					return 0;
				}

				libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
				LIBSSH2_FREE(session, data);
				return -1;
			}
			default:
				/* Unknown/Unexpected */
				libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
				LIBSSH2_FREE(session, data);
				data = NULL;
		}
	}
	/* never reached, but include `return` to silence compiler warnings */
	return -1;
}
Example #2
0
/* {{{ libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange
 * Diffie-Hellman Group Exchange Key Exchange using SHA1
 * Negotiates random(ish) group for secret derivation
 */
static int libssh2_kex_method_diffie_hellman_group_exchange_sha1_key_exchange(LIBSSH2_SESSION *session)
{
	unsigned char request[13], *s, *data;
	unsigned long data_len, p_len, g_len, request_len;
	_libssh2_bn *p = _libssh2_bn_init ();
	_libssh2_bn *g = _libssh2_bn_init ();
	int ret;

	/* Ask for a P and G pair */
#ifdef LIBSSH2_DH_GEX_NEW
	request[0] = SSH_MSG_KEX_DH_GEX_REQUEST;
	libssh2_htonu32(request + 1, LIBSSH2_DH_GEX_MINGROUP);
	libssh2_htonu32(request + 5, LIBSSH2_DH_GEX_OPTGROUP);
	libssh2_htonu32(request	+ 9, LIBSSH2_DH_GEX_MAXGROUP);
	request_len = 13;
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group-Exchange (New Method)");
#endif
#else
	request[0] = SSH_MSG_KEX_DH_GEX_REQUEST_OLD;
	libssh2_htonu32(request + 1, LIBSSH2_DH_GEX_OPTGROUP);
	request_len = 5;
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Initiating Diffie-Hellman Group-Exchange (Old Method)");
#endif
#endif

	if (libssh2_packet_write(session, request, request_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send Group Exchange Request", 0);
		ret = -1;
		goto dh_gex_clean_exit;
	}	

	if (libssh2_packet_require(session, SSH_MSG_KEX_DH_GEX_GROUP, &data, &data_len)) {
		libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timeout waiting for GEX_GROUP reply", 0);
		ret = -1;
		goto dh_gex_clean_exit;
	}

	s = data + 1;
	p_len = libssh2_ntohu32(s);						s += 4;
	_libssh2_bn_from_bin(p, p_len, s);					s += p_len;

	g_len = libssh2_ntohu32(s);						s += 4;
	_libssh2_bn_from_bin(g, g_len, s);					s += g_len;

	ret = libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(session, g, p, p_len, SSH_MSG_KEX_DH_GEX_INIT, SSH_MSG_KEX_DH_GEX_REPLY, data + 1, data_len - 1);

	LIBSSH2_FREE(session, data);

 dh_gex_clean_exit:
	_libssh2_bn_free(g);
	_libssh2_bn_free(p);

	return ret;
}
Example #3
0
/* {{{ libssh2_publickey_response_id
 * Translate a string response name to a numeric code
 * Data will be incremented by 4 + response_len on success only
 */
static int libssh2_publickey_response_id(unsigned char **pdata, int data_len)
{
	unsigned long response_len;
	unsigned char *data = *pdata;
	LIBSSH2_PUBLICKEY_CODE_LIST *codes = libssh2_publickey_response_codes;

	if (data_len < 4) {
		/* Malformed response */
		return -1;
	}
	response_len = libssh2_ntohu32(data);			data += 4;			data_len -= 4;
	if (data_len < response_len) {
		/* Malformed response */
		return -1;
	}

	while (codes->name) {
		if (codes->name_len == response_len &&
			strncmp(codes->name, data, response_len) == 0) {
			*pdata = data + response_len;
			return codes->code;
		}
		codes++;
	}

	return -1;
}
Example #4
0
/* {{{ libssh2_publickey_packet_receive
 * Read a packet from the subsystem
 */
static int libssh2_publickey_packet_receive(LIBSSH2_PUBLICKEY *pkey, unsigned char **data, unsigned long *data_len)
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	unsigned char buffer[4];
	unsigned long packet_len;
	unsigned char *packet;

	if (libssh2_channel_read(channel, buffer, 4) != 4) {
		libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid response from publickey subsystem", 0);
		return -1;
	}

	packet_len = libssh2_ntohu32(buffer);
	packet = LIBSSH2_ALLOC(session, packet_len);
	if (!packet) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate publickey response buffer", 0);
		return -1;
	}

	if (libssh2_channel_read(channel, packet, packet_len) != packet_len) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for publickey subsystem response packet", 0);
		LIBSSH2_FREE(session, packet);
		return -1;
	}

	*data = packet;
	*data_len = packet_len;

	return 0;
}
Example #5
0
/* {{{ libssh2_poll_channel_read
 * Returns 0 if no data is waiting on channel,
 * non-0 if data is available
 */
LIBSSH2_API int
libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
{
    LIBSSH2_SESSION *session = channel->session;
    LIBSSH2_PACKET *packet = session->packets.head;

    while (packet) {
        if (((packet->data[0] == SSH_MSG_CHANNEL_DATA) && (extended == 0) &&
             (channel->local.id == libssh2_ntohu32(packet->data + 1))) ||
            ((packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)
             && (extended != 0)
             && (channel->local.id == libssh2_ntohu32(packet->data + 1)))) {
            /* Found data waiting to be read */
            return 1;
        }
        packet = packet->next;
    }

    return 0;
}
Example #6
0
/* {{{ libssh2_hostkey_method_ssh_rsa_init
 * Initialize the server hostkey working area with e/n pair
 */
static int
libssh2_hostkey_method_ssh_rsa_init(LIBSSH2_SESSION *session,
				    unsigned char *hostkey_data,
				    unsigned long hostkey_data_len,
				    void **abstract)
{
	libssh2_rsa_ctx *rsactx;
	unsigned char *s, *e, *n;
	unsigned long len, e_len, n_len;

	(void)hostkey_data_len;

	if (*abstract) {
		libssh2_hostkey_method_ssh_rsa_dtor(session, abstract);
		*abstract = NULL;
	}

	s = hostkey_data;
	len = libssh2_ntohu32(s);
	s += 4;

	if (len != 7 || strncmp((char *)s, "ssh-rsa", 7) != 0) {
		return -1;
	}
	s += 7;

	e_len = libssh2_ntohu32(s);
	s += 4;

	e = s;										s += e_len;
	n_len = libssh2_ntohu32(s);					s += 4;
	n = s;										s += n_len;

	if (_libssh2_rsa_new (&rsactx, e, e_len, n, n_len, NULL, 0,
			      NULL, 0, NULL, 0, NULL, 0, NULL, 0, NULL, 0))
	  return -1;

	*abstract = rsactx;

	return 0;
}
Example #7
0
/* {{{ proto libssh2_userauth_list
 * List authentication methods
 * Will yield successful login if "none" happens to be allowable for this user
 * Not a common configuration for any SSH server though
 * username should be NULL, or a null terminated string
 */
LIBSSH2_API char *libssh2_userauth_list(LIBSSH2_SESSION *session, const char *username, unsigned int username_len)
{
	unsigned char reply_codes[3] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, 0 };
	unsigned long data_len = username_len + 31; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" +
												   method_len(4) + method(4)"none" */
	unsigned long methods_len;
	unsigned char *data, *s;

	s = data = LIBSSH2_ALLOC(session, data_len);
	if (!data) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth_list", 0);
		return NULL;
	}

	*(s++) = SSH_MSG_USERAUTH_REQUEST;
	libssh2_htonu32(s, username_len);				s += 4;
	if (username) {
		memcpy(s, username, username_len);			s += username_len;
	}

	libssh2_htonu32(s, 14);							s += 4;
	memcpy(s, "ssh-connection", 14);				s += 14;

	libssh2_htonu32(s, 4);							s += 4;
	memcpy(s, "none", 4);							s += 4;

	if (libssh2_packet_write(session, data, data_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-none request", 0);
		LIBSSH2_FREE(session, data);
		return NULL;
	}
	LIBSSH2_FREE(session, data);

	if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
		return NULL;
	}

	if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
		/* Wow, who'dve thought... */
		LIBSSH2_FREE(session, data);
		session->state |= LIBSSH2_STATE_AUTHENTICATED;
		return NULL;
	}

	methods_len = libssh2_ntohu32(data + 1);
	memcpy(data, data + 5, methods_len);
	data[methods_len] = '\0';
#ifdef LIBSSH2_DEBUG_USERAUTH
	_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Permitted auth methods: %s", data);
#endif
	return (char *)data;
}
Example #8
0
/* {{{ libssh2_hostkey_method_ssh_dss_init
 * Initialize the server hostkey working area with p/q/g/y set
 */
static int
libssh2_hostkey_method_ssh_dss_init(LIBSSH2_SESSION *session,
				    unsigned char *hostkey_data,
				    unsigned long hostkey_data_len,
				    void **abstract)
{
	libssh2_dsa_ctx *dsactx;
	unsigned char *p, *q, *g, *y, *s;
	unsigned long p_len, q_len, g_len, y_len, len;
	(void)hostkey_data_len;

	if (*abstract) {
		libssh2_hostkey_method_ssh_dss_dtor(session, abstract);
		*abstract = NULL;
	}

	s = hostkey_data;
	len = libssh2_ntohu32(s);					s += 4;
	if (len != 7 || strncmp((char *)s, "ssh-dss", 7) != 0) {
		return -1;
	}											s += 7;

	p_len = libssh2_ntohu32(s);					s += 4;
	p = s;										s += p_len;
	q_len = libssh2_ntohu32(s);					s += 4;
	q = s;										s += q_len;
	g_len = libssh2_ntohu32(s);					s += 4;
	g = s;										s += g_len;
	y_len = libssh2_ntohu32(s);					s += 4;
	y = s;										s += y_len;

	_libssh2_dsa_new(&dsactx, p, p_len, q, q_len, g, g_len,
			 y, y_len, NULL, 0);

	*abstract = dsactx;

	return 0;
}
Example #9
0
/* {{{ libssh2_poll_channel_read
 * Returns 0 if no data is waiting on channel,
 * non-0 if data is available
 */
LIBSSH2_API int
libssh2_poll_channel_read(LIBSSH2_CHANNEL * channel, int extended)
{
    LIBSSH2_SESSION *session = channel->session;
    LIBSSH2_PACKET *packet = session->packets.head;

    while (packet) 
	{
		if ( channel->local.id == libssh2_ntohu32(packet->data + 1)) {
			if ( extended == 1 &&
				(packet->data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA 
				|| packet->data[0] == SSH_MSG_CHANNEL_DATA )) {
				return 1;
			} else if ( extended == 0 && 
				packet->data[0] == SSH_MSG_CHANNEL_DATA) {
				return 1;
			}
			/* else - no data of any type is ready to be read */
        }
        packet = packet->next;
    }

    return 0;
}
Example #10
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;
}
Example #11
0
/* {{{ libssh2_packet_new
 * Create a new packet and attach it to the brigade
 */
static int libssh2_packet_add(LIBSSH2_SESSION *session, unsigned char *data, size_t datalen, int macstate)
{
	LIBSSH2_PACKET *packet;
	unsigned long data_head = 0;

#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Packet type %d received, length=%d", (int)data[0], (int)datalen);
#endif
	if (macstate == LIBSSH2_MAC_INVALID) {
		if (session->macerror) {
			if (LIBSSH2_MACERROR(session, data, datalen) == 0) {
				/* Calling app has given the OK, Process it anyway */
				macstate = LIBSSH2_MAC_CONFIRMED;
			} else {
				libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC, "Invalid Message Authentication Code received", 0);
				if (session->ssh_msg_disconnect) {
					LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR, "Invalid MAC received", sizeof("Invalid MAC received") - 1, "", 0);
				}
				return -1;
			}
		} else {
			libssh2_error(session, LIBSSH2_ERROR_INVALID_MAC, "Invalid Message Authentication Code received", 0);
			if (session->ssh_msg_disconnect) {
				LIBSSH2_DISCONNECT(session, SSH_DISCONNECT_MAC_ERROR, "Invalid MAC received", sizeof("Invalid MAC received") - 1, "", 0);
			}
			return -1;
		}
	}

	/* A couple exceptions to the packet adding rule: */
	switch (data[0]) {
		case SSH_MSG_DISCONNECT:
		{
			char *message, *language;
			int reason, message_len, language_len;

			reason = libssh2_ntohu32(data + 1);
			message_len = libssh2_ntohu32(data + 5);
			message = data + 9; /* packet_type(1) + reason(4) + message_len(4) */
			language_len = libssh2_ntohu32(data + 9 + message_len);
			/* This is where we hack on the data a little,
			 * Use the MSB of language_len to to a terminating NULL (In all liklihood it is already)
			 * Shift the language tag back a byte (In all likelihood it's zero length anyway
			 * Store a NULL in the last byte of the packet to terminate the language string
			 * With the lengths passed this isn't *REALLY* necessary, but it's "kind"
			 */
			message[message_len] = '\0';
			language = data + 9 + message_len + 3;
			if (language_len) {
				memcpy(language, language + 1, language_len);
			}
			language[language_len] = '\0';

			if (session->ssh_msg_disconnect) {
				LIBSSH2_DISCONNECT(session, reason, message, message_len, language, language_len);
			}
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Disconnect(%d): %s(%s)", reason, message, language);
#endif
			LIBSSH2_FREE(session, data);
			session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
			return -1;
		}
			break;
		case SSH_MSG_IGNORE:
			/* As with disconnect, back it up one and add a trailing NULL */
			memcpy(data + 4, data + 5, datalen - 5);
			data[datalen] = '\0';
			if (session->ssh_msg_ignore) {
				LIBSSH2_IGNORE(session, data + 4, datalen - 5);
			}
			LIBSSH2_FREE(session, data);
			return 0;
			break;
		case SSH_MSG_DEBUG:
		{
			int always_display = data[0];
			char *message, *language;
			int message_len, language_len;

			message_len = libssh2_ntohu32(data + 2);
			message = data + 6; /* packet_type(1) + display(1) + message_len(4) */
			language_len = libssh2_ntohu32(data + 6 + message_len);
			/* This is where we hack on the data a little,
			 * Use the MSB of language_len to to a terminating NULL (In all liklihood it is already)
			 * Shift the language tag back a byte (In all likelihood it's zero length anyway
			 * Store a NULL in the last byte of the packet to terminate the language string
			 * With the lengths passed this isn't *REALLY* necessary, but it's "kind"
			 */
			message[message_len] = '\0';
			language = data + 6 + message_len + 3;
			if (language_len) {
				memcpy(language, language + 1, language_len);
			}
			language[language_len] = '\0';

			if (session->ssh_msg_debug) {
				LIBSSH2_DEBUG(session, always_display, message, message_len, language, language_len);
			}
#ifdef LIBSSH2_DEBUG_TRANSPORT
	/* _libssh2_debug will actually truncate this for us so that it's not an inordinate about of data */
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Debug Packet: %s", message);
#endif
			LIBSSH2_FREE(session, data);
			return 0;
		}
			break;
		case SSH_MSG_CHANNEL_EXTENDED_DATA:
			data_head += 4; /* streamid(4) */
		case SSH_MSG_CHANNEL_DATA:
			data_head += 9; /* packet_type(1) + channelno(4) + datalen(4) */
			{
				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));

				if (!channel) {
					libssh2_error(session, LIBSSH2_ERROR_CHANNEL_UNKNOWN, "Packet received for unknown channel, ignoring", 0);
					LIBSSH2_FREE(session, data);
					return 0;
				}
#ifdef LIBSSH2_DEBUG_CONNECTION
{
	unsigned long stream_id = 0;

	if (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA) {
		stream_id = libssh2_ntohu32(data + 5);
	}

	_libssh2_debug(session, LIBSSH2_DBG_CONN, "%d bytes received for channel %lu/%lu stream #%lu", (int)(datalen - data_head), channel->local.id, channel->remote.id, stream_id);
}
#endif
				if ((channel->remote.extended_data_ignore_mode == LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE) && (data[0] == SSH_MSG_CHANNEL_EXTENDED_DATA)) {
					/* Pretend we didn't receive this */
					LIBSSH2_FREE(session, data);

#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Ignoring extended data and refunding %d bytes", (int)(datalen - 13));
#endif
					/* Adjust the window based on the block we just freed */
					libssh2_channel_receive_window_adjust(channel, datalen - 13, 0);

					return 0;
				}

				/* REMEMBER! remote means remote as source of data, NOT remote window! */
				if (channel->remote.packet_size < (datalen - data_head)) {
					/* Spec says we MAY ignore bytes sent beyond packet_size */
					libssh2_error(session, LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED, "Packet contains more data than we offered to receive, truncating", 0);
					datalen = channel->remote.packet_size + data_head;
				}
				if (channel->remote.window_size <= 0) {
					/* Spec says we MAY ignore bytes sent beyond window_size */
					libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "The current receive window is full, data ignored", 0);
					LIBSSH2_FREE(session, data);
					return 0;
				}
				/* Reset EOF status */
				channel->remote.eof = 0;

				if ((datalen - data_head) > channel->remote.window_size) {
					libssh2_error(session, LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED, "Remote sent more data than current window allows, truncating", 0);
					datalen = channel->remote.window_size + data_head;
				} else {
					/* Now that we've received it, shrink our window */
					channel->remote.window_size -= datalen - data_head;
				}
			}
			break;
		case SSH_MSG_CHANNEL_EOF:
			{
				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));

				if (!channel) {
					/* We may have freed already, just quietly ignore this... */
					LIBSSH2_FREE(session, data);
					return 0;
				}

#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "EOF received for channel %lu/%lu", channel->local.id, channel->remote.id);
#endif
				channel->remote.eof = 1;

				LIBSSH2_FREE(session, data);
				return 0;
			}
			break;
	    case SSH_MSG_CHANNEL_REQUEST:
		    {
				if (libssh2_ntohu32(data+5) == sizeof("exit-status") - 1
					&& !memcmp("exit-status", data + 9, sizeof("exit-status") - 1)) {

					/* we've got "exit-status" packet. Set the session value */
					LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data+1));

					if (channel) {
						channel->exit_status = libssh2_ntohu32(data + 9 + sizeof("exit-status"));
#ifdef LIBSSH2_DEBUG_CONNECTION
						_libssh2_debug(session, LIBSSH2_DBG_CONN, "Exit status %lu received for channel %lu/%lu", channel->exit_status, channel->local.id, channel->remote.id);
#endif
					}

					LIBSSH2_FREE(session, data);
					return 0;
				}
			}
			break;
		case SSH_MSG_CHANNEL_CLOSE:
			{
				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));

				if (!channel) {
					/* We may have freed already, just quietly ignore this... */
					LIBSSH2_FREE(session, data);
					return 0;
				}
#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Close received for channel %lu/%lu", channel->local.id, channel->remote.id);
#endif

				channel->remote.close = 1;
				/* TODO: Add a callback for this */

				LIBSSH2_FREE(session, data);
				return 0;
			}
			break;
		case SSH_MSG_CHANNEL_OPEN:
			if ((datalen >= (sizeof("forwarded-tcpip") + 4)) &&
				((sizeof("forwarded-tcpip")-1) == libssh2_ntohu32(data + 1)) &&
				(memcmp(data + 5, "forwarded-tcpip", sizeof("forwarded-tcpip") - 1) == 0)) {
				int retval = libssh2_packet_queue_listener(session, data, datalen);

				LIBSSH2_FREE(session, data);
				return retval;
			}
			if ((datalen >= (sizeof("x11") + 4)) &&
				((sizeof("x11")-1) == libssh2_ntohu32(data + 1)) &&
				(memcmp(data + 5, "x11", sizeof("x11") - 1) == 0)) {
				int retval = libssh2_packet_x11_open(session, data, datalen);

				LIBSSH2_FREE(session, data);
				return retval;
			}
			break;
		case SSH_MSG_CHANNEL_WINDOW_ADJUST:
			{
				LIBSSH2_CHANNEL *channel = libssh2_channel_locate(session, libssh2_ntohu32(data + 1));
				unsigned long bytestoadd = libssh2_ntohu32(data + 5);

				if (channel && bytestoadd) {
					channel->local.window_size += bytestoadd;
				}
#ifdef LIBSSH2_DEBUG_CONNECTION
	_libssh2_debug(session, LIBSSH2_DBG_CONN, "Window adjust received for channel %lu/%lu, adding %lu bytes, new window_size=%lu", channel->local.id, channel->remote.id, bytestoadd, channel->local.window_size);
#endif

				LIBSSH2_FREE(session, data);
				return 0;
			}
			break;
	}

	packet = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PACKET));
	memset(packet, 0, sizeof(LIBSSH2_PACKET));

	packet->data = data;
	packet->data_len = datalen;
	packet->data_head = data_head;
	packet->mac = macstate;
	packet->brigade = &session->packets;
	packet->next = NULL;

	if (session->packets.tail) {
		packet->prev = session->packets.tail;
		packet->prev->next = packet;
		session->packets.tail = packet;
	} else {
		session->packets.head = packet;
		session->packets.tail = packet;
		packet->prev = NULL;
	}

	if (data[0] == SSH_MSG_KEXINIT && !(session->state & LIBSSH2_STATE_EXCHANGING_KEYS)) {
		/* Remote wants new keys
		 * Well, it's already in the brigade,
		 * let's just call back into ourselves
		 */
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Renegotiating Keys");
#endif
		libssh2_kex_exchange(session, 1);
		/* 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 */
	}

	return 0;
}
Example #12
0
/* {{{ libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange
 * Diffie Hellman Key Exchange, Group Agnostic
 */
static int libssh2_kex_method_diffie_hellman_groupGP_sha1_key_exchange(LIBSSH2_SESSION *session, _libssh2_bn *g, _libssh2_bn *p, int group_order,
																		unsigned char packet_type_init, unsigned char packet_type_reply,
																		unsigned char *midhash, unsigned long midhash_len)
{
	unsigned char *e_packet = NULL, *s_packet = NULL, *tmp, h_sig_comp[SHA_DIGEST_LENGTH], c;
	unsigned long e_packet_len, s_packet_len, tmp_len;
	int ret = 0;
	_libssh2_bn_ctx *ctx = _libssh2_bn_ctx_new();
	_libssh2_bn *x = _libssh2_bn_init(); /* Random from client */
	_libssh2_bn *e = _libssh2_bn_init(); /* g^x mod p */
	_libssh2_bn *f = _libssh2_bn_init(); /* g^(Random from server) mod p */
	_libssh2_bn *k = _libssh2_bn_init(); /* The shared secret: f^x mod p */
	unsigned char *s, *f_value, *k_value = NULL, *h_sig;
	unsigned long f_value_len, k_value_len, h_sig_len;
	libssh2_sha1_ctx exchange_hash;

	/* Generate x and e */
	_libssh2_bn_rand(x, group_order, 0, -1);
	_libssh2_bn_mod_exp(e, g, x, p, ctx);

	/* Send KEX init */
	e_packet_len = _libssh2_bn_bytes(e) + 6; /* packet_type(1) + String Length(4) + leading 0(1) */
	if (_libssh2_bn_bits(e) % 8) {
		/* Leading 00 not needed */
		e_packet_len--;
	}
	e_packet = LIBSSH2_ALLOC(session, e_packet_len);
	if (!e_packet) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Out of memory error", 0);
		ret = -1;
		goto clean_exit;
	}
	e_packet[0] = packet_type_init;
	libssh2_htonu32(e_packet + 1, e_packet_len - 5);
	if (_libssh2_bn_bits(e) % 8) {
		_libssh2_bn_to_bin(e, e_packet + 5);
	} else {
		e_packet[5] = 0;
		_libssh2_bn_to_bin(e, e_packet + 6);
	}

#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending KEX packet %d", (int)packet_type_init);
#endif
	if (libssh2_packet_write(session, e_packet, e_packet_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send KEX init message", 0);
		ret = -11;
		goto clean_exit;
	}

	if (session->burn_optimistic_kexinit) {
		/* The first KEX packet to come along will be the guess initially sent by the server
		 * That guess turned out to be wrong so we need to silently ignore it */
		int burn_type;
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Waiting for badly guessed KEX packet (to be ignored)");
#endif
		burn_type = libssh2_packet_burn(session);
		if (burn_type <= 0) {
			/* Failed to receive a packet */
			ret = -1;
			goto clean_exit;
		}
		session->burn_optimistic_kexinit = 0;

#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Burnt packet of type: %02x", (unsigned int)burn_type);
#endif
	}

	/* Wait for KEX reply */
	if (libssh2_packet_require(session, packet_type_reply, &s_packet, &s_packet_len)) {
		libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for KEX reply", 0);
		ret = -1;
		goto clean_exit;
	}

	/* Parse KEXDH_REPLY */
	s = s_packet + 1;

	session->server_hostkey_len = libssh2_ntohu32(s);			s += 4;
	session->server_hostkey = LIBSSH2_ALLOC(session, session->server_hostkey_len);
	if (!session->server_hostkey) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for a copy of the host key", 0);
		ret = -1;
		goto clean_exit;
	}
	memcpy(session->server_hostkey, s, session->server_hostkey_len);
	s += session->server_hostkey_len;

#if LIBSSH2_MD5
{
	libssh2_md5_ctx fingerprint_ctx;

	libssh2_md5_init(&fingerprint_ctx);
	libssh2_md5_update(fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
	libssh2_md5_final(fingerprint_ctx, session->server_hostkey_md5);
}
#ifdef LIBSSH2_DEBUG_KEX
{
	char fingerprint[50], *fprint = fingerprint;
	int i;
	for(i = 0; i < 16; i++, fprint += 3) {
		snprintf(fprint, 4, "%02x:", session->server_hostkey_md5[i]);
	}
	*(--fprint) = '\0';
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's MD5 Fingerprint: %s", fingerprint);
}
#endif /* LIBSSH2_DEBUG_KEX */
#endif /* ! LIBSSH2_MD5 */

{
	libssh2_sha1_ctx fingerprint_ctx;

	libssh2_sha1_init(&fingerprint_ctx);
	libssh2_sha1_update (fingerprint_ctx, session->server_hostkey, session->server_hostkey_len);
	libssh2_sha1_final(fingerprint_ctx, session->server_hostkey_sha1);
}
#ifdef LIBSSH2_DEBUG_KEX
{
	char fingerprint[64], *fprint = fingerprint;
	int i;
	for(i = 0; i < 20; i++, fprint += 3) {
		snprintf(fprint, 4, "%02x:", session->server_hostkey_sha1[i]);
	}
	*(--fprint) = '\0';
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server's SHA1 Fingerprint: %s", fingerprint);
}
#endif /* LIBSSH2_DEBUG_KEX */

	if (session->hostkey->init(session, session->server_hostkey, session->server_hostkey_len, &session->server_hostkey_abstract)) {
		libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_INIT, "Unable to initialize hostkey importer", 0);
		ret = -1;
		goto clean_exit;
	}

	f_value_len = libssh2_ntohu32(s);							s += 4;
	f_value = s;												s += f_value_len;
	_libssh2_bn_from_bin(f, f_value_len, f_value);

	h_sig_len = libssh2_ntohu32(s);								s += 4;
	h_sig = s;

	/* Compute the shared secret */
	_libssh2_bn_mod_exp(k, f, x, p, ctx);
	k_value_len = _libssh2_bn_bytes(k) + 5;
	if (_libssh2_bn_bits(k) % 8) {
		/* don't need leading 00 */
		k_value_len--;
	}
	k_value = LIBSSH2_ALLOC(session, k_value_len);
	if (!k_value) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate buffer for K", 0);
		ret = -1;
		goto clean_exit;
	}
	libssh2_htonu32(k_value, k_value_len - 4);
	if (_libssh2_bn_bits(k) % 8) {
		_libssh2_bn_to_bin(k, k_value + 4);
	} else {
		k_value[4] = 0;
		_libssh2_bn_to_bin(k, k_value + 5);
	}

	libssh2_sha1_init(&exchange_hash);
	if (session->local.banner) {
		libssh2_htonu32(h_sig_comp,
				strlen((char *)session->local.banner) - 2);
		libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
		libssh2_sha1_update(exchange_hash, (char *)session->local.banner,
			    strlen((char *)session->local.banner) - 2);
	} else {
		libssh2_htonu32(h_sig_comp, sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
		libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
		libssh2_sha1_update(exchange_hash, LIBSSH2_SSH_DEFAULT_BANNER,
			    sizeof(LIBSSH2_SSH_DEFAULT_BANNER) - 1);
	}

	libssh2_htonu32(h_sig_comp, strlen((char *)session->remote.banner));
	libssh2_sha1_update(exchange_hash, h_sig_comp, 4);
	libssh2_sha1_update(exchange_hash, session->remote.banner,
		    strlen((char *)session->remote.banner));

	libssh2_htonu32(h_sig_comp, session->local.kexinit_len);
	libssh2_sha1_update(exchange_hash,		h_sig_comp,							4);
	libssh2_sha1_update(exchange_hash,		session->local.kexinit,				session->local.kexinit_len);

	libssh2_htonu32(h_sig_comp, session->remote.kexinit_len);
	libssh2_sha1_update(exchange_hash,		h_sig_comp,							4);
	libssh2_sha1_update(exchange_hash,		session->remote.kexinit,			session->remote.kexinit_len);

	libssh2_htonu32(h_sig_comp, session->server_hostkey_len);
	libssh2_sha1_update(exchange_hash,		h_sig_comp,							4);
	libssh2_sha1_update(exchange_hash,		session->server_hostkey,			session->server_hostkey_len);

	if (packet_type_init == SSH_MSG_KEX_DH_GEX_INIT) {
		/* diffie-hellman-group-exchange hashes additional fields */
#ifdef LIBSSH2_DH_GEX_NEW
		libssh2_htonu32(h_sig_comp,		LIBSSH2_DH_GEX_MINGROUP);
		libssh2_htonu32(h_sig_comp + 4,	LIBSSH2_DH_GEX_OPTGROUP);
		libssh2_htonu32(h_sig_comp + 8, LIBSSH2_DH_GEX_MAXGROUP);
		libssh2_sha1_update(exchange_hash,	h_sig_comp,							12);
#else
		libssh2_htonu32(h_sig_comp,		LIBSSH2_DH_GEX_OPTGROUP);
		libssh2_sha1_update(exchange_hash,	h_sig_comp,							4);
#endif
	}

	if (midhash) {
		libssh2_sha1_update(exchange_hash, midhash,							midhash_len);
	}

	libssh2_sha1_update(exchange_hash,		e_packet + 1,						e_packet_len - 1);

	libssh2_htonu32(h_sig_comp, f_value_len);
	libssh2_sha1_update(exchange_hash,		h_sig_comp,							4);
	libssh2_sha1_update(exchange_hash,		f_value,							f_value_len);

	libssh2_sha1_update(exchange_hash,		k_value,							k_value_len);

	libssh2_sha1_final(exchange_hash, h_sig_comp);

	if (session->hostkey->sig_verify(session, h_sig, h_sig_len, h_sig_comp, 20, &session->server_hostkey_abstract)) {
		libssh2_error(session, LIBSSH2_ERROR_HOSTKEY_SIGN, "Unable to verify hostkey signature", 0);
		ret = -1;
		goto clean_exit;
	}

#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Sending NEWKEYS message");
#endif
	c = SSH_MSG_NEWKEYS;
	if (libssh2_packet_write(session, &c, 1)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send NEWKEYS message", 0);
		ret = -1;
		goto clean_exit;
	}

	if (libssh2_packet_require(session, SSH_MSG_NEWKEYS, &tmp, &tmp_len)) {
		libssh2_error(session, LIBSSH2_ERROR_TIMEOUT, "Timed out waiting for NEWKEYS", 0);
		ret = -1;
		goto clean_exit;
	}
	/* The first key exchange has been performed, switch to active crypt/comp/mac mode */
	session->state |= LIBSSH2_STATE_NEWKEYS;
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Received NEWKEYS message");
#endif

	/* This will actually end up being just packet_type(1) for this packet type anyway */
	LIBSSH2_FREE(session, tmp);

	if (!session->session_id) {
		session->session_id = LIBSSH2_ALLOC(session, SHA_DIGEST_LENGTH);
		if (!session->session_id) {
			ret = -1;
			goto clean_exit;
		}
		memcpy(session->session_id, h_sig_comp, SHA_DIGEST_LENGTH);
		session->session_id_len = SHA_DIGEST_LENGTH;
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "session_id calculated");
#endif
	}

	/* Cleanup any existing cipher */
	if (session->local.crypt->dtor) {
		session->local.crypt->dtor(session, &session->local.crypt_abstract);
	}

	/* Calculate IV/Secret/Key for each direction */
	if (session->local.crypt->init) {
		unsigned char *iv = NULL, *secret = NULL;
		int free_iv = 0, free_secret = 0;

		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->local.crypt->iv_len, "A");
		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->local.crypt->secret_len, "C");
		if (session->local.crypt->init(session, session->local.crypt, iv, &free_iv, secret, &free_secret, 1, &session->local.crypt_abstract)) {
		  LIBSSH2_FREE(session, iv);
		  LIBSSH2_FREE(session, secret);
		  ret = -1;
		  goto clean_exit;
		}

		if (free_iv) {
			memset(iv, 0, session->local.crypt->iv_len);
			LIBSSH2_FREE(session, iv);
		}

		if (free_secret) {
			memset(secret, 0, session->local.crypt->secret_len);
			LIBSSH2_FREE(session, secret);
		}
	}
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server IV and Key calculated");
#endif

	if (session->remote.crypt->dtor) {
		/* Cleanup any existing cipher */
		session->remote.crypt->dtor(session, &session->remote.crypt_abstract);
	}

	if (session->remote.crypt->init) {
		unsigned char *iv = NULL, *secret = NULL;
		int free_iv = 0, free_secret = 0;

		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(iv, session->remote.crypt->iv_len, "B");
		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(secret, session->remote.crypt->secret_len, "D");
		if (session->remote.crypt->init(session, session->remote.crypt, iv, &free_iv, secret, &free_secret, 0, &session->remote.crypt_abstract)) {
		  LIBSSH2_FREE(session, iv);
		  LIBSSH2_FREE(session, secret);
		  ret = -1;
		  goto clean_exit;
		}

		if (free_iv) {
			memset(iv, 0, session->remote.crypt->iv_len);
			LIBSSH2_FREE(session, iv);
		}

		if (free_secret) {
			memset(secret, 0, session->remote.crypt->secret_len);
			LIBSSH2_FREE(session, secret);
		}
	}
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client IV and Key calculated");
#endif

	if (session->local.mac->dtor) {
		session->local.mac->dtor(session, &session->local.mac_abstract);
	}

	if (session->local.mac->init) {
		unsigned char *key = NULL;
		int free_key = 0;

		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->local.mac->key_len, "E");
		session->local.mac->init(session, key, &free_key, &session->local.mac_abstract);

		if (free_key) {
			memset(key, 0, session->local.mac->key_len);
			LIBSSH2_FREE(session, key);
		}
	}
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Client to Server HMAC Key calculated");
#endif

	if (session->remote.mac->dtor) {
		session->remote.mac->dtor(session, &session->remote.mac_abstract);
	}

	if (session->remote.mac->init) {
		unsigned char *key = NULL;
		int free_key = 0;

		LIBSSH2_KEX_METHOD_DIFFIE_HELLMAN_SHA1_HASH(key, session->remote.mac->key_len, "F");
		session->remote.mac->init(session, key, &free_key, &session->remote.mac_abstract);

		if (free_key) {
			memset(key, 0, session->remote.mac->key_len);
			LIBSSH2_FREE(session, key);
		}
	}
#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Server to Client HMAC Key calculated");
#endif

 clean_exit:
	_libssh2_bn_free(x);
	_libssh2_bn_free(e);
	_libssh2_bn_free(f);
	_libssh2_bn_free(k);
	_libssh2_bn_ctx_free(ctx);

	if (e_packet) {
		LIBSSH2_FREE(session, e_packet);
	}

	if (s_packet) {
		LIBSSH2_FREE(session, s_packet);
	}

	if (k_value) {
		LIBSSH2_FREE(session, k_value);
	}

	if (session->server_hostkey) {
		LIBSSH2_FREE(session, session->server_hostkey);
		session->server_hostkey = NULL;
	}

	return ret;
}
Example #13
0
/* {{{ libssh2_userauth_keyboard_interactive
 * Authenticate using a challenge-response authentication
 */
LIBSSH2_API int libssh2_userauth_keyboard_interactive_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
														 LIBSSH2_USERAUTH_KBDINT_RESPONSE_FUNC((*response_callback)))
{
	unsigned char *s, *data; /* packet */
	unsigned long packet_len;

	packet_len = 1         /* byte      SSH_MSG_USERAUTH_REQUEST */
		+ 4 + username_len /* string    user name (ISO-10646 UTF-8, as defined in [RFC-3629]) */
		+ 4 + 14           /* string    service name (US-ASCII) */
		+ 4 + 20           /* string    "keyboard-interactive" (US-ASCII) */
		+ 4 + 0            /* string    language tag (as defined in [RFC-3066]) */
		+ 4 + 0            /* string    submethods (ISO-10646 UTF-8) */
		;

	if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive authentication", 0);
		return -1;
	}

	*s++ = SSH_MSG_USERAUTH_REQUEST;

	/* user name */
	libssh2_htonu32(s, username_len);										s += 4;
	memcpy(s, username, username_len);										s += username_len;

	/* service name */
	libssh2_htonu32(s, sizeof("ssh-connection") - 1);						s += 4;
	memcpy(s, "ssh-connection", sizeof("ssh-connection") - 1);				s += sizeof("ssh-connection") - 1;

	/* "keyboard-interactive" */
	libssh2_htonu32(s, sizeof("keyboard-interactive") - 1);					s += 4;
	memcpy(s, "keyboard-interactive", sizeof("keyboard-interactive") - 1);	s += sizeof("keyboard-interactive") - 1;

	/* language tag */
	libssh2_htonu32(s, 0);													s += 4;

	/* submethods */
	libssh2_htonu32(s, 0);													s += 4;

#ifdef LIBSSH2_DEBUG_USERAUTH
	_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting keyboard-interactive authentication");
#endif
	if (libssh2_packet_write(session, data, packet_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send keyboard-interactive request", 0);
		LIBSSH2_FREE(session, data);
		return -1;
	}
	LIBSSH2_FREE(session, data);

	for (;;) {
		unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_INFO_REQUEST, 0 };
		unsigned int auth_name_len;
		char* auth_name = NULL;
		unsigned auth_instruction_len;
		char* auth_instruction = NULL;
		unsigned int language_tag_len;
		unsigned long data_len;
		unsigned int num_prompts = 0;
		unsigned int i;
		int auth_failure = 1;
		LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts = NULL;
		LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses = NULL;

		if (libssh2_packet_requirev(session, reply_codes, &data, &data_len)) {
			return -1;
		}

		if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
			_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive authentication successful");
#endif
			LIBSSH2_FREE(session, data);
			session->state |= LIBSSH2_STATE_AUTHENTICATED;
			return 0;
		}

		if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
			LIBSSH2_FREE(session, data);
			return -1;
		}

		/* server requested PAM-like conversation */

		s = data + 1;

		/* string    name (ISO-10646 UTF-8) */
		auth_name_len = libssh2_ntohu32(s);								s += 4;
		if (!(auth_name = LIBSSH2_ALLOC(session, auth_name_len))) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'name' request field", 0);
			goto cleanup;
		}
		memcpy(auth_name, s, auth_name_len);							s += auth_name_len;

		/* string    instruction (ISO-10646 UTF-8) */
		auth_instruction_len = libssh2_ntohu32(s); s += 4;
		if (!(auth_instruction = LIBSSH2_ALLOC(session, auth_instruction_len))) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive 'instruction' request field", 0);
			goto cleanup;
		}
		memcpy(auth_instruction, s, auth_instruction_len);				s += auth_instruction_len;

		/* string    language tag (as defined in [RFC-3066]) */
		language_tag_len = libssh2_ntohu32(s);							s += 4;
		/* ignoring this field as deprecated */							s += language_tag_len;

		/* int       num-prompts */
		num_prompts = libssh2_ntohu32(s);								s += 4;

		prompts = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);
		if (!prompts) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompts array", 0);
			goto cleanup;
		}
		memset(prompts, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_PROMPT) * num_prompts);

		responses = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);
		if (!responses) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive responses array", 0);
			goto cleanup;
		}
		memset(responses, 0, sizeof(LIBSSH2_USERAUTH_KBDINT_RESPONSE) * num_prompts);

		for(i = 0; i != num_prompts; ++i) {
			/* string    prompt[1] (ISO-10646 UTF-8) */
			prompts[i].length = libssh2_ntohu32(s);						s += 4;
			if (!(prompts[i].text = LIBSSH2_ALLOC(session, prompts[i].length))) {
				libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive prompt message", 0);
				goto cleanup;
			}
			memcpy(prompts[i].text, s, prompts[i].length);				s += prompts[i].length;

			/* boolean   echo[1] */
			prompts[i].echo = *s++;
		}

		response_callback(auth_name, auth_name_len,  auth_instruction, auth_instruction_len, num_prompts, prompts, responses, &session->abstract);

#ifdef LIBSSH2_DEBUG_USERAUTH
		_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Keyboard-interactive response callback function invoked");
#endif

		packet_len = 1 /* byte      SSH_MSG_USERAUTH_INFO_RESPONSE */
			+ 4        /* int       num-responses */
			;

		for (i = 0; i != num_prompts; ++i) {
			packet_len += 4 + responses[i].length; /* string    response[1] (ISO-10646 UTF-8) */
		}

		if (!(data = s = LIBSSH2_ALLOC(session, packet_len))) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for keyboard-interactive response packet", 0);
			goto cleanup;
		}

		*s = SSH_MSG_USERAUTH_INFO_RESPONSE; s++;
		libssh2_htonu32(s, num_prompts);								s += 4;

		for (i = 0; i != num_prompts; ++i) {
			libssh2_htonu32(s, responses[i].length);					s += 4;
			memcpy(s, responses[i].text, responses[i].length);			s += responses[i].length;
		}

		if (libssh2_packet_write(session, data, packet_len)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-keyboard-interactive request", 0);
			goto cleanup;
		}

		auth_failure = 0;

	cleanup:
		/* It's safe to clean all the data here, because unallocated pointers
		 * are filled by zeroes
		 */

		LIBSSH2_FREE(session, data);

		if (prompts) {
			for (i = 0; i != num_prompts; ++i) {
				LIBSSH2_FREE(session, prompts[i].text);
			}
		}

		if (responses) {
			for (i = 0; i != num_prompts; ++i) {
				LIBSSH2_FREE(session, responses[i].text);
			}
		}

		LIBSSH2_FREE(session, prompts);
		LIBSSH2_FREE(session, responses);

		if (auth_failure) {
			return -1;
		}
	}
}
Example #14
0
/* {{{ proto libssh2_session_startup
 * session: LIBSSH2_SESSION struct allocated and owned by the calling program
 * Returns: 0 on success, or non-zero on failure
 * Any memory allocated by libssh2 will use alloc/realloc/free
 * callbacks in session
 * socket *must* be populated with an opened and connected socket.
 */
LIBSSH2_API int
libssh2_session_startup(LIBSSH2_SESSION * session, int sock)
{
    int rc;

    if (session->startup_state == libssh2_NB_state_idle) {
        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "session_startup for socket %d", sock);
        /* FIXME: on some platforms (like win32) sockets are unsigned */
        if (sock < 0) {
            /* Did we forget something? */
            libssh2_error(session, LIBSSH2_ERROR_SOCKET_NONE,
                          "Bad socket provided", 0);
            return LIBSSH2_ERROR_SOCKET_NONE;
        }
        session->socket_fd = sock;

        session->socket_block =
            !_libssh2_get_socket_nonblocking(session->socket_fd);
        if (session->socket_block) {
            /*
             * Since we can't be sure that we are in blocking or there
             * was an error detecting the state, so set to blocking to
             * be sure
             */
            _libssh2_nonblock(session->socket_fd, 0);
        }

        session->startup_state = libssh2_NB_state_created;
    }

    /* TODO: Liveness check */

    if (session->startup_state == libssh2_NB_state_created) {
        rc = libssh2_banner_send(session);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block sending banner to remote host", 0);
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            /* Unable to send banner? */
            libssh2_error(session, LIBSSH2_ERROR_BANNER_SEND,
                          "Error sending banner to remote host", 0);
            return LIBSSH2_ERROR_BANNER_SEND;
        }

        session->startup_state = libssh2_NB_state_sent;
    }

    if (session->startup_state == libssh2_NB_state_sent) {
        rc = libssh2_banner_receive(session);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block waiting for banner", 0);
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            /* Unable to receive banner from remote */
            libssh2_error(session, LIBSSH2_ERROR_BANNER_NONE,
                          "Timeout waiting for banner", 0);
            return LIBSSH2_ERROR_BANNER_NONE;
        }

        session->startup_state = libssh2_NB_state_sent1;
    }

    if (session->startup_state == libssh2_NB_state_sent1) {
        rc = libssh2_kex_exchange(session, 0, &session->startup_key_state);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block exchanging encryption keys", 0);
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            libssh2_error(session, LIBSSH2_ERROR_KEX_FAILURE,
                          "Unable to exchange encryption keys", 0);
            return LIBSSH2_ERROR_KEX_FAILURE;
        }

        session->startup_state = libssh2_NB_state_sent2;
    }

    if (session->startup_state == libssh2_NB_state_sent2) {
        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "Requesting userauth service");

        /* Request the userauth service */
        session->startup_service[0] = SSH_MSG_SERVICE_REQUEST;
        libssh2_htonu32(session->startup_service + 1,
                        sizeof("ssh-userauth") - 1);
        memcpy(session->startup_service + 5, "ssh-userauth",
               sizeof("ssh-userauth") - 1);

        session->startup_state = libssh2_NB_state_sent3;
    }

    if (session->startup_state == libssh2_NB_state_sent3) {
        rc = libssh2_packet_write(session, session->startup_service,
                                  sizeof("ssh-userauth") + 5 - 1);
        if (rc == PACKET_EAGAIN) {
            libssh2_error(session, LIBSSH2_ERROR_EAGAIN,
                          "Would block asking for ssh-userauth service", 0);
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND,
                          "Unable to ask for ssh-userauth service", 0);
            return LIBSSH2_ERROR_SOCKET_SEND;
        }

        session->startup_state = libssh2_NB_state_sent4;
    }

    if (session->startup_state == libssh2_NB_state_sent4) {
        rc = libssh2_packet_require_ex(session, SSH_MSG_SERVICE_ACCEPT,
                                       &session->startup_data,
                                       &session->startup_data_len, 0, NULL, 0,
                                       &session->startup_req_state);
        if (rc == PACKET_EAGAIN) {
            return LIBSSH2_ERROR_EAGAIN;
        } else if (rc) {
            return LIBSSH2_ERROR_SOCKET_DISCONNECT;
        }
        session->startup_service_length =
            libssh2_ntohu32(session->startup_data + 1);

        if ((session->startup_service_length != (sizeof("ssh-userauth") - 1))
            || strncmp("ssh-userauth", (char *) session->startup_data + 5,
                       session->startup_service_length)) {
            LIBSSH2_FREE(session, session->startup_data);
            session->startup_data = NULL;
            libssh2_error(session, LIBSSH2_ERROR_PROTO,
                          "Invalid response received from server", 0);
            return LIBSSH2_ERROR_PROTO;
        }
        LIBSSH2_FREE(session, session->startup_data);
        session->startup_data = NULL;

        session->startup_state = libssh2_NB_state_idle;

        return 0;
    }

    /* just for safety return some error */
    return LIBSSH2_ERROR_INVAL;
}
Example #15
0
/*
 * This function reads the binary stream as specified in chapter 6 of RFC4253
 * "The Secure Shell (SSH) Transport Layer Protocol"
 */
libssh2pack_t
libssh2_packet_read(LIBSSH2_SESSION * session)
{
    libssh2pack_t rc;
    struct transportpacket *p = &session->packet;
    int remainbuf;
    int remainpack;
    int numbytes;
    int numdecrypt;
    unsigned char block[MAX_BLOCKSIZE];
    int blocksize;
    int encrypted = 1;

    /*
     * =============================== NOTE ===============================
     * I know this is very ugly and not a really good use of "goto", but
     * this case statement would be even uglier to do it any other way
     */
    if (session->readPack_state == libssh2_NB_state_jump1) {
        session->readPack_state = libssh2_NB_state_idle;
        encrypted = session->readPack_encrypted;
        goto libssh2_packet_read_point1;
    }

    do {
        if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
            return PACKET_NONE;
        }

        if (session->state & LIBSSH2_STATE_NEWKEYS) {
            blocksize = session->remote.crypt->blocksize;
        } else {
            encrypted = 0;      /* not encrypted */
            blocksize = 5;      /* not strictly true, but we can use 5 here to
                                   make the checks below work fine still */
        }

        /* read/use a whole big chunk into a temporary area stored in
           the LIBSSH2_SESSION struct. We will decrypt data from that
           buffer into the packet buffer so this temp one doesn't have
           to be able to keep a whole SSH packet, just be large enough
           so that we can read big chunks from the network layer. */

        /* how much data there is remaining in the buffer to deal with
           before we should read more from the network */
        remainbuf = p->writeidx - p->readidx;

        /* if remainbuf turns negative we have a bad internal error */
        assert(remainbuf >= 0);

        if (remainbuf < blocksize) {
            /* If we have less than a blocksize left, it is too
               little data to deal with, read more */
            ssize_t nread;

            /* move any remainder to the start of the buffer so
               that we can do a full refill */
            if (remainbuf) {
                memmove(p->buf, &p->buf[p->readidx], remainbuf);
                p->readidx = 0;
                p->writeidx = remainbuf;
            } else {
                /* nothing to move, just zero the indexes */
                p->readidx = p->writeidx = 0;
            }

            /* now read a big chunk from the network into the temp buffer */
            nread =
                recv(session->socket_fd, &p->buf[remainbuf],
                     PACKETBUFSIZE - remainbuf,
                     LIBSSH2_SOCKET_RECV_FLAGS(session));
            if (nread <= 0) {
                /* check if this is due to EAGAIN and return the special
                   return code if so, error out normally otherwise */
#ifdef WIN32
                switch (WSAGetLastError()) {
                case WSAEWOULDBLOCK:
                    errno = EAGAIN;
                    break;

                case WSAENOTSOCK:
                    errno = EBADF;
                    break;

                case WSAENOTCONN:
                case WSAECONNABORTED:
                    errno = WSAENOTCONN;
                    break;

                case WSAEINTR:
                    errno = EINTR;
                    break;
                }
#endif /* WIN32 */
                if ((nread < 0) && (errno == EAGAIN)) {
                    return PACKET_EAGAIN;
                }
                return PACKET_FAIL;
            }
            debugdump(session, "libssh2_packet_read() raw",
                      &p->buf[remainbuf], nread);
            /* advance write pointer */
            p->writeidx += nread;

            /* update remainbuf counter */
            remainbuf = p->writeidx - p->readidx;
        }

        /* how much data to deal with from the buffer */
        numbytes = remainbuf;

        if (!p->total_num) {
            /* No payload package area allocated yet. To know the
               size of this payload, we need to decrypt the first
               blocksize data. */

            if (numbytes < blocksize) {
                /* we can't act on anything less than blocksize, but this
                   check is only done for the initial block since once we have
                   got the start of a block we can in fact deal with fractions
                */
                return PACKET_EAGAIN;
            }

            if (encrypted) {
                rc = decrypt(session, &p->buf[p->readidx], block, blocksize);
                if (rc != PACKET_NONE) {
                    return rc;
                }
                /* save the first 5 bytes of the decrypted package, to be
                   used in the hash calculation later down. */
                memcpy(p->init, &p->buf[p->readidx], 5);
            } else {
                /* the data is plain, just copy it verbatim to
                   the working block buffer */
                memcpy(block, &p->buf[p->readidx], blocksize);
            }

            /* advance the read pointer */
            p->readidx += blocksize;

            /* we now have the initial blocksize bytes decrypted,
             * and we can extract packet and padding length from it
             */
            p->packet_length = libssh2_ntohu32(block);
            p->padding_length = block[4];

            /* total_num is the number of bytes following the initial
               (5 bytes) packet length and padding length fields */
            p->total_num =
                p->packet_length - 1 +
                (encrypted ? session->remote.mac->mac_len : 0);

            /* RFC4253 section 6.1 Maximum Packet Length says:
             *
             * "All implementations MUST be able to process
             * packets with uncompressed payload length of 32768
             * bytes or less and total packet size of 35000 bytes
             * or less (including length, padding length, payload,
             * padding, and MAC.)."
             */
            if (p->total_num > LIBSSH2_PACKET_MAXPAYLOAD) {
                return PACKET_TOOBIG;
            }

            /* Get a packet handle put data into. We get one to
               hold all data, including padding and MAC. */
            p->payload = LIBSSH2_ALLOC(session, p->total_num);
            if (!p->payload) {
                return PACKET_ENOMEM;
            }
            /* init write pointer to start of payload buffer */
            p->wptr = p->payload;

            if (blocksize > 5) {
                /* copy the data from index 5 to the end of
                   the blocksize from the temporary buffer to
                   the start of the decrypted buffer */
                memcpy(p->wptr, &block[5], blocksize - 5);
                p->wptr += blocksize - 5;       /* advance write pointer */
            }

            /* init the data_num field to the number of bytes of
               the package read so far */
            p->data_num = p->wptr - p->payload;

            /* we already dealt with a blocksize worth of data */
            numbytes -= blocksize;
        }

        /* how much there is left to add to the current payload
           package */
        remainpack = p->total_num - p->data_num;

        if (numbytes > remainpack) {
            /* if we have more data in the buffer than what is going into this
               particular packet, we limit this round to this packet only */
            numbytes = remainpack;
        }

        if (encrypted) {
            /* At the end of the incoming stream, there is a MAC,
               and we don't want to decrypt that since we need it
               "raw". We MUST however decrypt the padding data
               since it is used for the hash later on. */
            int skip = session->remote.mac->mac_len;

            /* if what we have plus numbytes is bigger than the
               total minus the skip margin, we should lower the
               amount to decrypt even more */
            if ((p->data_num + numbytes) > (p->total_num - skip)) {
                numdecrypt = (p->total_num - skip) - p->data_num;
            } else {
                int frac;
                numdecrypt = numbytes;
                frac = numdecrypt % blocksize;
                if (frac) {
                    /* not an aligned amount of blocks,
                       align it */
                    numdecrypt -= frac;
                    /* and make it no unencrypted data
                       after it */
                    numbytes = 0;
                }
            }
        } else {
            /* unencrypted data should not be decrypted at all */
            numdecrypt = 0;
        }

        /* if there are bytes to decrypt, do that */
        if (numdecrypt > 0) {
            /* now decrypt the lot */
            rc = decrypt(session, &p->buf[p->readidx], p->wptr, numdecrypt);
            if (rc != PACKET_NONE) {
                return rc;
            }

            /* advance the read pointer */
            p->readidx += numdecrypt;
            /* advance write pointer */
            p->wptr += numdecrypt;
            /* increse data_num */
            p->data_num += numdecrypt;

            /* bytes left to take care of without decryption */
            numbytes -= numdecrypt;
        }

        /* if there are bytes to copy that aren't decrypted, simply
           copy them as-is to the target buffer */
        if (numbytes > 0) {
            memcpy(p->wptr, &p->buf[p->readidx], numbytes);

            /* advance the read pointer */
            p->readidx += numbytes;
            /* advance write pointer */
            p->wptr += numbytes;
            /* increse data_num */
            p->data_num += numbytes;
        }

        /* now check how much data there's left to read to finish the
           current packet */
        remainpack = p->total_num - p->data_num;

        if (!remainpack) {
            /* we have a full packet */
          libssh2_packet_read_point1:
            rc = fullpacket(session, encrypted);
            if (rc == PACKET_EAGAIN) {
                session->readPack_encrypted = encrypted;
                session->readPack_state = libssh2_NB_state_jump1;
                return PACKET_EAGAIN;
            }

            p->total_num = 0;   /* no packet buffer available */

            return rc;
        }
    } while (1);                /* loop */

    return PACKET_FAIL;         /* we never reach this point */
}
Example #16
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;
}
Example #17
0
/* {{{ libssh2_publickey_list_fetch
 * Fetch a list of supported public key from a server
 */
LIBSSH2_API int libssh2_publickey_list_fetch(LIBSSH2_PUBLICKEY *pkey, unsigned long *num_keys, libssh2_publickey_list **pkey_list)
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	libssh2_publickey_list *list = NULL;
	unsigned char *s, buffer[12], *data = NULL;
	unsigned long buffer_len = 12, keys = 0, max_keys = 0, data_len, i, response;
	/*	packet_len(4) + 
		list_len(4) +
		"list"(4) */

	s = buffer;
	libssh2_htonu32(s, buffer_len - 4);							s += 4;
	libssh2_htonu32(s, sizeof("list") - 1);						s += 4;
	memcpy(s, "list", sizeof("list") - 1);						s += sizeof("list") - 1;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"list\" packet");
#endif
    if ((s - buffer) != libssh2_channel_write(channel, buffer, (s - buffer))) {
        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey list packet", 0);
		return -1;
    }

	while (1) {
		if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
			goto err_exit;
		}

		s = data;
		if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
			libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
			goto err_exit;
		}

		switch (response) {
			case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
			/* Error, or processing complete */
			{
				unsigned long status, descr_len, lang_len;
				unsigned char *descr, *lang;
				
				status = libssh2_ntohu32(s);					s += 4;
				descr_len = libssh2_ntohu32(s);					s += 4;
				descr = s;										s += descr_len;
				lang_len = libssh2_ntohu32(s);					s += 4;
				lang = s;										s += lang_len;

				if (s > data + data_len) {
					libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
					goto err_exit;
				}

				if (status == LIBSSH2_PUBLICKEY_SUCCESS) {
					LIBSSH2_FREE(session, data);
					*pkey_list = list;
					*num_keys = keys;
					return 0;
				}

				libssh2_publickey_status_error(pkey, session, status, descr, descr_len);
				goto err_exit;
			}
			case LIBSSH2_PUBLICKEY_RESPONSE_PUBLICKEY:
				/* What we want */
				if (keys >= max_keys) {
					/* Grow the key list if necessary */
					max_keys += 8;
					list = LIBSSH2_REALLOC(session, list, (max_keys + 1) * sizeof(libssh2_publickey_list));
					if (!list) {
						libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey list", 0);
						goto err_exit;
					}
				}
				if (pkey->version == 1) {
					unsigned long comment_len;

					comment_len = libssh2_ntohu32(s);								s += 4;
					if (comment_len) {
						list[keys].num_attrs = 1;
						list[keys].attrs = LIBSSH2_ALLOC(session, sizeof(libssh2_publickey_attribute));
						if (!list[keys].attrs) {
							libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
							goto err_exit;
						}
						list[keys].attrs[0].name = "comment";
						list[keys].attrs[0].name_len = sizeof("comment") - 1;
						list[keys].attrs[0].value = s;
						list[keys].attrs[0].value_len = comment_len;
						list[keys].attrs[0].mandatory = 0;

						s += comment_len;
					} else {
						list[keys].num_attrs = 0;
						list[keys].attrs = NULL;
					}
					list[keys].name_len = libssh2_ntohu32(s);						s += 4;
					list[keys].name = s;											s += list[keys].name_len;
					list[keys].blob_len = libssh2_ntohu32(s);						s += 4;
					list[keys].blob = s;											s += list[keys].blob_len;
				} else {
					/* Version == 2 */
					list[keys].name_len = libssh2_ntohu32(s);						s += 4;
					list[keys].name = s;											s += list[keys].name_len;
					list[keys].blob_len = libssh2_ntohu32(s);						s += 4;
					list[keys].blob = s;											s += list[keys].blob_len;
					list[keys].num_attrs = libssh2_ntohu32(s);						s += 4;
					if (list[keys].num_attrs) {
						list[keys].attrs = LIBSSH2_ALLOC(session, list[keys].num_attrs * sizeof(libssh2_publickey_attribute));
						if (!list[keys].attrs) {
							libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey attributes", 0);
							goto err_exit;
						}
						for(i = 0; i < list[keys].num_attrs; i++) {
							list[keys].attrs[i].name_len = libssh2_ntohu32(s);			s += 4;
							list[keys].attrs[i].name = s;								s += list[keys].attrs[i].name_len;
							list[keys].attrs[i].value_len = libssh2_ntohu32(s);			s += 4;
							list[keys].attrs[i].value = s;								s += list[keys].attrs[i].value_len;
							list[keys].attrs[i].mandatory = 0;	/* actually an ignored value */
						}
					} else {
						list[keys].attrs = NULL;
					}
				}
				list[keys].packet = data; /* To be FREEd in libssh2_publickey_list_free() */
				keys++;

				list[keys].packet = NULL; /* Terminate the list */
				data = NULL;
				break;
			default:
				/* Unknown/Unexpected */
				libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
				LIBSSH2_FREE(session, data);
		}
	}

	/* Only reached via explicit goto */
 err_exit:
	if (data) {
		LIBSSH2_FREE(session, data);
	}
	if (list) {
		libssh2_publickey_list_free(pkey, list);
	}
	return -1;
}
Example #18
0
/* {{{ libssh2_kex_agree_methods
 * Decide which specific method to use of the methods offered by each party
 */
static int libssh2_kex_agree_methods(LIBSSH2_SESSION *session, unsigned char *data, unsigned data_len)
{
	unsigned char *kex, *hostkey, *crypt_cs, *crypt_sc, *comp_cs, *comp_sc, *mac_cs, *mac_sc, *lang_cs, *lang_sc;
	size_t kex_len, hostkey_len, crypt_cs_len, crypt_sc_len, comp_cs_len, comp_sc_len, mac_cs_len, mac_sc_len, lang_cs_len, lang_sc_len;
	unsigned char *s = data;

	/* Skip packet_type, we know it already */
	s++;

	/* Skip cookie, don't worry, it's preserved in the kexinit field */
	s += 16;

	/* Locate each string */
	kex_len			= libssh2_ntohu32(s);		kex			= s + 4;		s += 4 + kex_len;
	hostkey_len		= libssh2_ntohu32(s);		hostkey		= s + 4;		s += 4 + hostkey_len;
	crypt_cs_len	= libssh2_ntohu32(s);		crypt_cs	= s + 4;		s += 4 + crypt_cs_len;
	crypt_sc_len	= libssh2_ntohu32(s);		crypt_sc	= s + 4;		s += 4 + crypt_sc_len;
	mac_cs_len		= libssh2_ntohu32(s);		mac_cs		= s + 4;		s += 4 + mac_cs_len;
	mac_sc_len		= libssh2_ntohu32(s);		mac_sc		= s + 4;		s += 4 + mac_sc_len;
	comp_cs_len		= libssh2_ntohu32(s);		comp_cs		= s + 4;		s += 4 + comp_cs_len;
	comp_sc_len		= libssh2_ntohu32(s);		comp_sc		= s + 4;		s += 4 + comp_sc_len;
	lang_cs_len		= libssh2_ntohu32(s);		lang_cs		= s + 4;		s += 4 + lang_cs_len;
	lang_sc_len		= libssh2_ntohu32(s);		lang_sc		= s + 4;		s += 4 + lang_sc_len;

	/* If the server sent an optimistic packet, assume that it guessed wrong.
	 * If the guess is determined to be right (by libssh2_kex_agree_kex_hostkey)
	 * This flag will be reset to zero so that it's not ignored */
	session->burn_optimistic_kexinit = *(s++);
	/* Next uint32 in packet is all zeros (reserved) */

	if (libssh2_kex_agree_kex_hostkey(session, kex, kex_len, hostkey, hostkey_len)) {
		return -1;
	}

	if (libssh2_kex_agree_crypt(session, &session->local,  crypt_cs, crypt_cs_len) ||
		libssh2_kex_agree_crypt(session, &session->remote, crypt_sc, crypt_sc_len)) {
		return -1;
	}

	if (libssh2_kex_agree_mac(session, &session->local,  mac_cs, mac_cs_len) ||
		libssh2_kex_agree_mac(session, &session->remote, mac_sc, mac_sc_len)) {
		return -1;
	}

	if (libssh2_kex_agree_comp(session, &session->local,  comp_cs, comp_cs_len) ||
		libssh2_kex_agree_comp(session, &session->remote, comp_sc, comp_sc_len)) {
		return -1;
	}

	if (libssh2_kex_agree_lang(session, &session->local,  lang_cs, lang_cs_len) ||
		libssh2_kex_agree_lang(session, &session->remote, lang_sc, lang_sc_len)) {
		return -1;
	}

#ifdef LIBSSH2_DEBUG_KEX
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on KEX method: %s", session->kex->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on HOSTKEY method: %s", session->hostkey->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_CS method: %s", session->local.crypt->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on CRYPT_SC method: %s", session->remote.crypt->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_CS method: %s", session->local.mac->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on MAC_SC method: %s", session->remote.mac->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_CS method: %s", session->local.comp->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on COMP_SC method: %s", session->remote.comp->name);
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_CS method:"); /* None yet */
	_libssh2_debug(session, LIBSSH2_DBG_KEX, "Agreed on LANG_SC method:"); /* None yet */
#endif

	/* Initialize compression layer */
	if (session->local.comp && session->local.comp->init &&
		session->local.comp->init(session, 1, &session->local.comp_abstract)) {
		return -1;
	}

	if (session->remote.comp && session->remote.comp->init &&
		session->remote.comp->init(session, 0, &session->remote.comp_abstract)) {
		return -1;
	}

	return 0;
}
Example #19
0
/* {{{ 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;
	}
}
Example #20
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;
    }
}
Example #21
0
/* {{{ libssh2_packet_read
 * Collect a packet into the input brigade
 * block only controls whether or not to wait for a packet to start,
 * Once a packet starts, libssh2 will block until it is complete
 * Returns packet type added to input brigade (0 if nothing added), or -1 on failure
 */
int libssh2_packet_read(LIBSSH2_SESSION *session, int should_block)
{
	int packet_type = -1;

	if (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) {
		return 0;
	}

#ifndef WIN32
	fcntl(session->socket_fd, F_SETFL, O_NONBLOCK);
#else
	{
		u_long non_block = TRUE;
		ioctlsocket(session->socket_fd, FIONBIO, &non_block);
	}
#endif

#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Checking for packet: will%s block", should_block ? "" : " not");
#endif
	if (session->state & LIBSSH2_STATE_NEWKEYS) {
		/* Temporary Buffer
		 * The largest blocksize (currently) is 32, the largest MAC (currently) is 20
		 */
		unsigned char block[2 * 32], *payload, *s, tmp[6];
		long read_len;
		unsigned long blocksize = session->remote.crypt->blocksize;
		unsigned long packet_len, payload_len;
		int padding_len;
		int macstate;
		int free_payload = 1;
		/* Safely ignored in CUSTOM cipher mode */
		EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->remote.crypt_abstract;

		/* Note: If we add any cipher with a blocksize less than 6 we'll need to get more creative with this
		 * For now, all blocksize sizes are 8+
		 */
		if (should_block) {
			read_len = libssh2_blocking_read(session, block, blocksize);
		} else {
			read_len = recv(session->socket_fd, block, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
			if (read_len <= 0) {
				return 0;
			}
			read_len += libssh2_blocking_read(session, block + read_len, blocksize - read_len);
		}
		if (read_len < blocksize) {
			return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
		}

		if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
			EVP_Cipher(ctx, block + blocksize, block, blocksize);
			memcpy(block, block + blocksize, blocksize);
		} else {
			if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
				libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
				return -1;
			}
		}

		packet_len = libssh2_ntohu32(block);
		padding_len = block[4];
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing packet %lu bytes long (with %lu bytes padding)", packet_len, padding_len);
#endif
		memcpy(tmp, block, 5); /* Use this for MAC later */

		payload_len = packet_len - 1; /* padding_len(1) */
		/* Sanity Check */
		if ((payload_len > LIBSSH2_PACKET_MAXPAYLOAD) ||
			((packet_len + 4) % blocksize)) {
			/* If something goes horribly wrong during the decryption phase, just bailout and die gracefully */
			session->socket_state = LIBSSH2_SOCKET_DISCONNECTED;
			libssh2_error(session, LIBSSH2_ERROR_PROTO, "Fatal protocol error, invalid payload size", 0);
			return -1;
		}

		s = payload = LIBSSH2_ALLOC(session, payload_len);
		memcpy(s, block + 5, blocksize - 5);
		s += blocksize - 5;

		while ((s - payload) < payload_len) {
			read_len = libssh2_blocking_read(session, block, blocksize);
			if (read_len < blocksize) {
				LIBSSH2_FREE(session, payload);
				return -1;
			}
			if (session->remote.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
				EVP_Cipher(ctx, block + blocksize, block, blocksize);
				memcpy(s, block + blocksize, blocksize);
			} else {
				if (session->remote.crypt->crypt(session, block, &session->remote.crypt_abstract)) {
					libssh2_error(session, LIBSSH2_ERROR_DECRYPT, "Error decrypting packet preamble", 0);
					LIBSSH2_FREE(session, payload);
					return -1;
				}
				memcpy(s, block, blocksize);
			}

			s += blocksize;
		}

		read_len = libssh2_blocking_read(session, block, session->remote.mac->mac_len);
		if (read_len < session->remote.mac->mac_len) {
			LIBSSH2_FREE(session, payload);
			return -1;
		}

		/* Calculate MAC hash */
 		session->remote.mac->hash(session, block + session->remote.mac->mac_len, session->remote.seqno, tmp, 5, payload, payload_len, &session->remote.mac_abstract);

		macstate =  (strncmp(block, block + session->remote.mac->mac_len, session->remote.mac->mac_len) == 0) ? LIBSSH2_MAC_CONFIRMED : LIBSSH2_MAC_INVALID;

		session->remote.seqno++;

		/* Ignore padding */
		payload_len -= padding_len;

		if (session->remote.comp &&
			strcmp(session->remote.comp->name, "none")) {
			/* Decompress */
			unsigned char *data;
			unsigned long data_len;

			if (session->remote.comp->comp(session, 0, &data, &data_len, LIBSSH2_PACKET_MAXDECOMP, &free_payload, payload, payload_len, &session->remote.comp_abstract)) {
				LIBSSH2_FREE(session, payload);
				return -1;
			}
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Payload decompressed: %lu bytes(compressed) to %lu bytes(uncompressed)", data_len, payload_len);
#endif
			if (free_payload) {
				LIBSSH2_FREE(session, payload);
				payload = data;
				payload_len = data_len;
			} else {
				if (data == payload) {
					/* It's not to be freed, because the compression layer reused payload,
					 * So let's do the same!
					 */
					payload_len = data_len;
				} else {
					/* No comp_method actually lets this happen, but let's prepare for the future */

					LIBSSH2_FREE(session, payload);

					/* We need a freeable struct otherwise the brigade won't know what to do with it */
					payload = LIBSSH2_ALLOC(session, data_len);
					if (!payload) {
						libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of uncompressed data", 0);
						return -1;
					}
					memcpy(payload, data, data_len);
					payload_len = data_len;
				}
			}
		}

		packet_type = payload[0];
		libssh2_packet_add(session, payload, payload_len, macstate);

	} else { /* No cipher active */
		unsigned char *payload;
		unsigned char buf[24];
		unsigned long buf_len, payload_len;
		unsigned long packet_length;
		unsigned long padding_length;

		if (should_block) {
			buf_len = libssh2_blocking_read(session, buf, 5);
		} else {
			buf_len = recv(session->socket_fd, buf, 1, LIBSSH2_SOCKET_RECV_FLAGS(session));
			if (buf_len <= 0) {
				return 0;
			}
			buf_len += libssh2_blocking_read(session, buf, 5 - buf_len);
		}
		if (buf_len < 5) {
			/* Something bad happened */
			return -1;
		}
		packet_length = libssh2_ntohu32(buf);
		padding_length = buf[4];
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Processing plaintext packet %lu bytes long (with %lu bytes padding)", packet_length, padding_length);
#endif

		payload_len = packet_length - padding_length - 1; /* padding_length(1) */
		payload = LIBSSH2_ALLOC(session, payload_len);
		if (!payload) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for copy of plaintext data", 0);
			return -1;
		}

		if (libssh2_blocking_read(session, payload, payload_len) < payload_len) {
			return (session->socket_state == LIBSSH2_SOCKET_DISCONNECTED) ? 0 : -1;
		}
		while (padding_length) {
			int l;
			/* Flush padding */
			l = libssh2_blocking_read(session, buf, padding_length);
			if (l > 0)
				padding_length -= l;
			else
				break;
		}

		packet_type = payload[0];

		/* MACs don't exist in non-encrypted mode */
		libssh2_packet_add(session, payload, payload_len, LIBSSH2_MAC_CONFIRMED);
		session->remote.seqno++;
	}
	return packet_type;
}
Example #22
0
/* {{{ libssh2_publickey_init
 * Startup the publickey subsystem
 */
LIBSSH2_API LIBSSH2_PUBLICKEY *libssh2_publickey_init(LIBSSH2_SESSION *session)
{
	LIBSSH2_PUBLICKEY *pkey = NULL;
	LIBSSH2_CHANNEL *channel = NULL;
	unsigned char buffer[19];
	/*	packet_len(4) + 
		version_len(4) + 
		"version"(7) + 
		version_num(4) */
	unsigned char *s, *data = NULL;
	unsigned long data_len;
	int response;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Initializing publickey subsystem");
#endif

	channel = libssh2_channel_open_session(session);
	if (!channel) {
		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to startup channel", 0);
		goto err_exit;
	}
	if (libssh2_channel_subsystem(channel, "publickey")) {
		libssh2_error(session, LIBSSH2_ERROR_CHANNEL_FAILURE, "Unable to request publickey subsystem", 0);
		goto err_exit;
	}

	libssh2_channel_set_blocking(channel, 1);
	libssh2_channel_handle_extended_data(channel, LIBSSH2_CHANNEL_EXTENDED_DATA_IGNORE);

	pkey = LIBSSH2_ALLOC(session, sizeof(LIBSSH2_PUBLICKEY));
	if (!pkey) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate a new publickey structure", 0);
		goto err_exit;
	}
	pkey->channel = channel;
	pkey->version = 0;

	s = buffer;
	libssh2_htonu32(s, 4 + (sizeof("version") - 1) + 4);	s += 4;
	libssh2_htonu32(s, sizeof("version") - 1);				s += 4;
	memcpy(s, "version", sizeof("version") - 1);			s += sizeof("version") - 1;
	libssh2_htonu32(s, LIBSSH2_PUBLICKEY_VERSION);			s += 4;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey version packet advertising version %d support", (int)LIBSSH2_PUBLICKEY_VERSION);
#endif
    if ((s - buffer) != libssh2_channel_write(channel, buffer, (s - buffer))) {
        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey version packet", 0);
		goto err_exit;
    }

	while (1) {
		if (libssh2_publickey_packet_receive(pkey, &data, &data_len)) {
			libssh2_error(session, LIBSSH2_ERROR_SOCKET_TIMEOUT, "Timeout waiting for response from publickey subsystem", 0);
			goto err_exit;
		}

		s = data;
		if ((response = libssh2_publickey_response_id(&s, data_len)) < 0) {
			libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Invalid publickey subsystem response code", 0);
			goto err_exit;
		}

		switch (response) {
			case LIBSSH2_PUBLICKEY_RESPONSE_STATUS:
			/* Error */
			{
				unsigned long status, descr_len, lang_len;
				unsigned char *descr, *lang;
				
				status = libssh2_ntohu32(s);					s += 4;
				descr_len = libssh2_ntohu32(s);					s += 4;
				descr = s;										s += descr_len;
				lang_len = libssh2_ntohu32(s);					s += 4;
				lang = s;										s += lang_len;

				if (s > data + data_len) {
					libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Malformed publickey subsystem packet", 0);
					goto err_exit;
				}

				libssh2_publickey_status_error(NULL, session, status, descr, descr_len);
				goto err_exit;
			}
			case LIBSSH2_PUBLICKEY_RESPONSE_VERSION:
				/* What we want */
				pkey->version = libssh2_ntohu32(s);
				if (pkey->version > LIBSSH2_PUBLICKEY_VERSION) {
#ifdef LIBSSH2_DEBUG_PUBLICKEY
					_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Truncating remote publickey version from %lu", pkey->version);
#endif
					pkey->version = LIBSSH2_PUBLICKEY_VERSION;
				}
#ifdef LIBSSH2_DEBUG_PUBLICKEY
				_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Enabling publickey subsystem version %lu", pkey->version);
#endif
				LIBSSH2_FREE(session, data);
				return pkey;
			default:
				/* Unknown/Unexpected */
				libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_PROTOCOL, "Unexpected publickey subsystem response, ignoring", 0);
				LIBSSH2_FREE(session, data);
				data = NULL;
		}
	}

	/* Never reached except by direct goto */
 err_exit:
	if (channel) {
		libssh2_channel_close(channel);
	}
	if (pkey) {
		LIBSSH2_FREE(session, pkey);
	}
	if (data) {
		LIBSSH2_FREE(session, data);
	}
	return NULL;
}