コード例 #1
0
ファイル: kex.c プロジェクト: Baskaran/ConnectionKit
/* {{{ 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;
}
コード例 #2
0
ファイル: userauth.c プロジェクト: Baskaran/ConnectionKit
/* {{{ 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;
}
コード例 #3
0
ファイル: mac.c プロジェクト: RangelReale/sandbox
/* {{{ libssh2_mac_method_hmac_ripemd160_hash
 * Calculate hash using ripemd160 value
 */
static int
libssh2_mac_method_hmac_ripemd160_hash(LIBSSH2_SESSION * session,
                                       unsigned char *buf, unsigned long seqno,
                                       const unsigned char *packet,
                                       unsigned long packet_len,
                                       const unsigned char *addtl,
                                       unsigned long addtl_len,
                                       void **abstract)
{
    libssh2_hmac_ctx ctx;
    unsigned char seqno_buf[4];
    (void) session;

    libssh2_htonu32(seqno_buf, seqno);

    libssh2_hmac_ripemd160_init(&ctx, *abstract, 20);
    libssh2_hmac_update(ctx, seqno_buf, 4);
    libssh2_hmac_update(ctx, packet, packet_len);
    if (addtl && addtl_len) {
        libssh2_hmac_update(ctx, addtl, addtl_len);
    }
    libssh2_hmac_final(ctx, buf);
    libssh2_hmac_cleanup(&ctx);

    return 0;
}
コード例 #4
0
ファイル: publickey.c プロジェクト: Zarzuelo/pandorafms
/* {{{ libssh2_publickey_remove_ex
 * Remove an existing publickey so that authentication can no longer be performed using it
 */
LIBSSH2_API int libssh2_publickey_remove_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
                                                            const unsigned char *blob, unsigned long blob_len)
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	unsigned char *s, *packet = NULL;
	unsigned long packet_len = 22 + name_len + blob_len;
	/*	packet_len(4) + 
		remove_len(4) +
		"remove"(6) +
		name_len(4) +
		{name}
		blob_len(4) +
		{blob} */

	packet = LIBSSH2_ALLOC(session, packet_len);
	if (!packet) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"remove\" packet", 0);
		return -1;
	}

	s = packet;
	libssh2_htonu32(s, packet_len - 4);							s += 4;
	libssh2_htonu32(s, sizeof("remove") - 1);					s += 4;
	memcpy(s, "remove", sizeof("remove") - 1);					s += sizeof("remove") - 1;
	libssh2_htonu32(s, name_len);								s += 4;
	memcpy(s, name, name_len);									s += name_len;
	libssh2_htonu32(s, blob_len);								s += 4;
	memcpy(s, blob, blob_len);									s += blob_len;

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"remove\" packet: type=%s blob_len=%ld", name, blob_len);
#endif
    if ((s - packet) != libssh2_channel_write(channel, packet, (s - packet))) {
        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey remove packet", 0);
		LIBSSH2_FREE(session, packet);
		return -1;
    }
	LIBSSH2_FREE(session, packet);
	packet = NULL;

	return libssh2_publickey_response_success(pkey);
}
コード例 #5
0
ファイル: kex.c プロジェクト: Baskaran/ConnectionKit
/* {{{ libssh2_kex_method_list
 * Generate formatted preference list in buf
 */
static size_t libssh2_kex_method_list(unsigned char *buf, size_t list_strlen, LIBSSH2_COMMON_METHOD **method)
{
	libssh2_htonu32(buf, list_strlen);
	buf += 4;

	if (!method || !*method) {
		return 4;
	}

	while (*method && (*method)->name) {
		int mlen = strlen((*method)->name);
		memcpy(buf, (*method)->name, mlen);
		buf += mlen;
		*(buf++) = ',';
		method++;
	}

	return list_strlen + 4;
}
コード例 #6
0
ファイル: mac.c プロジェクト: Zarzuelo/pandorafms
/* {{{ libssh2_mac_method_hmac_sha1_hash
 * Calculate hash using full sha1 value
 */
