All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jcifs.ntlmssp.Type2Message Maven / Gradle / Ivy

/* jcifs smb client library in Java
 * Copyright (C) 2002  "Michael B. Allen" 
 *                 "Eric Glass" 
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package jcifs.ntlmssp;

import java.io.IOException;

import java.net.UnknownHostException;

import jcifs.Config;

import jcifs.netbios.NbtAddress;

/**
 * Represents an NTLMSSP Type-2 message.
 */
public class Type2Message extends NtlmMessage {

    private static final int DEFAULT_FLAGS;

    private static final String DEFAULT_DOMAIN;

    private static final byte[] DEFAULT_TARGET_INFORMATION;

    private byte[] challenge;

    private String target;

    private byte[] context;

    private byte[] targetInformation;

    static {
        DEFAULT_FLAGS = NTLMSSP_NEGOTIATE_NTLM |
                (Config.getBoolean("jcifs.smb.client.useUnicode", true) ?
                        NTLMSSP_NEGOTIATE_UNICODE : NTLMSSP_NEGOTIATE_OEM);
        DEFAULT_DOMAIN = Config.getProperty("jcifs.smb.client.domain", null);
        byte[] domain = new byte[0];
        if (DEFAULT_DOMAIN != null) {
            try {
                domain = DEFAULT_DOMAIN.getBytes("UnicodeLittleUnmarked");
            } catch (IOException ex) { }
        }
        int domainLength = domain.length;
        byte[] server = new byte[0];
        try {
            String host = NbtAddress.getLocalHost().getHostName();
            if (host != null) {
                try {
                    server = host.getBytes("UnicodeLittleUnmarked");
                } catch (IOException ex) { }
            }
        } catch (UnknownHostException ex) { }
        int serverLength = server.length;
        byte[] targetInfo = new byte[(domainLength > 0 ? domainLength + 4 : 0) +
                (serverLength > 0 ? serverLength + 4 : 0) + 4];
        int offset = 0;
        if (domainLength > 0) {
            writeUShort(targetInfo, offset, 2);
            offset += 2;
            writeUShort(targetInfo, offset, domainLength);
            offset += 2;
            System.arraycopy(domain, 0, targetInfo, offset, domainLength);
            offset += domainLength;
        }
        if (serverLength > 0) {
            writeUShort(targetInfo, offset, 1);
            offset += 2;
            writeUShort(targetInfo, offset, serverLength);
            offset += 2;
            System.arraycopy(server, 0, targetInfo, offset, serverLength);
        }
        DEFAULT_TARGET_INFORMATION = targetInfo;
    }

    /**
     * Creates a Type-2 message using default values from the current
     * environment.
     */
    public Type2Message() {
        this(getDefaultFlags(), null, null);
    }

    /**
     * Creates a Type-2 message in response to the given Type-1 message
     * using default values from the current environment.
     *
     * @param type1 The Type-1 message which this represents a response to.
     */
    public Type2Message(Type1Message type1) {
        this(type1, null, null);
    }

    /**
     * Creates a Type-2 message in response to the given Type-1 message.
     *
     * @param type1 The Type-1 message which this represents a response to.
     * @param challenge The challenge from the domain controller/server.
     * @param target The authentication target.
     */
    public Type2Message(Type1Message type1, byte[] challenge, String target) {
        this(getDefaultFlags(type1), challenge, (type1 != null &&
                target == null && type1.getFlag(NTLMSSP_REQUEST_TARGET)) ?
                        getDefaultDomain() : target);
    }

    /**
     * Creates a Type-2 message with the specified parameters.
     *
     * @param flags The flags to apply to this message.
     * @param challenge The challenge from the domain controller/server.
     * @param target The authentication target.
     */
    public Type2Message(int flags, byte[] challenge, String target) {
        setFlags(flags);
        setChallenge(challenge);
        setTarget(target);
        if (target != null) setTargetInformation(getDefaultTargetInformation());
    }

    /**
     * Creates a Type-2 message using the given raw Type-2 material.
     *
     * @param material The raw Type-2 material used to construct this message.
     * @throws IOException If an error occurs while parsing the material.
     */
    public Type2Message(byte[] material) throws IOException {
        parse(material);
    }

    /**
     * Returns the challenge for this message.
     *
     * @return A byte[] containing the challenge.
     */
    public byte[] getChallenge() {
        return challenge;
    }

