예제 #1
0
    void send_fastpath_data(InStream & data) {
        StaticOutStream<TRANSPARENT_CHUNK_HEADER_SIZE> header;
        this->make_chunk_header(header, CHUNK_TYPE_FASTPATH, data.get_capacity());

        assert(header.get_offset() == header.get_capacity());
        this->t->send(header.get_data(), header.get_capacity());
        this->t->send(data.get_data(), data.get_capacity());
    }
예제 #2
0
void CopyPaste::send_to_mod_channel(InStream & chunk, uint32_t flags)
{
    InStream stream(chunk.get_data(), chunk.get_capacity());

    if (this->long_data_response_size) {
        size_t available_data_length =
            std::min<size_t>(this->long_data_response_size, stream.in_remain());

        // if (this->long_data_response_size < stream.in_remain()) {
        //     LOG( LOG_ERR
        //         , "CopyPaste::send_to_mod_channel truncated CB_FORMAT_DATA_RESPONSE dataU16, need=%u remains=%u"
        //         , this->long_data_response_size, stream.in_remain());
        //     throw Error(ERR_RDP_PROTOCOL);
        // }

        if (available_data_length) {
            // this->long_data_response_size -= stream.in_remain();
            this->long_data_response_size -= available_data_length;
            // this->clipboard_str_.utf16_push_back(stream.p, stream.in_remain() / 2);
            this->clipboard_str_.utf16_push_back(stream.get_current(), available_data_length / 2);
        }

        // if (!this->long_data_response_size && this->paste_edit_) {
        if ((flags & CHANNELS::CHANNEL_FLAG_LAST) != 0) {
            if (this->paste_edit_) {
                this->paste_edit_->insert_text(this->clipboard_str_.c_str());
                this->paste_edit_ = nullptr;
            }

            this->long_data_response_size = 0;
        }

        return ;
    }

    RDPECLIP::RecvPredictor rp(stream);

    switch (rp.msgType()) {
        case RDPECLIP::CB_FORMAT_LIST:
            {
                RDPECLIP::CliprdrHeader clipboard_header;
                clipboard_header.recv(stream);

                RDPECLIP::FormatListPDUEx format_list_pdu;
                const bool use_long_format_names = false;
                const bool in_ASCII_8            = (clipboard_header.msgFlags() & RDPECLIP::CB_ASCII_NAMES);
                format_list_pdu.recv(stream, use_long_format_names, in_ASCII_8);

                RDPECLIP::FormatListResponsePDU pdu;
                RDPECLIP::CliprdrHeader header(RDPECLIP::CB_FORMAT_LIST_RESPONSE, RDPECLIP::CB_RESPONSE_OK, pdu.size());

                StaticOutStream<256> out_s;
                header.emit(out_s);
                pdu.emit(out_s);

                const size_t length     = out_s.get_offset();
                const size_t chunk_size = length;
                this->front_->send_to_channel(
                    *this->channel_, out_s.get_data(), length, chunk_size,
                    CHANNELS::CHANNEL_FLAG_FIRST | CHANNELS::CHANNEL_FLAG_LAST | CHANNELS::CHANNEL_FLAG_SHOW_PROTOCOL
                );

                this->has_clipboard_ = false;
                this->clipboard_str_.clear();
            }
            break;
        //case RDPECLIP::CB_FORMAT_LIST_RESPONSE:
        //    break;
        //case RDPECLIP::CB_FORMAT_DATA_REQUEST:
        //    RDPECLIP::FormatDataRequestPDU().recv(stream);
        //    this->send_to_front_channel_and_set_buf_size(
        //        this->clipboard_str_.size() * 2 /*utf8 to utf16*/ + sizeof(RDPECLIP::CliprdrHeader) + 4 /*data_len*/,
        //        RDPECLIP::FormatDataResponsePDU(true), this->clipboard_str_.c_str()
        //    );
        //    break;
        case RDPECLIP::CB_FORMAT_DATA_RESPONSE: {
            RDPECLIP::CliprdrHeader header(RDPECLIP::CB_FORMAT_DATA_RESPONSE, RDPECLIP::CB_RESPONSE_FAIL, 0);
            // TODO: format data response PDU is bypassed and the raw data is managed directly
            // we should not do that but reassemble data response packet from PDU before pasting
            // see also condition on this->long_data_response_size
//            RDPECLIP::FormatDataResponsePDU format_data_response_pdu;
            header.recv(stream);
//            format_data_response_pdu.recv(stream);
            if (header.msgFlags() == RDPECLIP::CB_RESPONSE_OK) {

                if ((flags & CHANNELS::CHANNEL_FLAG_LAST) != 0) {
                    if (!stream.in_check_rem(header.dataLen())) {
                        LOG( LOG_ERR
                            , "CopyPaste::send_to_mod_channel truncated CB_FORMAT_DATA_RESPONSE dataU16, need=%" PRIu32 " remains=%zu"
                            , header.dataLen(), stream.in_remain());
                        throw Error(ERR_RDP_PROTOCOL);
                    }

                    this->clipboard_str_.utf16_push_back(stream.get_current(), header.dataLen() / 2);

                    if (this->paste_edit_) {
                        this->paste_edit_->insert_text(this->clipboard_str_.c_str());
                        this->paste_edit_ = nullptr;
                    }

                    this->has_clipboard_ = true;
                }
                else {
                    // Virtual channel data span in multiple Virtual Channel PDUs.

                    if ((flags & CHANNELS::CHANNEL_FLAG_FIRST) == 0) {
                        LOG(LOG_ERR, "CopyPaste::send_to_mod_channel flag CHANNEL_FLAG_FIRST expected");
                        throw Error(ERR_RDP_PROTOCOL);
                    }

                    this->long_data_response_size = header.dataLen() - stream.in_remain();
                    this->clipboard_str_.utf16_push_back(stream.get_current(), stream.in_remain() / 2);
                }
            }
            break;
        }
        default:
            if (this->verbose) {
                LOG(LOG_INFO, "CopyPaste::send_to_mod_channel msgType=%u", unsigned(rp.msgType()));
            }
            break;
    }
}