// 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.ntlmssp;

/**
 * During NTLM authentication, each of the following flags is a possible value
 * of the NegotiateFlags field of the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE, and
 * AUTHENTICATE_MESSAGE, unless otherwise noted. These flags define client or
 * server NTLM capabilities supported by the sender.
 *
 * @see http://msdn.microsoft.com/en-us/library/cc236650.aspx
 */
public class NegoFlags {

    /**
     * 56-bit encryption. If the client sends NTLMSSP_NEGOTIATE_SEAL or
     * NTLMSSP_NEGOTIATE_SIGN with NTLMSSP_NEGOTIATE_56 to the server in the
     * NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_56 to the
     * client in the CHALLENGE_MESSAGE. Otherwise it is ignored. If both
     * NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are requested and supported
     * by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128
     * will both be returned to the client. Clients and servers that set
     * NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_56 if it is supported.
     * An alternate name for this field is
     */
    public static final int NTLMSSP_NEGOTIATE_56 = 0x80000000;

    /**
     * Explicit key exchange. This capability SHOULD be used because it improves
     * security for message integrity or confidentiality. See sections 3.2.5.1.2,
     * 3.2.5.2.1, and 3.2.5.2.2 for details.
     */
    public static final int NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000;

    /**
     * 128-bit session key negotiation. An alternate name for this field is
     * NTLMSSP_NEGOTIATE_128. If the client sends NTLMSSP_NEGOTIATE_128 to the
     * server in the NEGOTIATE_MESSAGE, the server MUST return
     * NTLMSSP_NEGOTIATE_128 to the client in the CHALLENGE_MESSAGE only if the
     * client sets NTLMSSP_NEGOTIATE_SEAL or NTLMSSP_NEGOTIATE_SIGN. Otherwise it
     * is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are
     * requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and
     * NTLMSSP_NEGOTIATE_128 will both be returned to the client. Clients and
     * servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_128 if
     * it is supported.
     */
    public static final int NTLMSSP_NEGOTIATE_128 = 0x20000000;

    /**
     * Protocol version number. The data corresponding to this flag is provided in
     * the Version field of the NEGOTIATE_MESSAGE, the CHALLENGE_MESSAGE, and the
     * AUTHENTICATE_MESSAGE.
     */
    public static final int NTLMSSP_NEGOTIATE_VERSION = 0x02000000;

    /**
     * TargetInfo fields in the CHALLENGE_MESSAGE (section 2.2.1.2) are populated.
     */
    public static final int NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000;

    /** LMOWF (section 3.3). */
    public static final int NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000;

    /** An identify level token. */
    public static final int NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000;

    /**
     * NTLM v2 session security. NTLM v2 session security is a misnomer because it
     * is not NTLM v2. It is NTLM v1 using the extended session security that is
     * also in NTLM v2. NTLMSSP_NEGOTIATE_LM_KEY and
     * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both
     * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and NTLMSSP_NEGOTIATE_LM_KEY are
     * requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be
     * returned to the client. NTLM v2 authentication session key generation MUST
     * be supported by both the client and the DC in order to be used, and
     * extended session security signing and sealing requires support from the
     * client and the server in order to be used.
     */
    public static final int NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY = 0x00080000;

    /**
     * TargetName MUST be a server name. The data corresponding to this flag is
     * provided by the server in the TargetName field of the CHALLENGE_MESSAGE. If
     * this bit is set, then NTLMSSP_TARGET_TYPE_DOMAIN MUST NOT be set. This flag
     * MUST be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE.
     */
    public static final int NTLMSSP_TARGET_TYPE_SERVER = 0x00020000;

    /**
     * TargetName MUST be a domain name. The data corresponding to this flag is
     * provided by the server in the TargetName field of the CHALLENGE_MESSAGE. If
     * set, then NTLMSSP_TARGET_TYPE_SERVER MUST NOT be set. This flag MUST be
     * ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE.
     */
    public static final int NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000;

    /**
     * Signature block on all messages. NTLMSSP_NEGOTIATE_ALWAYS_SIGN MUST be set
     * in the NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the
     * client. NTLMSSP_NEGOTIATE_ALWAYS_SIGN is overridden by
     * NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL, if they are supported.
     */
    public static final int NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000;

    /**
     * Workstation field is present. If this flag is not set, the Workstation
     * field MUST be ignored. If this flag is set, the length field of the
     * Workstation field specifies whether the workstation name is nonempty or
     * not.
     */
    public static final int NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000;

