Package com.lixia.rdp.rdp5.rdpdr

Source Code of com.lixia.rdp.rdp5.rdpdr.Rdpdr

package com.lixia.rdp.rdp5.rdpdr;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.UnknownHostException;
import java.util.ArrayList;

import com.lixia.rdp.RdesktopException;
import com.lixia.rdp.crypto.CryptoException;
import com.lixia.rdp.Package.RdpPackage;
import com.lixia.rdp.rdp5.VChannel;
import com.lixia.rdp.rdp5.VChannels;

public class Rdpdr extends VChannel {

    private final static int DEVICE_TYPE_SERIAL = 0x01;
    private final static int DEVICE_TYPE_PARALLEL = 0x02;
    private final static int DEVICE_TYPE_PRINTER = 0x04;
    private final static int DEVICE_TYPE_DISK = 0x08;
    private final static int DEVICE_TYPE_SCARD = 0x20;

    /* NT status codes for RDPDR */
    private final static int RD_STATUS_SUCCESS = 0x00000000;
    private final static int RD_STATUS_NOT_IMPLEMENTED = 0x00000001;
    private final static int RD_STATUS_PENDING = 0x00000103;

    private final static int RD_STATUS_NO_MORE_FILES = 0x80000006;
    private final static int RD_STATUS_DEVICE_PAPER_EMPTY = 0x8000000e;
    private final static int RD_STATUS_DEVICE_POWERED_OFF = 0x8000000f;
    private final static int RD_STATUS_DEVICE_OFF_LINE = 0x80000010;
    private final static int RD_STATUS_DEVICE_BUSY = 0x80000011;

    private final static int RD_STATUS_INVALID_HANDLE = 0xc0000008;
    private final static int RD_STATUS_INVALID_PARAMETER = 0xc000000d;
    private final static int RD_STATUS_NO_SUCH_FILE = 0xc000000f;
    private final static int RD_STATUS_INVALID_DEVICE_REQUEST = 0xc0000010;
    private final static int RD_STATUS_ACCESS_DENIED = 0xc0000022;
    private final static int RD_STATUS_OBJECT_NAME_COLLISION = 0xc0000035;
    private final static int RD_STATUS_DISK_FULL = 0xc000007f;
    private final static int RD_STATUS_FILE_IS_A_DIRECTORY = 0xc00000ba;
    private final static int RD_STATUS_NOT_SUPPORTED = 0xc00000bb;
    private final static int RD_STATUS_TIMEOUT = 0xc0000102;
    private final static int RD_STATUS_NOTIFY_ENUM_DIR = 0xc000010c;
    private final static int RD_STATUS_CANCELLED = 0xc0000120;

    private final static int IRP_MJ_CREATE = 0x00;
    private final static int IRP_MJ_CLOSE = 0x02;
    private final static int IRP_MJ_READ = 0x03;
    private final static int IRP_MJ_WRITE = 0x04;
    private final static int IRP_MJ_QUERY_INFORMATION = 0x05;
    private final static int IRP_MJ_SET_INFORMATION = 0x06;
    private final static int IRP_MJ_QUERY_VOLUME_INFORMATION = 0x0a;
    private final static int IRP_MJ_DIRECTORY_CONTROL = 0x0c;
    private final static int IRP_MJ_DEVICE_CONTROL = 0x0e;
    private final static int IRP_MJ_LOCK_CONTROL = 0x11;

    /* RDPDR constants */
    private final static int RDPDR_COMPONENT_TYPE_CORE = 0x4472; // "sD" "Ds" ???
    private final static int RDPDR_COMPONENT_TYPE_PRINTING = 0x5052; // "RP" "PR" (PR)inting