    /**
     * Sets the challenge for this message.
     *
     * @param challenge The challenge from the domain controller/server.
     */
    public void setChallenge(byte[] challenge) {
        this.challenge = challenge;
    }

    /**
     * Returns the authentication target.
     *
     * @return A String containing the authentication target.
     */
    public String getTarget() {
        return target;
    }

    /**
     * Sets the authentication target.
     *
     * @param target The authentication target.
     */
    public void setTarget(String target) {
        this.target = target;
    }

    /**
     * Returns the target information block.
     *
     * @return A byte[] containing the target information block.
     * The target information block is used by the client to create an
     * NTLMv2 response.
     */ 
    public byte[] getTargetInformation() {
        return targetInformation;
    }

    /**
     * Sets the target information block.
     * The target information block is used by the client to create
     * an NTLMv2 response.
     * 
     * @param targetInformation The target information block.
     */
    public void setTargetInformation(byte[] targetInformation) {
        this.targetInformation = targetInformation;
    }

    /**
     * Returns the local security context.
     *
     * @return A byte[] containing the local security
     * context.  This is used by the client to negotiate local
     * authentication.
     */
    public byte[] getContext() {
        return context;
    }

    /**
     * Sets the local security context.  This is used by the client
     * to negotiate local authentication.
     *
     * @param context The local security context.
     */
    public void setContext(byte[] context) {
        this.context = context;
    }

    public byte[] toByteArray() {
        try {
            String targetName = getTarget();
            byte[] challenge = getChallenge();
            byte[] context = getContext();
            byte[] targetInformation = getTargetInformation();
            int flags = getFlags();
            byte[] target = new byte[0];
            if ((flags & (NTLMSSP_TARGET_TYPE_DOMAIN |
                    NTLMSSP_TARGET_TYPE_SERVER |
                            NTLMSSP_TARGET_TYPE_SHARE)) != 0) {
                if (targetName != null && targetName.length() != 0) {
                    target = (flags & NTLMSSP_NEGOTIATE_UNICODE) != 0 ?
                            targetName.getBytes("UnicodeLittleUnmarked") :
                            targetName.toUpperCase().getBytes(getOEMEncoding());
                } else {
                    flags &= (0xffffffff ^ (NTLMSSP_TARGET_TYPE_DOMAIN |
                            NTLMSSP_TARGET_TYPE_SERVER |
                                    NTLMSSP_TARGET_TYPE_SHARE));
                }
            }
            if (targetInformation != null) {
                flags ^= NTLMSSP_NEGOTIATE_TARGET_INFO;
                // empty context is needed for padding when t.i. is supplied.
                if (context == null) context = new byte[8];
            }
            int data = 32;
            if (context != null) data += 8;
            if (targetInformation != null) data += 8;
            byte[] type2 = new byte[data + target.length +
                    (targetInformation != null ? targetInformation.length : 0)];
            System.arraycopy(NTLMSSP_SIGNATURE, 0, type2, 0, 8);
            writeULong(type2, 8, 2);
            writeSecurityBuffer(type2, 12, data, target);
            writeULong(type2, 20, flags);
            System.arraycopy(challenge != null ? challenge : new byte[8], 0,
                    type2, 24, 8);
            if (context != null) System.arraycopy(context, 0, type2, 32, 8);
            if (targetInformation != null) {
                writeSecurityBuffer(type2, 40, data + target.length,
                        targetInformation);
            }
            return type2;
        } catch (IOException ex) {
            throw new IllegalStateException(ex.getMessage());
        }
    }