static int libssh2_mac_method_hmac_sha1_hash(LIBSSH2_SESSION *session, unsigned char *buf, unsigned long seqno,
																	   const unsigned char *packet, unsigned long packet_len, 
																	   const unsigned char *addtl, unsigned long addtl_len, void **abstract)
{
	HMAC_CTX ctx;
	unsigned char seqno_buf[4];

	libssh2_htonu32(seqno_buf, seqno);

	HMAC_Init(&ctx, *abstract, 20, EVP_sha1());
	HMAC_Update(&ctx, seqno_buf, 4);
	HMAC_Update(&ctx, packet, packet_len);
	if (addtl && addtl_len) {
		HMAC_Update(&ctx, addtl, addtl_len);
	}
	HMAC_Final(&ctx, buf, NULL);
	HMAC_cleanup(&ctx);

	return 0;
}
コード例 #7
0
ファイル: userauth.c プロジェクト: Baskaran/ConnectionKit
/* {{{ libssh2_userauth_publickey_fromfile_ex
 * Authenticate using a keypair found in the named files
 */
LIBSSH2_API int libssh2_userauth_publickey_fromfile_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
                                                                                 const char *publickey, const char *privatekey,
                                                                                 const char *passphrase)
{
	LIBSSH2_HOSTKEY_METHOD *privkeyobj;
	void *abstract;
	unsigned char buf[5];
	struct iovec datavec[4];
	unsigned char *method, *pubkeydata, *packet, *s, *b, *sig, *data;
	unsigned char reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PK_OK, 0 };
	unsigned long method_len, pubkeydata_len, packet_len, sig_len, data_len;

	if (libssh2_file_read_publickey(session, &method, &method_len, &pubkeydata, &pubkeydata_len, publickey)) {
		return -1;
	}

	packet_len = username_len + method_len + pubkeydata_len + 45;	/* packet_type(1) + username_len(4) + servicename_len(4) + 
																	   service_name(14)"ssh-connection" + authmethod_len(4) + 
																	   authmethod(9)"publickey" + sig_included(1)'\0' + 
																	   algmethod_len(4) + publickey_len(4) */
	/* Preallocate space for an overall length,  method name again,
	 * and the signature, which won't be any larger than the size of the publickeydata itself */
	s = packet = LIBSSH2_ALLOC(session, packet_len + 4 + (4 + method_len) + (4 + pubkeydata_len));

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

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

	libssh2_htonu32(s, 9);							s += 4;
	memcpy(s, "publickey", 9);						s += 9;

	b = s;
	*(s++) = 0; /* Not sending signature with *this* packet */

	libssh2_htonu32(s, method_len);					s += 4;
	memcpy(s, method, method_len);					s += method_len;

	libssh2_htonu32(s, pubkeydata_len);				s += 4;
	memcpy(s, pubkeydata, pubkeydata_len);			s += pubkeydata_len;

#ifdef LIBSSH2_DEBUG_USERAUTH
	_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication");