    private final static int PAKID_CORE_SERVER_ANNOUNCE = 0x496E; // "nI" "nI" ???
    private final static int PAKID_CORE_CLIENTID_CONFIRM = 0x4343; // "CC" "CC" (C)lientID (C)onfirm
    private final static int PAKID_CORE_CLIENT_NAME = 0x434E; // "NC" "CN" (C)lient (N)ame
    private final static int PAKID_CORE_DEVICELIST_ANNOUNCE = 0x4441; // "AD" "DA" (D)evice (A)nnounce
    private final static int PAKID_CORE_DEVICE_REPLY = 0x6472; // "rd" "dr" (d)evice (r)eply
    private final static int PAKID_CORE_DEVICE_IOREQUEST = 0x4952; // "RI" "IR" (I)O (R)equest
    private final static int PAKID_CORE_DEVICE_IOCOMPLETION = 0x4943; // "CI" "IC" (I)O (C)ompletion
    private final static int PAKID_CORE_SERVER_CAPABILITY = 0x5350; // "PS" "SP" (S)erver (C)apability
    private final static int PAKID_CORE_CLIENT_CAPABILITY = 0x4350; // "PC" "CP" (C)lient (C)apability
    private final static int PAKID_CORE_DEVICELIST_REMOVE = 0x444D; // "MD" "DM" (D)evice list (R)emove
    private final static int PAKID_PRN_CACHE_DATA = 0x5043; // "CP" "PC" (P)rinter (C)ache data
    private final static int PAKID_CORE_USER_LOGGEDON = 0x554C; // "LU" "UL" (U)ser (L)ogged on
    private final static int PAKID_PRN_USING_XPS = 0x5543; // "CU" "UC" (U)sing (?)XPS

    /* CAPABILITY_HEADER.CapabilityType */
    private final static int CAP_GENERAL_TYPE = 0x0001;
    private final static int CAP_PRINTER_TYPE = 0x0002;
    private final static int CAP_PORT_TYPE = 0x0003;
    private final static int CAP_DRIVE_TYPE = 0x0004;
    private final static int CAP_SMARTCARD_TYPE = 0x0005;

    /* CAPABILITY_HEADER.Version */
    private final static int GENERAL_CAPABILITY_VERSION_01 = 0x00000001;
    private final static int GENERAL_CAPABILITY_VERSION_02 = 0x00000002;
    private final static int PRINT_CAPABILITY_VERSION_01 = 0x00000001;
    private final static int PORT_CAPABILITY_VERSION_01 = 0x00000001;
    private final static int DRIVE_CAPABILITY_VERSION_01 = 0x00000001;
    private final static int DRIVE_CAPABILITY_VERSION_02 = 0x00000002;
    private final static int SMARTCARD_CAPABILITY_VERSION_01 = 0x00000001;

    private final static int DR_MINOR_RDP_VERSION_5_0 = 0x0002;
    private final static int DR_MINOR_RDP_VERSION_5_1 = 0x0005;
    private final static int DR_MINOR_RDP_VERSION_5_2 = 0x000A;
    private final static int DR_MINOR_RDP_VERSION_6_X = 0x000C;

    /* GENERAL_CAPS_SET.extendedPDU */
    private final static int RDPDR_DEVICE_REMOVE_PDUS = 0x00000001;
    private final static int RDPDR_CLIENT_DISPLAY_NAME_PDU = 0x00000002;
    private final static int RDPDR_USER_LOGGEDON_PDU = 0x00000004;

    /* GENERAL_CAPS_SET.extraFlags1 */
    private final static int ENABLE_ASYNCIO = 0x00000001;

    /* DEVICE_ANNOUNCE.DeviceType */
    public final static int RDPDR_DTYP_SERIAL = 0x00000001;
    public final static int RDPDR_DTYP_PARALLEL = 0x00000002;
    public final static int RDPDR_DTYP_PRINT = 0x00000004;
    public final static int RDPDR_DTYP_FILESYSTEM = 0x00000008;
    public final static int RDPDR_DTYP_SMARTCARD = 0x00000020;

    public final static int RDPDR_PRINTER_ANNOUNCE_FLAG_ASCII = 0x00000001;
    public final static int RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER = 0x00000002;
    public final static int RDPDR_PRINTER_ANNOUNCE_FLAG_NETWORKPRINTER = 0x00000004;
    public final static int RDPDR_PRINTER_ANNOUNCE_FLAG_TSPRINTER = 0x00000008;
    public final static int RDPDR_PRINTER_ANNOUNCE_FLAG_XPSFORMAT = 0x00000010;

    public int rdpdr_version_minor = DR_MINOR_RDP_VERSION_5_2;
    public int rdpdr_clientid = 0;
    public String rdpdr_clientname = null;

    public ArrayList<RdpdrDevice> devices = new ArrayList<RdpdrDevice>();

    @Override
    public int flags() {
        return VChannels.CHANNEL_OPTION_INITIALIZED
                | VChannels.CHANNEL_OPTION_COMPRESS_RDP;
    }

    @Override
    public String name() {
        return "rdpdr";
    }

    @Override
    public void process(RdpPackage data) throws RdesktopException, IOException, CryptoException {
        int component = data.getLittleEndian16();
        int packetID = data.getLittleEndian16();
        if (component == RDPDR_COMPONENT_TYPE_CORE) {
            switch (packetID) {
                case PAKID_CORE_SERVER_ANNOUNCE:
                    rdpdr_process_server_announce_request(data);
                    rdpdr_send_client_announce_reply();
                    rdpdr_send_client_name_request();
                    break;
                case PAKID_CORE_SERVER_CAPABILITY:
                    /* server capabilities */
                    rdpdr_process_capabilities(data);
                    rdpdr_send_capabilities();
                    break;
                case PAKID_CORE_CLIENTID_CONFIRM:
                    rdpdr_send_capabilities();
                    /* versionMinor 0x0005 doesn't send PAKID_CORE_USER_LOGGEDON,
                     so we have to send it here */
                    if (rdpdr_version_minor == 0x0005) {
                        rdpdr_send_device_list_announce_request();
                    }
                    break;
                case PAKID_CORE_USER_LOGGEDON:
                    rdpdr_send_device_list_announce_request();
                    break;
                case PAKID_CORE_DEVICE_REPLY:
                    /* connect to a specific resource */
                    int deviceID = data.getLittleEndian32();
                    int status = data.getLittleEndian32();
                    break;
                case PAKID_CORE_DEVICE_IOREQUEST:
                    rdpdr_process_irp(data);
                    break;
                default:
//          ui_unimpl(NULL, "RDPDR core component, packetID: 0x%02X\n", packetID);
                    break;

            }
        } else if (component == RDPDR_COMPONENT_TYPE_PRINTING) {
            switch (packetID) {
                case PAKID_PRN_CACHE_DATA:
//          printercache_process(s);
                    break;
                default:
//          ui_unimpl(NULL, "RDPDR printer component, packetID: 0x%02X\n", packetID);
                    break;
            }
        } else {
            System.out.printf("RDPDR component: 0x%02X packetID: 0x%02X\n", component, packetID);
        }
    }

    private void rdpdr_process_server_announce_request(RdpPackage data) {
        int versionMajor = data.getLittleEndian16();// versionMajor, must be 1
        int versionMinor = data.getLittleEndian16(); // versionMinor
        rdpdr_clientid = data.getLittleEndian32(); // clientID
        if (versionMinor < rdpdr_version_minor) {
            rdpdr_version_minor = versionMinor;
        }
    }

    private void rdpdr_process_server_clientid_confirm(RdpPackage data) {
        int versionMinor = data.getLittleEndian16(); // versionMinor
        int clientID = data.getLittleEndian32(); // clientID
        if (rdpdr_clientid != clientID) {
            rdpdr_clientid = clientID;
        }
        if (versionMinor != rdpdr_version_minor) {
            rdpdr_version_minor = versionMinor;
        }
    }

    private void rdpdr_send_client_announce_reply() {
        RdpPackage s;

        s = new RdpPackage(12);
        s.setLittleEndian16(RDPDR_COMPONENT_TYPE_CORE);
        s.setLittleEndian16(PAKID_CORE_CLIENTID_CONFIRM);
        s.setLittleEndian16(1);// versionMajor, must be set to 1
        s.setLittleEndian16(rdpdr_version_minor);// versionMinor
        if (rdpdr_clientid > 0) {
            s.setLittleEndian32(rdpdr_clientid); // clientID, given by the server in a Server Announce Request
        } else {
            s.setLittleEndian32(0x815ed39d);///* IP address (use 127.0.0.1) 0x815ed39d */
        }
        s.markEnd();

        try {
            this.send_packet(s);
        } catch (RdesktopException e) {
        } catch (IOException e) {
        } catch (CryptoException e) {
        }
    }