    /**
     * Domain name is provided.
     *
     * Sent by the client in the Type 1 message to indicate that the name of the
     * domain in which the client workstation has membership is included in the
     * message. This is used by the server to determine whether the client is
     * eligible for local authentication.
     */
    public static final int NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000;

    /**
     * Connection SHOULD be anonymous.
     *
     * Sent by the client in the Type 3 message to indicate that an anonymous
     * context has been established. This also affects the response fields (as
     * detailed in the "Anonymous Response" section).
     */
    public static final int NTLMSSP_NEGOTIATE_ANONYMOUS = 0x00000800;

    /**
     * Usage of the NTLM v1 session security protocol. NTLMSSP_NEGOTIATE_NTLM MUST
     * be set in the NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to
     * the client.
     */
    public static final int NTLMSSP_NEGOTIATE_NTLM = 0x00000200;

    /**
     * LAN Manager (LM) session key computation. NTLMSSP_NEGOTIATE_LM_KEY and
     * NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both
     * NTLMSSP_NEGOTIATE_LM_KEY and NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are
     * requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be
     * returned to the client. NTLM v2 authentication session key generation MUST
     * be supported by both the client and the DC in order to be used, and
     * extended session security signing and sealing requires support from the
     * client and the server to be used.
     */
    public static final int NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080;

    /**
     * Connectionless authentication. If NTLMSSP_NEGOTIATE_DATAGRAM is set, then
     * NTLMSSP_NEGOTIATE_KEY_EXCH MUST always be set in the AUTHENTICATE_MESSAGE
     * to the server and the CHALLENGE_MESSAGE to the client.
     */
    public static final int NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040;

    /**
     * Session key negotiation for message confidentiality. If the client sends
     * NTLMSSP_NEGOTIATE_SEAL to the server in the NEGOTIATE_MESSAGE, the server
     * MUST return NTLMSSP_NEGOTIATE_SEAL to the client in the CHALLENGE_MESSAGE.
     * Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD always set
     * NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128, if they are supported.
     */
    public static final int NTLMSSP_NEGOTIATE_SEAL = 0x00000020;

    /**
     * Session key negotiation for message signatures. If the client sends
     * NTLMSSP_NEGOTIATE_SIGN to the server in the NEGOTIATE_MESSAGE, the server
     * MUST return NTLMSSP_NEGOTIATE_SIGN to the client in the CHALLENGE_MESSAGE.
     */
    public static final int NTLMSSP_NEGOTIATE_SIGN = 0x00000010;

    /**
     * TargetName field of the CHALLENGE_MESSAGE (section 2.2.1.2) MUST be
     * supplied.
     */
    public static final int NTLMSSP_REQUEST_TARGET = 0x00000004;

    /**
     * OEM character set encoding.
     *
     * @see NTLMSSP_NEGOTIATE_UNICODE
     */
    public static final int NTLMSSP_NEGOTIATE_OEM = 0x00000002;

    /**
     * Unicode character set encoding.
     *
     * The NTLMSSP_NEGOTIATE_UNICODE(A) and NTLM_NEGOTIATE_OEM(B) bits are
     * evaluated together as follows:
     * <ul>
     * <li>A==1: The choice of character set encoding MUST be Unicode.
     *
     * <li>A==0 and B==1: The choice of character set encoding MUST be OEM.
     *
     * <li>A==0 and B==0: The protocol MUST return SEC_E_INVALID_TOKEN.
     * <ul>
     * */
    public static final int NTLMSSP_NEGOTIATE_UNICODE = 0x00000001;

    public int value;

    public NegoFlags(int value) {
        this.value = value;
    }

    public NegoFlags() {
        value = 0;
    }

    @Override
    public String toString() {
        return String.format("NegoFlags [value=0x%04x (%s)]", value, flagsToSting());
    }

