void RedClient::on_connect() { AutoRef<ConnectedEvent> event(new ConnectedEvent()); push_event(*event); _migrate.add_channel(new MigChannel(SPICE_CHANNEL_MAIN, 0, get_common_caps(), get_caps())); }
void RedChannelBase::link(uint32_t connection_id, const std::string& password, int protocol) { SpiceLinkHeader header; SpiceLinkMess link_mess; SpiceLinkReply* reply; uint32_t link_res; uint32_t i; EVP_PKEY *pubkey; int nRSASize; BIO *bioKey; RSA *rsa; uint8_t *buffer, *p; uint32_t expected_major; header.magic = SPICE_MAGIC; header.size = sizeof(link_mess); if (protocol == 1) { /* protocol 1 == major 1, old 0.4 protocol, last active minor */ expected_major = header.major_version = 1; header.minor_version = 3; } else if (protocol == 2) { /* protocol 2 == current */ expected_major = header.major_version = SPICE_VERSION_MAJOR; header.minor_version = SPICE_VERSION_MINOR; } else { THROW("unsupported protocol version specified"); } link_mess.connection_id = connection_id; link_mess.channel_type = _type; link_mess.channel_id = _id; link_mess.num_common_caps = get_common_caps().size(); link_mess.num_channel_caps = get_caps().size(); link_mess.caps_offset = sizeof(link_mess); header.size += (link_mess.num_common_caps + link_mess.num_channel_caps) * sizeof(uint32_t); buffer = new uint8_t[sizeof(header) + sizeof(link_mess) + _common_caps.size() * sizeof(uint32_t) + _caps.size() * sizeof(uint32_t)]; p = buffer; memcpy(p, (uint8_t*)&header, sizeof(header)); p += sizeof(header); memcpy(p, (uint8_t*)&link_mess, sizeof(link_mess)); p += sizeof(link_mess); for (i = 0; i < _common_caps.size(); i++) { *(uint32_t *)p = _common_caps[i]; p += sizeof(uint32_t); } for (i = 0; i < _caps.size(); i++) { *(uint32_t *)p = _caps[i]; p += sizeof(uint32_t); } send(buffer, p - buffer); delete [] buffer; recive((uint8_t*)&header, sizeof(header)); if (header.magic != SPICE_MAGIC) { THROW_ERR(SPICEC_ERROR_CODE_CONNECT_FAILED, "bad magic"); } if (header.major_version != expected_major) { THROW_ERR(SPICEC_ERROR_CODE_VERSION_MISMATCH, "version mismatch: expect %u got %u", expected_major, header.major_version); } _remote_major = header.major_version; _remote_minor = header.minor_version; AutoArray<uint8_t> reply_buf(new uint8_t[header.size]); recive(reply_buf.get(), header.size); reply = (SpiceLinkReply *)reply_buf.get(); if (reply->error != SPICE_LINK_ERR_OK) { THROW_ERR(SPICEC_ERROR_CODE_CONNECT_FAILED, "connect error %u - %s", reply->error, spice_link_error_string(reply->error)); } uint32_t num_caps = reply->num_channel_caps + reply->num_common_caps; if ((uint8_t *)(reply + 1) > reply_buf.get() + header.size || (uint8_t *)reply + reply->caps_offset + num_caps * sizeof(uint32_t) > reply_buf.get() + header.size) { THROW_ERR(SPICEC_ERROR_CODE_CONNECT_FAILED, "access violation"); } uint32_t *caps = (uint32_t *)((uint8_t *)reply + reply->caps_offset); _remote_common_caps.clear(); for (i = 0; i < reply->num_common_caps; i++, caps++) { _remote_common_caps.resize(i + 1); _remote_common_caps[i] = *caps; } _remote_caps.clear(); for (i = 0; i < reply->num_channel_caps; i++, caps++) { _remote_caps.resize(i + 1); _remote_caps[i] = *caps; } bioKey = BIO_new(BIO_s_mem()); if (bioKey != NULL) { BIO_write(bioKey, reply->pub_key, SPICE_TICKET_PUBKEY_BYTES); pubkey = d2i_PUBKEY_bio(bioKey, NULL); rsa = pubkey->pkey.rsa; nRSASize = RSA_size(rsa); AutoArray<unsigned char> bufEncrypted(new unsigned char[nRSASize]); /* The use of RSA encryption limit the potential maximum password length. for RSA_PKCS1_OAEP_PADDING it is RSA_size(rsa) - 41. */ if (RSA_public_encrypt(password.length() + 1, (unsigned char *)password.c_str(), (uint8_t *)bufEncrypted.get(), rsa, RSA_PKCS1_OAEP_PADDING) > 0) { send((uint8_t*)bufEncrypted.get(), nRSASize); } else { THROW("could not encrypt password"); } memset(bufEncrypted.get(), 0, nRSASize); } else { THROW("Could not initiate BIO"); } BIO_free(bioKey); recive((uint8_t*)&link_res, sizeof(link_res)); if (link_res != SPICE_LINK_ERR_OK) { int error_code = (link_res == SPICE_LINK_ERR_PERMISSION_DENIED) ? SPICEC_ERROR_CODE_CONNECT_FAILED : SPICEC_ERROR_CODE_CONNECT_FAILED; THROW_ERR(error_code, "connect failed %u", link_res); } }