    private void rdpdr_send_client_name_request() {
        RdpPackage s;
        int hostlen;

        if (null == rdpdr_clientname) {
            try {
                rdpdr_clientname = java.net.InetAddress.getLocalHost().getHostName();
            } catch (UnknownHostException e) {
                rdpdr_clientname = "127.0.0.1";
            }
        }
        hostlen = rdpdr_clientname.length() * 2;

        s = new RdpPackage(16 + hostlen + 2);
        s.setLittleEndian16(RDPDR_COMPONENT_TYPE_CORE);
        s.setLittleEndian16(PAKID_CORE_CLIENT_NAME);
        s.setLittleEndian32(1);// unicodeFlag, 0 for ASCII and 1 for Unicode
        s.setLittleEndian32(0);// codePage, must be set to zero
        s.setLittleEndian32(hostlen + 2); // clientID, given by the server in a Server Announce Request
        if (hostlen > 0) {
            try {
                s.copyFromByteArray(rdpdr_clientname.getBytes("UTF-16LE"), 0, s.getPosition(), hostlen);
            } catch (UnsupportedEncodingException e) {
            }
            s.incrementPosition(hostlen);
        }
        s.setLittleEndian16(0);
        s.markEnd();
        try {
            this.send_packet(s);
        } catch (RdesktopException e) {
        } catch (IOException e) {
        } catch (CryptoException e) {
        }
    }

    private void rdpdr_process_capabilities(RdpPackage data) {
        int i;
        int numCapabilities = data.getLittleEndian16();
        /* pad (2 bytes) */
        data.incrementPosition(2);

        for (i = 0; i < numCapabilities; i++) {
            int capabilityType = data.getLittleEndian16();
            switch (capabilityType) {
                case CAP_GENERAL_TYPE:
                    rdpdr_process_general_capset(data);
                    break;
                case CAP_PRINTER_TYPE:
                    rdpdr_process_printer_capset(data);
                    break;
                case CAP_PORT_TYPE:
                    rdpdr_process_port_capset(data);
                    break;
                case CAP_DRIVE_TYPE:
                    rdpdr_process_drive_capset(data);
                    break;
                case CAP_SMARTCARD_TYPE:
                    rdpdr_process_smartcard_capset(data);
                    break;
                default:
                    //fprintf(stderr, "unimpl: Device redirection capability set type %d\n", capabilityType);
                    break;
            }
        }
    }

    /* Process device direction general capability set */
    private void rdpdr_process_general_capset(RdpPackage data) {
        int capabilityLength = data.getLittleEndian16();/* capabilityLength */

        int version = data.getLittleEndian32();/* version */

        data.incrementPosition(4);/* osType, ignored on receipt (4 bytes) */

        data.incrementPosition(4);/* osVersion, unused and must be set to zero (4 bytes) */

        data.incrementPosition(2);/* protocolMajorVersion, must be set to 1 (2 bytes) */

        int protocolMinorVersion = data.getLittleEndian16();
        int ioCode1 = data.getLittleEndian32();
        data.incrementPosition(4);/* ioCode2, must be set to zero, reserved for future use (4 bytes) */

        int extendedPDU = data.getLittleEndian32();
        int extraFlags1 = data.getLittleEndian32();
        data.incrementPosition(4);/* extraFlags2, must be set to zero, reserved for future use (4 bytes) */
        /*
         * SpecialTypeDeviceCap (4 bytes):
         * present when GENERAL_CAPABILITY_VERSION_02 is used
         */

        if (version == GENERAL_CAPABILITY_VERSION_02) {
            int specialTypeDeviceCap = data.getLittleEndian32();
        }
    }
    /* Process printer direction capability set */

    private void rdpdr_process_printer_capset(RdpPackage data) {
        int capabilityLength = data.getLittleEndian16();
        int version = data.getLittleEndian32();
    }
    /* Process port redirection capability set */

    private void rdpdr_process_port_capset(RdpPackage data) {
        int capabilityLength = data.getLittleEndian16();
        int version = data.getLittleEndian32();
    }