    public String flagsToSting() {

        String str = "";

        if (NEGOTIATE_56())
            str += "NEGOTIATE_56 ";
        if (NEGOTIATE_KEY_EXCH())
            str += "NEGOTIATE_KEY_EXCH ";
        if (NEGOTIATE_128())
            str += "NEGOTIATE_128 ";
        if (NEGOTIATE_VERSION())
            str += "NEGOTIATE_VERSION ";
        if (NEGOTIATE_TARGET_INFO())
            str += "NEGOTIATE_TARGET_INFO ";
        if (REQUEST_NON_NT_SESSION_KEY())
            str += "REQUEST_NON_NT_SESSION_KEY ";
        if (NEGOTIATE_IDENTIFY())
            str += "NEGOTIATE_IDENTIFY ";
        if (NEGOTIATE_EXTENDED_SESSION_SECURITY())
            str += "NEGOTIATE_EXTENDED_SESSION_SECURITY ";
        if (TARGET_TYPE_SERVER())
            str += "TARGET_TYPE_SERVER ";
        if (TARGET_TYPE_DOMAIN())
            str += "TARGET_TYPE_DOMAIN ";
        if (NEGOTIATE_ALWAYS_SIGN())
            str += "NEGOTIATE_ALWAYS_SIGN ";
        if (NEGOTIATE_OEM_WORKSTATION_SUPPLIED())
            str += "NEGOTIATE_OEM_WORKSTATION_SUPPLIED ";
        if (NEGOTIATE_OEM_DOMAIN_SUPPLIED())
            str += "NEGOTIATE_OEM_DOMAIN_SUPPLIED ";
        if (NEGOTIATE_ANONYMOUS())
            str += "NEGOTIATE_ANONYMOUS ";
        if (NEGOTIATE_NTLM())
            str += "NEGOTIATE_NTLM ";
        if (NEGOTIATE_LM_KEY())
            str += "NEGOTIATE_LM_KEY ";
        if (NEGOTIATE_DATAGRAM())
            str += "NEGOTIATE_DATAGRAM ";
        if (NEGOTIATE_SEAL())
            str += "NEGOTIATE_SEAL ";
        if (NEGOTIATE_SIGN())
            str += "NEGOTIATE_SIGN ";
        if (REQUEST_TARGET())
            str += "REQUEST_TARGET ";
        if (NEGOTIATE_OEM())
            str += "NEGOTIATE_OEM ";
        if (NEGOTIATE_UNICODE())
            str += "NEGOTIATE_UNICODE ";

        return str;
    }

    public boolean NEGOTIATE_56() {
        return ((value & NTLMSSP_NEGOTIATE_56) != 0);
    }

    public boolean NEGOTIATE_KEY_EXCH() {
        return ((value & NTLMSSP_NEGOTIATE_KEY_EXCH) != 0);
    }

    public boolean NEGOTIATE_128() {
        return ((value & NTLMSSP_NEGOTIATE_128) != 0);
    }

    public boolean NEGOTIATE_VERSION() {
        return ((value & NTLMSSP_NEGOTIATE_VERSION) != 0);
    }

    public boolean NEGOTIATE_TARGET_INFO() {
        return ((value & NTLMSSP_NEGOTIATE_TARGET_INFO) != 0);
    }

    public boolean REQUEST_NON_NT_SESSION_KEY() {
        return ((value & NTLMSSP_REQUEST_NON_NT_SESSION_KEY) != 0);
    }

    public boolean NEGOTIATE_IDENTIFY() {
        return ((value & NTLMSSP_NEGOTIATE_IDENTIFY) != 0);
    }

    public boolean NEGOTIATE_EXTENDED_SESSION_SECURITY() {
        return ((value & NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY) != 0);
    }

    public boolean TARGET_TYPE_SERVER() {
        return ((value & NTLMSSP_TARGET_TYPE_SERVER) != 0);
    }

    public boolean TARGET_TYPE_DOMAIN() {
        return ((value & NTLMSSP_TARGET_TYPE_DOMAIN) != 0);
    }

    public boolean NEGOTIATE_ALWAYS_SIGN() {
        return ((value & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) != 0);
    }

    public boolean NEGOTIATE_OEM_WORKSTATION_SUPPLIED() {
        return ((value & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) != 0);
    }

    public boolean NEGOTIATE_OEM_DOMAIN_SUPPLIED() {
        return ((value & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED) != 0);
    }

    public boolean NEGOTIATE_ANONYMOUS() {
        return ((value & NTLMSSP_NEGOTIATE_ANONYMOUS) != 0);
    }

    public boolean NEGOTIATE_NTLM() {
        return ((value & NTLMSSP_NEGOTIATE_NTLM) != 0);
    }

    public boolean NEGOTIATE_LM_KEY() {
        return ((value & NTLMSSP_NEGOTIATE_LM_KEY) != 0);
    }

    public boolean NEGOTIATE_DATAGRAM() {
        return ((value & NTLMSSP_NEGOTIATE_DATAGRAM) != 0);
    }