#endif
	if (libssh2_packet_write(session, packet, packet_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
		LIBSSH2_FREE(session, packet);
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, pubkeydata);
		return -1;
	}

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

	if (data[0] == SSH_MSG_USERAUTH_SUCCESS) {
#ifdef LIBSSH2_DEBUG_USERAUTH
		_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Pubkey authentication prematurely successful");
#endif
		/* God help any SSH server that allows an UNVERIFIED public key to validate the user */
		LIBSSH2_FREE(session, data);
		LIBSSH2_FREE(session, packet);
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, pubkeydata);
		session->state |= LIBSSH2_STATE_AUTHENTICATED;
		return 0;
	}

	if (data[0] == SSH_MSG_USERAUTH_FAILURE) {
		/* This public key is not allowed for this user on this server */
		LIBSSH2_FREE(session, data);
		LIBSSH2_FREE(session, packet);
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, pubkeydata);
		libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED, "Username/PublicKey combination invalid", 0);
		return -1;
	}

	/* Semi-Success! */
	LIBSSH2_FREE(session, data);
	LIBSSH2_FREE(session, pubkeydata);

	if (libssh2_file_read_privatekey(session, &privkeyobj, &abstract, (const char *)method, method_len, privatekey, passphrase)) {
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, packet);
		return -1;
	}

	*b = 0xFF;

	libssh2_htonu32(buf, session->session_id_len);
	datavec[0].iov_base = buf;
	datavec[0].iov_len = 4;
	datavec[1].iov_base = session->session_id;
	datavec[1].iov_len = session->session_id_len;
	datavec[2].iov_base = packet;
	datavec[2].iov_len = packet_len;

	if (privkeyobj->signv(session, &sig, &sig_len, 3, datavec, &abstract)) {
		LIBSSH2_FREE(session, method);
		LIBSSH2_FREE(session, packet);
		if (privkeyobj->dtor) {
			privkeyobj->dtor(session, &abstract);
		}
		return -1;
	}

	if (privkeyobj->dtor) {
		privkeyobj->dtor(session, &abstract);
	}

	if (sig_len > pubkeydata_len) {
		/* Should *NEVER* happen, but...well.. better safe than sorry */
		packet = LIBSSH2_REALLOC(session, packet, packet_len + 4 + (4 + method_len) + (4 + sig_len)); /* PK sigblob */
		if (!packet) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Failed allocating additional space for userauth-publickey packet", 0);
			LIBSSH2_FREE(session, method);
			return -1;
		}
	}

	s = packet + packet_len;

	libssh2_htonu32(s, 4 + method_len + 4 + sig_len);	s += 4;

	libssh2_htonu32(s, method_len);						s += 4;
	memcpy(s, method, method_len);						s += method_len;
	LIBSSH2_FREE(session, method);

	libssh2_htonu32(s, sig_len);						s += 4;
	memcpy(s, sig, sig_len);							s += sig_len;
	LIBSSH2_FREE(session, sig);

#ifdef LIBSSH2_DEBUG_USERAUTH
	_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting publickey authentication -- phase 2");
#endif
	if (libssh2_packet_write(session, packet, s - packet)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-publickey request", 0);
		LIBSSH2_FREE(session, packet);
		return -1;
	}
	LIBSSH2_FREE(session, packet);

	/* PK_OK is no longer valid */
	reply_codes[2] = 0;

	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, "Publickey authentication successful");
#endif
		/* We are us and we've proved it. */
		LIBSSH2_FREE(session, data);
		session->state |= LIBSSH2_STATE_AUTHENTICATED;
		return 0;
	}

	/* This public key is not allowed for this user on this server */
	LIBSSH2_FREE(session, data);
	libssh2_error(session, LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED, "Invalid signature for supplied public key, or bad username/public key combination", 0);
	return -1;
}
コード例 #8
0
ファイル: userauth.c プロジェクト: Baskaran/ConnectionKit
/* {{{ libssh2_userauth_password
 * Plain ol' login
 */
LIBSSH2_API int libssh2_userauth_password_ex(LIBSSH2_SESSION *session, const char *username, unsigned int username_len,
																					  const char *password, unsigned int password_len,
																					  LIBSSH2_PASSWD_CHANGEREQ_FUNC((*passwd_change_cb)))
{
	unsigned char *data, *s, reply_codes[4] = { SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, 0 };
	unsigned long data_len = username_len + password_len + 40; /* packet_type(1) + username_len(4) + service_len(4) + service(14)"ssh-connection" + 
																  method_len(4) + method(8)"password" + chgpwdbool(1) + password_len(4) */

	s = data = LIBSSH2_ALLOC(session, data_len);
	if (!data) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password request", 0);
		return -1;
	}

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

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

	libssh2_htonu32(s, sizeof("password") - 1);					s += 4;
	memcpy(s, "password", sizeof("password") - 1);				s += sizeof("password") - 1;

	*s = '\0';													s++;

	libssh2_htonu32(s, password_len);							s += 4;
	memcpy(s, password, password_len);							s += password_len;

#ifdef LIBSSH2_DEBUG_USERAUTH
	_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Attempting to login using password authentication");
#endif
	if (libssh2_packet_write(session, data, data_len)) {
		libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password request", 0);
		LIBSSH2_FREE(session, data);
		return -1;
	}
	LIBSSH2_FREE(session, data);

 password_response:
	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, "Password authentication successful");
