// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package rdpclient.rdp; import streamer.BaseElement; import streamer.ByteBuffer; import streamer.Link; /** * @see http://msdn.microsoft.com/en-us/library/cc240621.aspx */ public class ServerFastPath extends BaseElement { /** * TPKT protocol version (first byte). */ public static final int PROTOCOL_TPKT = 0x03; /** * Fast path protocol version (first two bits of first byte). */ public static final int PROTOCOL_FASTPATH = 0x00; /** * CredSSP packets. */ public static final int PROTOCOL_CREDSSP = 0x30; /** * TPKT packets will be pushed to that pad. */ public static final String TPKT_PAD = "tpkt"; /** * CredSSP packets will be pushed to same pad as TPKT, because they are part * of slow-path initialization sequence. */ public static final String CREDSSP_PAD = "tpkt"; private static final String ORDERS_PAD = "orders"; private static final String BITMAP_PAD = "bitmap"; private static final String PALETTE_PAD = "palette"; /** * Indicates that packet contains 8 byte secure checksum at top of packet. Top * two bits of first byte. */ public static final int FASTPATH_OUTPUT_SECURE_CHECKSUM = 1; /** * Indicates that packet contains 8 byte secure checksum at top of packet and * packet content is encrypted. Top two bits of first byte. */ public static final int FASTPATH_OUTPUT_ENCRYPTED = 2; public static final int FASTPATH_UPDATETYPE_ORDERS = 0; public static final int FASTPATH_UPDATETYPE_BITMAP = 1; public static final int FASTPATH_UPDATETYPE_PALETTE = 2; public static final int FASTPATH_UPDATETYPE_SYNCHRONIZE = 3; public static final int FASTPATH_UPDATETYPE_SURFCMDS = 4; public static final int FASTPATH_UPDATETYPE_PTR_NULL = 5; public static final int FASTPATH_UPDATETYPE_PTR_DEFAULT = 6; public static final int FASTPATH_UPDATETYPE_PTR_POSITION = 8; public static final int FASTPATH_UPDATETYPE_COLOR = 9; public static final int FASTPATH_UPDATETYPE_CACHED = 0xa; public static final int FASTPATH_UPDATETYPE_POINTER = 0xb; public static final int FASTPATH_FRAGMENT_SINGLE = 0; public static final int FASTPATH_FRAGMENT_LAST = 1; public static final int FASTPATH_FRAGMENT_FIRST = 2; public static final int FASTPATH_FRAGMENT_NEXT = 3; public static final int FASTPATH_OUTPUT_COMPRESSION_USED = 2; public ServerFastPath(String id) { super(id); } @Override public void handleData(ByteBuffer buf, Link link) { if (buf == null) return; if (verbose) System.out.println("[" + this + "] INFO: Data received: " + buf + "."); // * DEBUG */System.out.println(buf.toHexString(buf.length)); // We need at 4 bytes to read packet type (TPKT or FastPath) and packet // length if (!cap(buf, 4, UNLIMITED, link, false)) return; int typeAndFlags = buf.readUnsignedByte(); switch (typeAndFlags) { case PROTOCOL_TPKT: // 0x03 handleTpkt(buf, link); break; case PROTOCOL_CREDSSP: // 0x30, potential clash with FastPath handleCredSSP(buf, link); break; default: // (value & 0x03) == 0x00 case PROTOCOL_FASTPATH: handleFastPath(buf, link, typeAndFlags); break; } } private void handleTpkt(ByteBuffer buf, Link link) { // Reserved buf.skipBytes(1); // Read TPKT length int length = buf.readUnsignedShort(); if (!cap(buf, length, length, link, false)) // Wait for full packet to arrive return; int payloadLength = length - buf.cursor; // Extract payload ByteBuffer outBuf = buf.slice(buf.cursor, payloadLength, true); buf.unref(); if (verbose) { outBuf.putMetadata("source", this); } pushDataToPad(TPKT_PAD, outBuf); } private void handleCredSSP(ByteBuffer buf, Link link) { if (verbose) System.out.println("[" + this + "] INFO: CredSSP data received: " + buf + "."); // Store header position: will parse whole header later in BER format parser int headerPosition = buf.cursor - 1; long payloadLength = buf.readBerLength(); if (payloadLength > 10 * 1024) throw new RuntimeException("[" + this + "] ERROR: CredSSP packets seems to be too long: " + payloadLength + "bytes. Data: " + buf + "."); // Length is the size of payload, so we need to append size of header int headerLength = buf.cursor - headerPosition; int packetLength = (int)payloadLength + headerLength; if (!cap(buf, packetLength, packetLength, link, false)) // Wait for full packet to arrive return; // Extract payload (with header) ByteBuffer outBuf = buf.slice(headerPosition, packetLength, true); buf.unref(); if (verbose) { outBuf.putMetadata("source", this); } pushDataToPad(CREDSSP_PAD, outBuf); } private void handleFastPath(ByteBuffer buf, Link link, int typeAndFlags) { // Number of bytes in updateData field (including header (1+1 or 2 // bytes)) int length = buf.readVariableUnsignedShort(); if (!cap(buf, length, length, link, false)) // Wait for full packet to arrive return; int type = typeAndFlags & 0x3; int securityFlags = (typeAndFlags >> 6) & 0x3; // Assertions { if (type != PROTOCOL_FASTPATH) throw new RuntimeException("Unknown protocol. Expected protocol: 0 (FastPath). Actual protocol: " + type + ", data: " + buf + "."); switch (securityFlags) { case FASTPATH_OUTPUT_SECURE_CHECKSUM: // TODO throw new RuntimeException("Secure checksum is not supported in FastPath packets."); case FASTPATH_OUTPUT_ENCRYPTED: // TODO throw new RuntimeException("Encryption is not supported in FastPath packets."); } } // TODO: optional FIPS information, when FIPS is selected // TODO: optional data signature (checksum), when checksum or FIPS is // selected // Array of FastPath update fields while (buf.cursor < buf.length) { int updateHeader = buf.readUnsignedByte(); int size = buf.readUnsignedShortLE(); int updateCode = updateHeader & 0xf; int fragmentation = (updateHeader >> 4) & 0x3; int compression = (updateHeader >> 6) & 0x3; if (verbose) System.out.println("[" + this + "] INFO: FastPath update received. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation + ", compression: " + compression + ", size: " + size + "."); ByteBuffer data = buf.readBytes(size); buf.putMetadata("fragmentation", fragmentation); buf.putMetadata("compression", compression); switch (updateCode) { case FASTPATH_UPDATETYPE_ORDERS: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_ORDERS."); pushDataToPad(ORDERS_PAD, data); break; case FASTPATH_UPDATETYPE_BITMAP: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_BITMAP."); pushDataToPad(BITMAP_PAD, data); break; case FASTPATH_UPDATETYPE_PALETTE: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PALETTE."); pushDataToPad(PALETTE_PAD, data); break; case FASTPATH_UPDATETYPE_SYNCHRONIZE: // @see http://msdn.microsoft.com/en-us/library/cc240625.aspx if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_SYNCHRONIZE."); data.unref(); if (size != 0) throw new RuntimeException("Size of FastPath synchronize packet must be 0. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation + ", compression: " + compression + ", size: " + size + ", data: " + data + "."); break; case FASTPATH_UPDATETYPE_SURFCMDS: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_SURFCMDS."); break; case FASTPATH_UPDATETYPE_PTR_NULL: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_NULL."); break; case FASTPATH_UPDATETYPE_PTR_DEFAULT: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_DEFAULT."); break; case FASTPATH_UPDATETYPE_PTR_POSITION: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_PTR_POSITION."); break; case FASTPATH_UPDATETYPE_COLOR: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_COLOR."); break; case FASTPATH_UPDATETYPE_CACHED: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_CACHED."); break; case FASTPATH_UPDATETYPE_POINTER: if (verbose) System.out.println("[" + this + "] INFO: FASTPATH_UPDATETYPE_POINTER."); break; default: throw new RuntimeException("Unknown FastPath update. UpdateCode: " + updateCode + ", fragmentation: " + fragmentation + ", compression: " + compression + ", size: " + size + ", data: " + data + "."); } buf.unref(); } } }