    public boolean NEGOTIATE_SEAL() {
        return ((value & NTLMSSP_NEGOTIATE_SEAL) != 0);
    }

    public boolean NEGOTIATE_SIGN() {
        return ((value & NTLMSSP_NEGOTIATE_SIGN) != 0);
    }

    public boolean REQUEST_TARGET() {
        return ((value & NTLMSSP_REQUEST_TARGET) != 0);
    }

    public boolean NEGOTIATE_OEM() {
        return ((value & NTLMSSP_NEGOTIATE_OEM) != 0);
    }

    public boolean NEGOTIATE_UNICODE() {
        return ((value & NTLMSSP_NEGOTIATE_UNICODE) != 0);
    }

    public NegoFlags set_NEGOTIATE_56() {
        value |= NTLMSSP_NEGOTIATE_56;
        return this;
    }

    public NegoFlags set_NEGOTIATE_KEY_EXCH() {
        value |= NTLMSSP_NEGOTIATE_KEY_EXCH;
        return this;
    }

    public NegoFlags set_NEGOTIATE_128() {
        value |= NTLMSSP_NEGOTIATE_128;
        return this;
    }

    public NegoFlags set_NEGOTIATE_VERSION() {
        value |= NTLMSSP_NEGOTIATE_VERSION;
        return this;
    }

    public NegoFlags set_NEGOTIATE_TARGET_INFO() {
        value |= NTLMSSP_NEGOTIATE_TARGET_INFO;
        return this;
    }

    public NegoFlags set_REQUEST_NON_NT_SESSION_KEY() {
        value |= NTLMSSP_REQUEST_NON_NT_SESSION_KEY;
        return this;
    }

    public NegoFlags set_NEGOTIATE_IDENTIFY() {
        value |= NTLMSSP_NEGOTIATE_IDENTIFY;
        return this;
    }

    public NegoFlags set_NEGOTIATE_EXTENDED_SESSION_SECURITY() {
        value |= NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY;
        return this;
    }

    public NegoFlags set_TARGET_TYPE_SERVER() {
        value |= NTLMSSP_TARGET_TYPE_SERVER;
        return this;
    }

    public NegoFlags set_TARGET_TYPE_DOMAIN() {
        value |= NTLMSSP_TARGET_TYPE_DOMAIN;
        return this;
    }

    public NegoFlags set_NEGOTIATE_ALWAYS_SIGN() {
        value |= NTLMSSP_NEGOTIATE_ALWAYS_SIGN;
        return this;
    }

    public NegoFlags set_NEGOTIATE_OEM_WORKSTATION_SUPPLIED() {
        value |= NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED;
        return this;
    }

    public NegoFlags set_NEGOTIATE_OEM_DOMAIN_SUPPLIED() {
        value |= NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED;
        return this;
    }

    public NegoFlags set_NEGOTIATE_ANONYMOUS() {
        value |= NTLMSSP_NEGOTIATE_ANONYMOUS;
        return this;
    }

    public NegoFlags set_NEGOTIATE_NTLM() {
        value |= NTLMSSP_NEGOTIATE_NTLM;
        return this;
    }

    public NegoFlags set_NEGOTIATE_LM_KEY() {
        value |= NTLMSSP_NEGOTIATE_LM_KEY;
        return this;
    }

    public NegoFlags set_NEGOTIATE_DATAGRAM() {
        value |= NTLMSSP_NEGOTIATE_DATAGRAM;
        return this;
    }

    public NegoFlags set_NEGOTIATE_SEAL() {
        value |= NTLMSSP_NEGOTIATE_SEAL;
        return this;
    }

    public NegoFlags set_NEGOTIATE_SIGN() {
        value |= NTLMSSP_NEGOTIATE_SIGN;
        return this;
    }

    public NegoFlags set_REQUEST_TARGET() {
        value |= NTLMSSP_REQUEST_TARGET;
        return this;
    }

    public NegoFlags set_NEGOTIATE_OEM() {
        value |= NTLMSSP_NEGOTIATE_OEM;
        return this;
    }

    public NegoFlags set_NEGOTIATE_UNICODE() {
        value |= NTLMSSP_NEGOTIATE_UNICODE;
        return this;
    }

    /**
     * Example.
     */

    public static void main(String args[]) {

        NegoFlags flags = new NegoFlags(0xe20882b7);
        System.out.println("Negotiation flags: " + flags);

    }

}