#endif
		LIBSSH2_FREE(session, data);
		session->state |= LIBSSH2_STATE_AUTHENTICATED;
		return 0;
	}

	if (data[0] == SSH_MSG_USERAUTH_PASSWD_CHANGEREQ) {
		char *newpw = NULL;
		int newpw_len = 0;

#ifdef LIBSSH2_DEBUG_USERAUTH
		_libssh2_debug(session, LIBSSH2_DBG_AUTH, "Password change required");
#endif
		LIBSSH2_FREE(session, data);
		if (passwd_change_cb) {
			passwd_change_cb(session, &newpw, &newpw_len, &session->abstract);
			if (!newpw) {
				libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password expired, and callback failed", 0);
				return -1;
			}
			data_len = username_len + password_len + 44 + newpw_len; /* basic data_len + newpw_len(4) */
			s = data = LIBSSH2_ALLOC(session, data_len);
			if (!data) {
				libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for userauth-password-change request", 0);
				return -1;
			}

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

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

			libssh2_htonu32(s, sizeof("password") - 1);					s += 4;
			memcpy(s, "password", sizeof("password") - 1);				s += sizeof("password") - 1;

			*s = 0xFF;													s++;

			libssh2_htonu32(s, password_len);							s += 4;
			memcpy(s, password, password_len);							s += password_len;

			libssh2_htonu32(s, newpw_len);								s += 4;
			memcpy(s, newpw, newpw_len);								s += newpw_len;

			if (libssh2_packet_write(session, data, data_len)) {
				libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send userauth-password-change request", 0);
				LIBSSH2_FREE(session, data);
				return -1;
			}
			LIBSSH2_FREE(session, data);
			LIBSSH2_FREE(session, newpw);

			/* Ugliest use of goto ever.  Blame it on the askN => requirev migration. */
			goto password_response;
		} else {
			libssh2_error(session, LIBSSH2_ERROR_PASSWORD_EXPIRED, "Password Expired, and no callback specified", 0);
			return -1;
		}
	}

	/* FAILURE */
	LIBSSH2_FREE(session, data);
	return -1;
}
コード例 #9
0
ファイル: transport.c プロジェクト: roderico/linm
/* {{{ libssh2_packet_write
 * Send a packet, encrypting it and adding a MAC code if necessary
 * Returns 0 on success, non-zero on failure.
 *
 * Returns PACKET_EAGAIN if it would block - and if it does so, you should
 * call this function again as soon as it is likely that more data can be
 * sent, and this function should then be called with the same argument set
 * (same data pointer and same data_len) until zero or failure is returned.
 */