    public String toString() {
        String target = getTarget();
        byte[] challenge = getChallenge();
        byte[] context = getContext();
        byte[] targetInformation = getTargetInformation();
        int flags = getFlags();
        StringBuffer buffer = new StringBuffer();
        if (target != null) {
            buffer.append("target: ").append(target);
        }
        if (challenge != null) {
            if (buffer.length() > 0) buffer.append("; ");
            buffer.append("challenge: ");
            buffer.append("0x");
            for (int i = 0; i < challenge.length; i++) {
                buffer.append(Integer.toHexString((challenge[i] >> 4) & 0x0f));
                buffer.append(Integer.toHexString(challenge[i] & 0x0f));
            }
        }
        if (context != null) {
            if (buffer.length() > 0) buffer.append("; ");
            buffer.append("context: ");
            buffer.append("0x");
            for (int i = 0; i < context.length; i++) {
                buffer.append(Integer.toHexString((context[i] >> 4) & 0x0f));
                buffer.append(Integer.toHexString(context[i] & 0x0f));
            }
        }
        if (targetInformation != null) {
            if (buffer.length() > 0) buffer.append("; ");
            buffer.append("targetInformation: ");
            buffer.append("0x");
            for (int i = 0; i < targetInformation.length; i++) {
                buffer.append(Integer.toHexString((targetInformation[i] >> 4) &
                        0x0f));
                buffer.append(Integer.toHexString(targetInformation[i] & 0x0f));
            }
        }
        if (flags != 0) {
            if (buffer.length() > 0) buffer.append("; ");
            buffer.append("flags: ");
            buffer.append("0x");
            buffer.append(Integer.toHexString((flags >> 28) & 0x0f));
            buffer.append(Integer.toHexString((flags >> 24) & 0x0f));
            buffer.append(Integer.toHexString((flags >> 20) & 0x0f));
            buffer.append(Integer.toHexString((flags >> 16) & 0x0f));
            buffer.append(Integer.toHexString((flags >> 12) & 0x0f));
            buffer.append(Integer.toHexString((flags >> 8) & 0x0f));
            buffer.append(Integer.toHexString((flags >> 4) & 0x0f));
            buffer.append(Integer.toHexString(flags & 0x0f));
        }
        return buffer.toString();
    }

    /**
     * Returns the default flags for a generic Type-2 message in the
     * current environment.
     *
     * @return An int containing the default flags.
     */
    public static int getDefaultFlags() {
        return DEFAULT_FLAGS;
    }

    /**
     * Returns the default flags for a Type-2 message created in response
     * to the given Type-1 message in the current environment.
     *
     * @return An int containing the default flags.
     */
    public static int getDefaultFlags(Type1Message type1) {
        if (type1 == null) return DEFAULT_FLAGS;
        int flags = NTLMSSP_NEGOTIATE_NTLM;
        int type1Flags = type1.getFlags();
        flags |= ((type1Flags & NTLMSSP_NEGOTIATE_UNICODE) != 0) ?
                NTLMSSP_NEGOTIATE_UNICODE : NTLMSSP_NEGOTIATE_OEM;
        if ((type1Flags & NTLMSSP_REQUEST_TARGET) != 0) {
            String domain = getDefaultDomain();
            if (domain != null) {
                flags |= NTLMSSP_REQUEST_TARGET | NTLMSSP_TARGET_TYPE_DOMAIN;
            }
        }
        return flags;
    }

    /**
     * Returns the default domain from the current environment.
     *
     * @return A String containing the domain.
     */
    public static String getDefaultDomain() {
        return DEFAULT_DOMAIN;
    }

    public static byte[] getDefaultTargetInformation() {
        return DEFAULT_TARGET_INFORMATION;
    }

    private void parse(byte[] material) throws IOException {
        for (int i = 0; i < 8; i++) {
            if (material[i] != NTLMSSP_SIGNATURE[i]) {
                throw new IOException("Not an NTLMSSP message.");
            }
        }
        if (readULong(material, 8) != 2) {
            throw new IOException("Not a Type 2 message.");
        }
        int flags = readULong(material, 20);
        setFlags(flags);
        String target = null;
        byte[] bytes = readSecurityBuffer(material, 12);
        if (bytes.length != 0) {
            target = new String(bytes,
                    ((flags & NTLMSSP_NEGOTIATE_UNICODE) != 0) ?
                            "UnicodeLittleUnmarked" : getOEMEncoding());
        }
        setTarget(target);
        for (int i = 24; i < 32; i++) {
            if (material[i] != 0) {
                byte[] challenge = new byte[8];
                System.arraycopy(material, 24, challenge, 0, 8);
                setChallenge(challenge);
                break;
            }
        }
        int offset = readULong(material, 16); // offset of targetname start
        if (offset == 32 || material.length == 32) return;
        for (int i = 32; i < 40; i++) {
            if (material[i] != 0) {
                byte[] context = new byte[8];
                System.arraycopy(material, 32, context, 0, 8);
                setContext(context);
                break;
            }
        }
        if (offset == 40 || material.length == 40) return;
        bytes = readSecurityBuffer(material, 40);
        if (bytes.length != 0) setTargetInformation(bytes);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy