// 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.ByteBuffer; import streamer.Element; import streamer.Link; import streamer.OneTimeSwitch; import streamer.Pipeline; import streamer.PipelineImpl; import streamer.debug.MockSink; import streamer.debug.MockSource; /** * @see http://msdn.microsoft.com/en-us/library/cc240475.aspx */ public class ClientInfoPDU extends OneTimeSwitch { public static final int INFO_MOUSE = 0x1; public static final int INFO_DISABLECTRLALTDEL = 0x2; public static final int INFO_UNICODE = 0x10; public static final int INFO_MAXIMIZESHELL = 0x20; public static final int INFO_LOGONNOTIFY = 0x40; public static final int INFO_ENABLEWINDOWSKEY = 0x100; public static final int INFO_MOUSE_HAS_WHEEL = 0x00020000; public static final int INFO_NOAUDIOPLAYBACK = 0x00080000; public static final int PERF_DISABLE_WALLPAPER = 0x1; public static final int PERF_DISABLE_FULLWINDOWDRAG = 0x2; public static final int PERF_DISABLE_MENUANIMATIONS = 0x4; protected byte[] userName = "".getBytes(RdpConstants.CHARSET_16); protected byte[] password = "".getBytes(RdpConstants.CHARSET_16); // No effect protected byte[] alternateShell = "".getBytes(RdpConstants.CHARSET_16); protected byte[] domain = "".getBytes(RdpConstants.CHARSET_16); protected byte[] workingDir = "".getBytes(RdpConstants.CHARSET_16); protected byte[] clientAddress = "192.168.0.100".getBytes(RdpConstants.CHARSET_16); protected byte[] clientDir = "C:\\Windows\\System32\\mstscax.dll".getBytes(RdpConstants.CHARSET_16); protected String standardTimeZoneName = "EET, Standard Time"; protected String daylightTimeZoneName = "EET, Summer Time"; protected int standardTimeZoneBias = 0; /* in minutes */ protected int daylightTimeZoneBias = 60; /* in minutes */ public ClientInfoPDU(String id, String userName) { super(id); this.userName = userName.getBytes(RdpConstants.CHARSET_16); } @Override protected void handleOneTimeData(ByteBuffer buf, Link link) { if (buf == null) return; throw new RuntimeException("Unexpected packet: " + buf + "."); } @Override protected void onStart() { super.onStart(); // Length of packet ByteBuffer buf = new ByteBuffer(1024, true); // MCS Send Data Request PDU buf.writeByte(0x64); // Initiator: 0x03 + 1001 = 1004 buf.writeShort(3); // Channel ID: 1003 buf.writeShort(1003); // Data priority: high, segmentation: begin | end (0x40 | 0x20 | 0x10 = 0x70) buf.writeByte(0x70); // User data length: (variable length field) int length = 224 + userName.length + password.length + alternateShell.length + domain.length + workingDir.length + clientAddress.length + clientDir.length; buf.writeShort(length | 0x8000); // Flags: SEC_INFO_PKT (0x4000) buf.writeShort(0x4000); // TS_SECURITY_HEADER::flagsHi - ignored buf.writeShort(0x0000); // Codepage: 0 (UNKNOWN, LE) (use 0x04090409 (1033,1033) for EN_US) buf.writeIntLE(0x0000); // Flags buf.writeIntLE(INFO_MOUSE | INFO_DISABLECTRLALTDEL | INFO_UNICODE | INFO_MAXIMIZESHELL | INFO_LOGONNOTIFY | INFO_ENABLEWINDOWSKEY | INFO_MOUSE_HAS_WHEEL | INFO_NOAUDIOPLAYBACK); // // Lengths // // cbDomain length: 0 bytes (LE) (NOT including size of mandatory NULL terminator) buf.writeShortLE(domain.length); // cbUserName length: 16 bytes (0x10, LE) (NOT including size of mandatory NULL terminator) buf.writeShortLE(userName.length); // cbPassword length: (LE) (NOT including size of mandatory NULL terminator) buf.writeShortLE(password.length); // cbAlternateShell: (LE) (NOT including size of mandatory NULL terminator) buf.writeShortLE(alternateShell.length); // cbWorkingDir: (LE) (NOT including size of mandatory NULL terminator) buf.writeShortLE(workingDir.length); // // Values // // Domain: (UCS2), see cbDomain buf.writeBytes(domain); buf.writeShort(0); // User name: (UCS2), see cbUserName buf.writeBytes(userName); buf.writeShort(0); // Password: (UCS2), see cbPassword buf.writeBytes(password); buf.writeShort(0); // Alternate shell: (UCS2), see cbAlternateShell buf.writeBytes(alternateShell); buf.writeShort(0); // Working directory: (UCS2), see cbWorkingDir buf.writeBytes(workingDir); buf.writeShort(0); // Client address family: 2 (AF_INET, LE) buf.writeShortLE(2); // cbClientAddress: ( LE) (including the size of the mandatory NULL terminator) buf.writeShortLE(clientAddress.length + 2); // Client address: (UCS2) buf.writeBytes(clientAddress); buf.writeShort(0); // cbClientDir: 64 bytes (0x40, LE) (including the size of the mandatory NULL terminator) buf.writeShortLE(clientDir.length + 2); // Client directory: (UCS2) buf.writeBytes(clientDir); buf.writeShort(0); // // Client time zone: // // Bias: 0 minutes (LE) buf.writeIntLE(0); // Standard name: "EET, Standard Time" (fixed string: 64 bytes, UCS2) buf.writeFixedString(62, standardTimeZoneName, RdpConstants.CHARSET_16); buf.writeShort(0); // Standard date buf.writeBytes(new byte[] { // wYear: 0 (LE) (byte)0x00, (byte)0x00, // wMonth: unknown (LE) (byte)0x00, (byte)0x00, // wDayOfWeek: Sunday (LE) (byte)0x00, (byte)0x00, // wDay: unknown (LE) (byte)0x00, (byte)0x00, // wHour: 0 (LE) (byte)0x00, (byte)0x00, // wMinute: 0 (LE) (byte)0x00, (byte)0x00, // wSecond: 0 (LE) (byte)0x00, (byte)0x00, // wMilliseconds: 0 (byte)0x00, (byte)0x00, }); // StandardBias: 0 minutes (LE) buf.writeIntLE(standardTimeZoneBias); // Daylight name: "EET, Summer Time" (fixed string: 64 bytes, UCS2) buf.writeFixedString(62, daylightTimeZoneName, RdpConstants.CHARSET_16); buf.writeShort(0); // Daylight date buf.writeBytes(new byte[] { // wYear: 0 (LE) (byte)0x00, (byte)0x00, // wMonth: unknown (LE) (byte)0x00, (byte)0x00, // wDayOfWeek: Sunday (LE) (byte)0x00, (byte)0x00, // wDay: unknown (LE) (byte)0x00, (byte)0x00, // wHour: 0 (LE) (byte)0x00, (byte)0x00, // wMinute: 0 (LE) (byte)0x00, (byte)0x00, // wSecond: 0 (LE) (byte)0x00, (byte)0x00, // wMilliseconds: 0 (byte)0x00, (byte)0x00, }); // Daylight bias: 60 minutes (LE) buf.writeIntLE(daylightTimeZoneBias); // Client session ID: 0x00000000 (LE) buf.writeIntLE(0); // Performance flags: 0x7 (LE) = PERF_DISABLE_WALLPAPER (0x1), PERF_DISABLE_FULLWINDOWDRAG (0x2), PERF_DISABLE_MENUANIMATIONS (0x4) buf.writeIntLE(PERF_DISABLE_WALLPAPER | PERF_DISABLE_FULLWINDOWDRAG | PERF_DISABLE_MENUANIMATIONS); // cbAutoReconnectCookie: 0 bytes (LE) buf.writeShortLE(0); // Trim buffer to actual length of data written buf.trimAtCursor(); pushDataToOTOut(buf); switchOff(); } /** * Example. */ public static void main(String args[]) { // System.setProperty("streamer.Link.debug", "true"); System.setProperty("streamer.Element.debug", "true"); // System.setProperty("streamer.Pipeline.debug", "true"); /* @formatter:off */ byte[] packet = new byte[] { // TPKT (byte) 0x03, (byte) 0x00, // TPKT length: 343 bytes (byte) 0x01, (byte) 0x57, // X224 Data PDU (byte) 0x02, (byte) 0xf0, (byte) 0x80, // MCS Send Data Request PDU (byte) 0x64, // Initiator: 0x03 + 1001 = 1004 (byte) 0x00, (byte) 0x03, // Channel ID: 1003 (IO Channel) (byte) 0x03, (byte) 0xeb, // Data priority: high, segmentation: begin | end (0x40 | 0x20 | 0x10 = 0x70) (byte) 0x70, // User data length: 328 (0x148) bytes, variable length field (byte) 0x81, (byte) 0x48, // Flags: SEC_INFO_PKT (0x4000) (byte) 0x40, (byte) 0x00, // TS_SECURITY_HEADER::flagsHi - ignored (byte) 0x00, (byte) 0x00, // Codepage: 0 (UNKNOWN, LE) (use 0x04090409 (1033,1033) for EN_US) (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Flags: 0xa0173 (LE), INFO_MOUSE (0x1), INFO_DISABLECTRLALTDEL (0x2), INFO_UNICODE (0x10), // INFO_MAXIMIZESHELL (0x20), INFO_LOGONNOTIFY (0x40), INFO_ENABLEWINDOWSKEY (0x100), // INFO_MOUSE_HAS_WHEEL (0x00020000), INFO_NOAUDIOPLAYBACK (0x00080000), (byte) 0x73, (byte) 0x01, (byte) 0x0a, (byte) 0x00, // Lengths // cbDomain length: 0 bytes (LE) (NOT including size of mandatory NULL terminator) (byte) 0x00, (byte) 0x00, // cbUserName length: 16 bytes (0x10, LE) (NOT including size of mandatory NULL terminator) (byte) 0x10, (byte) 0x00, // cbPassword length: 0 bytes (LE) (NOT including size of mandatory NULL terminator) (byte) 0x00, (byte) 0x00, // cbAlternateShell: 0 bytes (LE) (NOT including size of mandatory NULL terminator) (byte) 0x00, (byte) 0x00, // cbWorkingDir: 0 bytes (LE) (NOT including size of mandatory NULL terminator) (byte) 0x00, (byte) 0x00, // Values // Domain: "" (UCS2), see cbDomain (byte) 0x00, (byte) 0x00, // User name: "vlisivka" (UCS2), see cbUserName (byte) 0x76, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x76, (byte) 0x00, (byte) 0x6b, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Password: "" (UCS2), see cbPassword (byte) 0x00, (byte) 0x00, // Alternate shell: "" (UCS2), see cbAlternateShell (byte) 0x00, (byte) 0x00, // Working directory: "" (UCS2), see cbWorkingDir (byte) 0x00, (byte) 0x00, // Client address family: 2 (AF_INET, LE) (byte) 0x02, (byte) 0x00, // cbClientAddress = 28 bytes (0x1c, LE) (including the size of the mandatory NULL terminator) (byte) 0x1c, (byte) 0x00, // Client address: "192.168.0.100" (UCS2) (byte) 0x31, (byte) 0x00, (byte) 0x39, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x2e, (byte) 0x00, (byte) 0x31, (byte) 0x00, (byte) 0x36, (byte) 0x00, (byte) 0x38, (byte) 0x00, (byte) 0x2e, (byte) 0x00, (byte) 0x30, (byte) 0x00, (byte) 0x2e, (byte) 0x00, (byte) 0x31, (byte) 0x00, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x00, (byte) 0x00, (byte) 0x00, // cbClientDir: 64 bytes (0x40, LE) (including the size of the mandatory NULL terminator) (byte) 0x40, (byte) 0x00, // Client directory: "C:\Windows\System32\mstscax.dll" (UCS2) (byte) 0x43, (byte) 0x00, (byte) 0x3a, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x57, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x6f, (byte) 0x00, (byte) 0x77, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x79, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x33, (byte) 0x00, (byte) 0x32, (byte) 0x00, (byte) 0x5c, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x73, (byte) 0x00, (byte) 0x63, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x78, (byte) 0x00, (byte) 0x2e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x6c, (byte) 0x00, (byte) 0x00, (byte) 0x00, // // Client time zone: // Bias: 0 minutes (LE) (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Standard name: "EET, Standard Time" (fixed string: 64 bytes, UCS2) (byte) 0x45, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x2c, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x74, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x6e, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x61, (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x64, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // // Standard date // wYear: 0 (LE) (byte) 0x00, (byte) 0x00, // wMonth: unknown (LE) (byte) 0x00, (byte) 0x00, // wDayOfWeek: Sunday (LE) (byte) 0x00, (byte) 0x00, // wDay: unknown (LE) (byte) 0x00, (byte) 0x00, // wHour: 0 (LE) (byte) 0x00, (byte) 0x00, // wMinute: 0 (LE) (byte) 0x00, (byte) 0x00, // wSecond: 0 (LE) (byte) 0x00, (byte) 0x00, // wMilliseconds: 0 (byte) 0x00, (byte) 0x00, // StandardBias: 0 minutes (LE) (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Daylight name: "EET, Summer Time" (fixed string: 64 bytes, UCS2) (byte) 0x45, (byte) 0x00, (byte) 0x45, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x2c, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x53, (byte) 0x00, (byte) 0x75, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x72, (byte) 0x00, (byte) 0x20, (byte) 0x00, (byte) 0x54, (byte) 0x00, (byte) 0x69, (byte) 0x00, (byte) 0x6d, (byte) 0x00, (byte) 0x65, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Daylight date // wYear: 0 (LE) (byte) 0x00, (byte) 0x00, // wMonth: unknown (LE) (byte) 0x00, (byte) 0x00, // wDayOfWeek: Sunday (LE) (byte) 0x00, (byte) 0x00, // wDay: unknown (LE) (byte) 0x00, (byte) 0x00, // wHour: 0 (LE) (byte) 0x00, (byte) 0x00, // wMinute: 0 (LE) (byte) 0x00, (byte) 0x00, // wSecond: 0 (LE) (byte) 0x00, (byte) 0x00, // wMilliseconds: 0 (byte) 0x00, (byte) 0x00, // Daylight bias: 60 minutes (LE) (byte) 0x3c, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Client session ID: 0x00000000 (LE) (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00, // Performance flags: 0x7 (LE) = PERF_DISABLE_WALLPAPER (0x1), PERF_DISABLE_FULLWINDOWDRAG (0x2), PERF_DISABLE_MENUANIMATIONS (0x4) (byte) 0x07, (byte) 0x00, (byte) 0x00, (byte) 0x00, // cbAutoReconnectCookie: 0 bytes (LE) (byte) 0x00, (byte) 0x00, }; /* @formatter:on */ MockSource source = new MockSource("source", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3})); Element client_info = new ClientInfoPDU("client_info", "vlisivka"); Element x224 = new ClientX224DataPDU("x224"); Element tpkt = new ClientTpkt("tpkt"); Element sink = new MockSink("sink", ByteBuffer.convertByteArraysToByteBuffers(packet)); Element mainSink = new MockSink("mainSink", ByteBuffer.convertByteArraysToByteBuffers(new byte[] {1, 2, 3})); Pipeline pipeline = new PipelineImpl("test"); pipeline.add(source, client_info, x224, tpkt, sink, mainSink); pipeline.link("source", "client_info", "mainSink"); pipeline.link("client_info >" + OTOUT, "x224", "tpkt", "sink"); pipeline.runMainLoop("source", STDOUT, false, false); } }