int
libssh2_packet_write(LIBSSH2_SESSION * session, unsigned char *data,
                     unsigned long data_len)
{
    int blocksize =
        (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->
        blocksize : 8;
    int padding_length;
    int packet_length;
    int total_length;
    int free_data = 0;
#ifdef RANDOM_PADDING
    int rand_max;
    int seed = data[0];         /* FIXME: make this random */
#endif
    struct transportpacket *p = &session->packet;
    int encrypted;
    int i;
    ssize_t ret;
    libssh2pack_t rc;
    unsigned char *orgdata = data;
    unsigned long orgdata_len = data_len;

    debugdump(session, "libssh2_packet_write plain", data, data_len);

    /* FIRST, check if we have a pending write to complete */
    rc = send_existing(session, data, data_len, &ret);
    if (rc || ret) {
        return rc;
    }

    encrypted = (session->state & LIBSSH2_STATE_NEWKEYS) ? 1 : 0;

    /* check if we should compress */
    if (encrypted && strcmp(session->local.comp->name, "none")) {
        if (session->local.comp->
            comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP,
                 &free_data, data, data_len, &session->local.comp_abstract)) {
            return PACKET_COMPRESS;     /* compression failure */
        }
    }

    /* RFC4253 says: Note that the length of the concatenation of
       'packet_length', 'padding_length', 'payload', and 'random padding'
       MUST be a multiple of the cipher block size or 8, whichever is
       larger. */

    /* Plain math: (4 + 1 + packet_length + padding_length) % blocksize == 0 */

    packet_length = data_len + 1 + 4;   /* 1 is for padding_length field
                                           4 for the packet_length field */

    /* at this point we have it all except the padding */

    /* first figure out our minimum padding amount to make it an even
       block size */
    padding_length = blocksize - (packet_length % blocksize);

    /* if the padding becomes too small we add another blocksize worth
       of it (taken from the original libssh2 where it didn't have any
       real explanation) */
    if (padding_length < 4) {
        padding_length += blocksize;
    }
#ifdef RANDOM_PADDING
    /* FIXME: we can add padding here, but that also makes the packets
       bigger etc */

    /* now we can add 'blocksize' to the padding_length N number of times
       (to "help thwart traffic analysis") but it must be less than 255 in
       total */
    rand_max = (255 - padding_length) / blocksize + 1;
    padding_length += blocksize * (seed % rand_max);
#endif

    packet_length += padding_length;

    /* append the MAC length to the total_length size */
    total_length =
        packet_length + (encrypted ? session->local.mac->mac_len : 0);

    /* allocate memory to store the outgoing packet in, in case we can't
       send the whole one and thus need to keep it after this function
       returns. */
    p->outbuf = LIBSSH2_ALLOC(session, total_length);
    if (!p->outbuf) {
        return PACKET_ENOMEM;
    }

    /* store packet_length, which is the size of the whole packet except
       the MAC and the packet_length field itself */
    libssh2_htonu32(p->outbuf, packet_length - 4);
    /* store padding_length */
    p->outbuf[4] = padding_length;
    /* copy the payload data */
    memcpy(p->outbuf + 5, data, data_len);
    /* fill the padding area with random junk */
    libssh2_random(p->outbuf + 5 + data_len, padding_length);
    if (free_data) {
        LIBSSH2_FREE(session, data);
    }

    if (encrypted) {
        /* Calculate MAC hash. Put the output at index packet_length,
           since that size includes the whole packet. The MAC is
           calculated on the entire unencrypted packet, including all
           fields except the MAC field itself. */
        session->local.mac->hash(session, p->outbuf + packet_length,
                                 session->local.seqno, p->outbuf,
                                 packet_length, NULL, 0,
                                 &session->local.mac_abstract);

        /* Encrypt the whole packet data, one block size at a time.
           The MAC field is not encrypted. */
        for(i = 0; i < packet_length; i += session->local.crypt->blocksize) {
            unsigned char *ptr = &p->outbuf[i];
            if (session->local.crypt->
                crypt(session, ptr, &session->local.crypt_abstract))
                return PACKET_FAIL;     /* encryption failure */
        }
    }

    session->local.seqno++;

    ret = send(session->socket_fd, p->outbuf, total_length,
               LIBSSH2_SOCKET_SEND_FLAGS(session));

    if (ret != -1) {
        debugdump(session, "libssh2_packet_write send()", p->outbuf, ret);
    }
    if (ret != total_length) {
        if ((ret > 0) || ((ret == -1) && (errno == EAGAIN))) {
            /* the whole packet could not be sent, save the rest */
            p->odata = orgdata;
            p->olen = orgdata_len;
            p->osent = (ret == -1) ? 0 : ret;
            p->ototal_num = total_length;
            return PACKET_EAGAIN;
        }
        return PACKET_FAIL;
    }

    /* the whole thing got sent away */
    p->odata = NULL;
    p->olen = 0;
    LIBSSH2_FREE(session, p->outbuf);
    p->outbuf = NULL;

    return PACKET_NONE;         /* all is good */
}
コード例 #10
0
ファイル: session.c プロジェクト: roderico/linm
/* {{{ libssh2_session_disconnect_ex
 */