    private void rdpdr_process_drive_capset(RdpPackage data) {
        int capabilityLength = data.getLittleEndian16();
        int version = data.getLittleEndian32();
    }

    private void rdpdr_process_smartcard_capset(RdpPackage data) {
        int capabilityLength = data.getLittleEndian16();
        int version = data.getLittleEndian32();
    }

    private void rdpdr_send_capabilities() {
        RdpPackage s;

        s = new RdpPackage(0x54);
        s.setLittleEndian16(RDPDR_COMPONENT_TYPE_CORE);
        s.setLittleEndian16(PAKID_CORE_CLIENT_CAPABILITY);
        s.setLittleEndian16(5);// numCapabilities
        s.setLittleEndian16(0);// pad

        /* Output device direction general capability set */
//    s.setLittleEndian16(1);  /* first */
//    s.setLittleEndian16(0x28);  /* length */
//    s.setLittleEndian32(1);
//    s.setLittleEndian32(2);
//    s.setLittleEndian16(2);
//    s.setLittleEndian16(5);
//    s.setLittleEndian16(1);
//    s.setLittleEndian16(5);
//    s.setLittleEndian16(0xFFFF);
//    s.setLittleEndian16(0);
//    s.setLittleEndian32(0);
//    s.setLittleEndian32(3);
//    s.setLittleEndian32(0);
//    s.setLittleEndian32(0);
        s.setLittleEndian16(CAP_GENERAL_TYPE);
        s.setLittleEndian16(44);
        s.setLittleEndian32(GENERAL_CAPABILITY_VERSION_01);
        s.setLittleEndian32(0);// osType, ignored on receipt
        s.setLittleEndian32(0);// osVersion, unused and must be set to zero
        s.setLittleEndian16(1); // protocolMajorVersion, must be set to 1
        s.setLittleEndian16(DR_MINOR_RDP_VERSION_5_2);// protocolMinorVersion
        s.setLittleEndian32(0x0000FFFF); // ioCode1
        s.setLittleEndian32(0); // ioCode2, must be set to zero, reserved for future use
        s.setLittleEndian32(RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU); // extendedPDU
        s.setLittleEndian32(ENABLE_ASYNCIO); // extraFlags1
        s.setLittleEndian32(0); // extraFlags2, must be set to zero, reserved for future use5f7pre
        s.setLittleEndian32(0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */

        s.setLittleEndian16(CAP_PRINTER_TYPE);
        s.setLittleEndian16(8);
        s.setLittleEndian32(PRINT_CAPABILITY_VERSION_01);

        s.setLittleEndian16(CAP_PORT_TYPE)/* third */

        s.setLittleEndian16(8)/* length */

        s.setLittleEndian32(PORT_CAPABILITY_VERSION_01);

        s.setLittleEndian16(CAP_DRIVE_TYPE)/* fourth */

        s.setLittleEndian16(8)/* length */

        s.setLittleEndian32(DRIVE_CAPABILITY_VERSION_01);

        s.setLittleEndian16(CAP_SMARTCARD_TYPE)/* fifth */

        s.setLittleEndian16(8)/* length */

        s.setLittleEndian32(SMARTCARD_CAPABILITY_VERSION_01);

        s.markEnd();

        try {
            this.send_packet(s);
        } catch (RdesktopException e) {
        } catch (CryptoException e) {
        } catch (IOException e) {
        }
    }

    private int announcedata_size() {
        int size;
        size = 8;    /* static announce size */

        size += devices.size() * 0x14;

        for (RdpdrDevice dev : devices) {
            if (dev.type == RDPDR_DTYP_PRINT) {
                size += dev.deviceData.size();
            }
        }

        return size;
    }

    private int rdpdr_send_device_list_announce_request() {
        RdpPackage s;

        s = new RdpPackage(announcedata_size());
        s.setLittleEndian16(RDPDR_COMPONENT_TYPE_CORE);
        s.setLittleEndian16(PAKID_CORE_DEVICELIST_ANNOUNCE);
        s.setLittleEndian32(devices.size()); /* deviceCount */

        for (RdpdrDevice dev : devices) {
            s.setLittleEndian32(dev.type); /* deviceType */

            s.setLittleEndian32(devices.indexOf(dev) + 1); /* deviceID */
            /* preferredDosName, Max 8 characters, may not be null terminated */

            String name = dev.name.replace(" ", "_").substring(0, dev.name.length() > 8 ? 8 : dev.name.length());
            s.copyFromByteArray(name.getBytes(), 0, s.getPosition(), name.length());
            s.incrementPosition(8);

            s.setLittleEndian32(dev.deviceData.size());
            if (dev.deviceData.size() > 0) {
                s.copyFromPacket(dev.deviceData, 0, s.getPosition(), dev.deviceData.size());
                s.incrementPosition(dev.deviceData.size());
            }
        }
        s.markEnd();
        byte[] outputbyte = new byte[s.size()];
        s.copyToByteArray(outputbyte, 0, 0, s.size());
        try {
            this.send_packet(s);
        } catch (RdesktopException e) {
        } catch (CryptoException e) {
        } catch (IOException e) {
        }
        return 0;
    }

    //devices list
    public void deviceRegister(RdpdrDevice newDevice) {
        int port = 1;
        if (newDevice.type == RDPDR_DTYP_PRINT) {
            for (RdpdrDevice dev : devices) {
                if (dev.type == RDPDR_DTYP_PRINT) {
                    port++;
                }
            }
        }
        newDevice.register("", port);
        devices.add(newDevice);
    }

    private void rdpdr_process_irp(RdpPackage data) {

        byte[] buffer = null;
        int buffer_len = 0;

        int deviceid = data.getLittleEndian32();
        int file = data.getLittleEndian32();
        int id = data.getLittleEndian32();
        int major = data.getLittleEndian32();
        int minor = data.getLittleEndian32();

        RdpdrDevice device = devices.get(deviceid - 1);
        switch (device.type) {
            case DEVICE_TYPE_SERIAL:
                break;
            case DEVICE_TYPE_PARALLEL:
                break;
            case DEVICE_TYPE_PRINTER:
                break;
            case DEVICE_TYPE_DISK:
                break;
            case DEVICE_TYPE_SCARD:
            default:
                return;
        }
        switch (major) {
            case IRP_MJ_CREATE:
                device.create("PDFCreator");
                break;
            case IRP_MJ_CLOSE:
                device.close();
                break;
            case IRP_MJ_READ:
                break;
            case IRP_MJ_WRITE:
                buffer_len = 1;
                buffer = new byte[buffer_len];
                int length = data.getLittleEndian32();
                int offset = data.getLittleEndian32();
                data.incrementPosition(0x18);
                device.write(data, length, offset);
                break;
            case IRP_MJ_QUERY_INFORMATION:
                break;
            case IRP_MJ_SET_INFORMATION:
                break;
            case IRP_MJ_QUERY_VOLUME_INFORMATION:
                break;
            case IRP_MJ_DIRECTORY_CONTROL:
                break;
            case IRP_MJ_DEVICE_CONTROL:
                break;
            case IRP_MJ_LOCK_CONTROL:
                break;
            default:
                break;
        }
        int status = RD_STATUS_SUCCESS;
        int result = 0;
        rdpdr_send_completion(deviceid, id, status, result, buffer, buffer_len);
    }

    void rdpdr_send_completion(int device, int id, int status, int result, byte[] buffer, int length) {
        RdpPackage s;

        s = new RdpPackage(20 + length);
        s.setLittleEndian16(RDPDR_COMPONENT_TYPE_CORE);//PAKID_CORE_DEVICE_REPLY?
        s.setLittleEndian16(PAKID_CORE_DEVICE_IOCOMPLETION);
        s.setLittleEndian32(device);
        s.setLittleEndian32(id);
        s.setLittleEndian32(status);
        s.setLittleEndian32(result);
        if (length > 0) {
            s.copyFromByteArray(buffer, 0, s.getPosition(), length);
        }
        s.markEnd();
        try {
            this.send_packet(s);
        } catch (RdesktopException e) {
        } catch (CryptoException e) {
        } catch (IOException e) {
        }
    }

}
TOP

Related Classes of com.lixia.rdp.rdp5.rdpdr.Rdpdr

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.