LIBSSH2_API int
libssh2_session_disconnect_ex(LIBSSH2_SESSION * session, int reason,
                              const char *description, const char *lang)
{
    unsigned char *s;
    unsigned long descr_len = 0, lang_len = 0;
    int rc;

    if (session->disconnect_state == libssh2_NB_state_idle) {
        _libssh2_debug(session, LIBSSH2_DBG_TRANS,
                       "Disconnecting: reason=%d, desc=%s, lang=%s", reason,
                       description, lang);
        if (description) {
            descr_len = strlen(description);
        }
        if (lang) {
            lang_len = strlen(lang);
        }
        /* 13 = packet_type(1) + reason code(4) + descr_len(4) + lang_len(4) */
        session->disconnect_data_len = descr_len + lang_len + 13;

        s = session->disconnect_data =
            LIBSSH2_ALLOC(session, session->disconnect_data_len);
        if (!session->disconnect_data) {
            libssh2_error(session, LIBSSH2_ERROR_ALLOC,
                          "Unable to allocate memory for disconnect packet",
                          0);
            session->disconnect_state = libssh2_NB_state_idle;
            return -1;
        }

        *(s++) = SSH_MSG_DISCONNECT;
        libssh2_htonu32(s, reason);
        s += 4;

        libssh2_htonu32(s, descr_len);
        s += 4;
        if (description) {
            memcpy(s, description, descr_len);
            s += descr_len;
        }

        libssh2_htonu32(s, lang_len);
        s += 4;
        if (lang) {
            memcpy(s, lang, lang_len);
            s += lang_len;
        }

        session->disconnect_state = libssh2_NB_state_created;
    }

    rc = libssh2_packet_write(session, session->disconnect_data,
                              session->disconnect_data_len);
    if (rc == PACKET_EAGAIN) {
        return PACKET_EAGAIN;
    }

    LIBSSH2_FREE(session, session->disconnect_data);
    session->disconnect_data = NULL;
    session->disconnect_state = libssh2_NB_state_idle;

    return 0;
}
コード例 #11
0
ファイル: kex.c プロジェクト: Baskaran/ConnectionKit
/* {{{ 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;
}
コード例 #12
0
ファイル: packet.c プロジェクト: Zarzuelo/pandorafms
/* {{{ 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;
}
コード例 #13
0
ファイル: userauth.c プロジェクト: Baskaran/ConnectionKit
/* {{{ 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;
		}
	}
}
コード例 #14
0
ファイル: publickey.c プロジェクト: Zarzuelo/pandorafms
/* {{{ libssh2_publickey_add_ex
 * Add a new public key entry
 */
LIBSSH2_API int libssh2_publickey_add_ex(LIBSSH2_PUBLICKEY *pkey, const unsigned char *name, unsigned long name_len,
															const unsigned char *blob, unsigned long blob_len, char overwrite,
															unsigned long num_attrs, libssh2_publickey_attribute attrs[])
{
	LIBSSH2_CHANNEL *channel = pkey->channel;
	LIBSSH2_SESSION *session = channel->session;
	unsigned char *packet = NULL, *s;
	unsigned long i, packet_len = 19 + name_len + blob_len;
	unsigned char *comment = NULL;
	unsigned long comment_len = 0;
	/*	packet_len(4) +
		add_len(4) +
		"add"(3) +
		name_len(4) +
		{name}
		blob_len(4) +
		{blob} */

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Adding %s pubickey", name);
#endif

	if (pkey->version == 1) {
		for(i = 0; i < num_attrs; i++) {
			/* Search for a comment attribute */
			if (attrs[i].name_len == (sizeof("comment") - 1) &&
				strncmp(attrs[i].name, "comment", sizeof("comment") - 1) == 0) {
				comment = attrs[i].value;
				comment_len = attrs[i].value_len;
				break;
			}
		}
		packet_len += 4 + comment_len;
	} else {
		packet_len += 5; /* overwrite(1) + attribute_count(4) */
		for(i = 0; i < num_attrs; i++) {
			packet_len += 9 + attrs[i].name_len + attrs[i].value_len;
			/* name_len(4) + value_len(4) + mandatory(1) */
		}
	}

	packet = LIBSSH2_ALLOC(session, packet_len);
	if (!packet) {
		libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate memory for publickey \"add\" packet", 0);
		return -1;
	}

	s = packet;
	libssh2_htonu32(s, packet_len - 4);						s += 4;
	libssh2_htonu32(s, sizeof("add") - 1);					s += 4;
	memcpy(s, "add", sizeof("add") - 1);					s += sizeof("add") - 1;
	if (pkey->version == 1) {
		libssh2_htonu32(s, comment_len);					s += 4;
		if (comment) {
			memcpy(s, comment, comment_len);				s += comment_len;
		}

		libssh2_htonu32(s, name_len);						s += 4;
		memcpy(s, name, name_len);							s += name_len;
		libssh2_htonu32(s, blob_len);						s += 4;
		memcpy(s, blob, blob_len);							s += blob_len;
	} else {
		/* Version == 2 */

		libssh2_htonu32(s, name_len);						s += 4;
		memcpy(s, name, name_len);							s += name_len;
		libssh2_htonu32(s, blob_len);						s += 4;
		memcpy(s, blob, blob_len);							s += blob_len;
		*(s++) = overwrite ? 0xFF : 0;
		libssh2_htonu32(s, num_attrs);						s += 4;
		for(i = 0; i < num_attrs; i++) {
			libssh2_htonu32(s, attrs[i].name_len);			s += 4;
			memcpy(s, attrs[i].name, attrs[i].name_len);	s += attrs[i].name_len;
			libssh2_htonu32(s, attrs[i].value_len);			s += 4;
			memcpy(s, attrs[i].value, attrs[i].value_len);	s += attrs[i].value_len;
			*(s++) = attrs[i].mandatory ? 0xFF : 0;
		}
	}

#ifdef LIBSSH2_DEBUG_PUBLICKEY
	_libssh2_debug(session, LIBSSH2_DBG_PUBLICKEY, "Sending publickey \"add\" packet: type=%s blob_len=%ld num_attrs=%ld", name, blob_len, num_attrs);
#endif
    if ((s - packet) != libssh2_channel_write(channel, packet, (s - packet))) {
        libssh2_error(session, LIBSSH2_ERROR_SOCKET_SEND, "Unable to send publickey add packet", 0);
		LIBSSH2_FREE(session, packet);
		return -1;
    }
	LIBSSH2_FREE(session, packet);
	packet = NULL;

	return libssh2_publickey_response_success(pkey);
}
コード例 #15
0
ファイル: publickey.c プロジェクト: Zarzuelo/pandorafms
/* {{{ 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;
}
コード例 #16
0
ファイル: packet.c プロジェクト: RangelReale/sandbox
/* {{{ 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;
    }
}
コード例 #17
0
ファイル: packet.c プロジェクト: RangelReale/sandbox
/* {{{ 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;
}
コード例 #18
0
ファイル: packet.c プロジェクト: Zarzuelo/pandorafms
/* {{{ libssh2_packet_write
 * Send a packet, encrypting it and adding a MAC code if necessary
 * Returns 0 on success, non-zero on failure
 */
int libssh2_packet_write(LIBSSH2_SESSION *session, unsigned char *data, unsigned long data_len)
{
	unsigned long packet_length = data_len + 1;
	unsigned long block_size = (session->state & LIBSSH2_STATE_NEWKEYS) ? session->local.crypt->blocksize : 8;
	/* At this point packet_length doesn't include the packet_len field itself */
	unsigned long padding_length;
	int free_data = 0;
	unsigned char buf[246]; /* 6 byte header plus max padding size(240) */

#ifdef LIBSSH2_DEBUG_TRANSPORT
{
	/* Show a hint of what's being sent */
	char excerpt[32];
	int ex_len = 0, db_ofs = 0;

	for (; ex_len < 24 && db_ofs < data_len; ex_len += 3, db_ofs++) snprintf(excerpt + ex_len, 4, "%02X ", data[db_ofs]);
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet type %d, length=%lu, %s", (int)data[0], data_len, excerpt);
}
#endif
	if ((session->state & LIBSSH2_STATE_NEWKEYS) &&
		strcmp(session->local.comp->name, "none")) {

		if (session->local.comp->comp(session, 1, &data, &data_len, LIBSSH2_PACKET_MAXCOMP, &free_data, data, data_len, &session->local.comp_abstract)) {
			return -1;
		}
#ifdef LIBSSH2_DEBUG_TRANSPORT
		_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Compressed payload to %lu bytes", data_len);
#endif
	}

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

	packet_length = data_len + 1; /* padding_length(1) -- MAC doesn't count -- Padding to be added soon */
	padding_length = block_size - ((packet_length + 4) % block_size);
	if (padding_length < 4) {
		padding_length += block_size;
	}
	/* TODO: Maybe add 1 or 2 times block_size to padding_length randomly -- shake things up a bit... */

	packet_length += padding_length;
	libssh2_htonu32(buf, packet_length);
	buf[4] = padding_length;
#ifdef LIBSSH2_DEBUG_TRANSPORT
	_libssh2_debug(session, LIBSSH2_DBG_TRANS, "Sending packet with total length %lu (%lu bytes padding)", packet_length, padding_length);
#endif

	if (session->state & LIBSSH2_STATE_NEWKEYS) {
		/* Encryption is in effect */
		unsigned char *encbuf, *s;
		int ret;

		/* Safely ignored in CUSTOM cipher mode */
		EVP_CIPHER_CTX *ctx = (EVP_CIPHER_CTX *)session->local.crypt_abstract;

		/* include packet_length(4) itself and room for the hash at the end */
		encbuf = LIBSSH2_ALLOC(session, 4 + packet_length + session->local.mac->mac_len);
		if (!encbuf) {
			libssh2_error(session, LIBSSH2_ERROR_ALLOC, "Unable to allocate encryption buffer", 0);
			if (free_data) {
				LIBSSH2_FREE(session, data);
			}
			return -1;
		}

		/* Copy packet to encoding buffer */
		memcpy(encbuf, buf, 5);
		memcpy(encbuf + 5, data, data_len);
		RAND_bytes(encbuf + 5 + data_len, padding_length);
		if (free_data) {
			LIBSSH2_FREE(session, data);
		}

		/* Calculate MAC hash */
 		session->local.mac->hash(session, encbuf + 4 + packet_length , session->local.seqno, encbuf, 4 + packet_length, NULL, 0, &session->local.mac_abstract);

		/* Encrypt data */
		for(s = encbuf; (s - encbuf) < (4 + packet_length) ; s += session->local.crypt->blocksize) {
			if (session->local.crypt->flags & LIBSSH2_CRYPT_METHOD_FLAG_EVP) {
				EVP_Cipher(ctx, buf, s, session->local.crypt->blocksize);
				memcpy(s, buf, session->local.crypt->blocksize);
			} else {
				session->local.crypt->crypt(session, s, &session->local.crypt_abstract);
			}
		}

		session->local.seqno++;

		/* Send It */
		ret = ((4 + packet_length + session->local.mac->mac_len) == send(session->socket_fd, encbuf, 4 + packet_length + session->local.mac->mac_len, LIBSSH2_SOCKET_SEND_FLAGS(session))) ? 0 : -1;

		/* Cleanup environment */
		LIBSSH2_FREE(session, encbuf);

		return ret;
	} else { /* LIBSSH2_ENDPOINT_CRYPT_NONE */
		/* Simplified write for non-encrypted mode */
		struct iovec data_vector[3];

		/* Using vectors means we don't have to alloc a new buffer -- a byte saved is a byte earned
		 * No MAC during unencrypted phase
		 */
		data_vector[0].iov_base = buf;
		data_vector[0].iov_len = 5;
		data_vector[1].iov_base = (char*)data;
		data_vector[1].iov_len = data_len;
		data_vector[2].iov_base = buf + 5;
		data_vector[2].iov_len = padding_length;

		session->local.seqno++;

		/* Ignore this, it can't actually happen :) */
		if (free_data) {
			LIBSSH2_FREE(session, data);
		}

		return ((packet_length + 4) == writev(session->socket_fd, data_vector, 3)) ? 0 : 1;
	}
}
コード例 #19
0
ファイル: publickey.c プロジェクト: Zarzuelo/pandorafms
/* {{{ 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;
}
コード例 #20
0
ファイル: packet.c プロジェクト: Zarzuelo/pandorafms
/* {{{ 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;
	}
}
コード例 #21
0
ファイル: session.c プロジェクト: roderico/linm
/* {{{ 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;
}