/// <summary>
 /// to decode the smb parameters: from the general SmbParameters to the concrete Smb Parameters.
 /// </summary>
 protected override void DecodeParameters()
 {
     this.smbParameters = TypeMarshal.ToStruct<SMB_COM_SESSION_SETUP_ANDX_Request_SMB_Parameters>(
         TypeMarshal.ToBytes(this.smbParametersBlock));
 }
        /// <summary>
        /// to create a SessionSetupAndx request packet.
        /// </summary>
        /// <param name="messageId">This field SHOULD be the multiplex ID that is used to associate a response with a
        /// request.</param>
        /// <param name="flags">An 8-bit field of 1-bit flags describing various features in effect for the
        /// message</param>
        /// <param name="flags2">A 16-bit field of 1-bit flags that represent various features in effect for the
        /// message. Unspecified bits are reserved and MUST be zero.</param>
        /// <param name="maxBufferSize">The maximum size, in bytes, of the largest SMB message that the client can
        /// receive. This is the size of the largest SMB message that the server MAY send to the client. SMB message
        /// size includes the size of the SMB header, parameter, and data blocks. This size MUST not include any
        /// transport-layer framing or other transport-layer data</param>
        /// <param name="maxMpxCount">The maximum number of pending multiplexed requests supported by the client. This
        /// value MUST be less than or equal to the MaxMpxCount value provided by the server in the SMB_COM_NEGOTIATE
        /// response</param>
        /// <param name="vcNumber">The number of this VC (virtual circuit) between the client and the server. This
        /// field SHOULD be set to a value of 0 for the first virtual circuit between the client and the server and it
        /// SHOULD be set to a unique nonzero value for additional virtual circuit.</param>
        /// <param name="sessionKey">The client MUST set this to be equal to the SessionKey field in the
        /// SMB_COM_NEGOTIATE response for this SMB connection</param>
        /// <param name="capabilities">A 32-bit field providing a set of client capability indicators. The client uses
        /// this field to report its own set of capabilities to the server. The client capabilities are a subset of the
        /// server capabilities, specified in section </param>
        /// <param name="userInfo">the user account information with which the user authenticates.</param>     
        /// <param name="nativeOs">A string representing the native operating system of the CIFS client. </param>     
        /// <param name="nativeLanMan">A string that represents the native LAN manager type of the client.</param>     
        /// <param name="andxPacket">the andx packet.</param>
        /// <param name="ntlmAuthenticationPolicy">the NT LAN Manager challenge/response authentication mechanism
        /// to be used.</param>     
        /// <param name="lmAuthenticationPolicy">the LAN Manager challenge/response authentication mechanism
        /// to be used. </param>     
        /// <returns>a SessionSetupAndx request packet</returns>
        /// <exception cref="System.ArgumentNullException">the userInfo must not be null.</exception>
        public SmbSessionSetupAndxRequestPacket CreateSessionSetupAndxRequest(
            ushort messageId,
            SmbFlags flags,
            SmbFlags2 flags2,
            ushort maxBufferSize,
            ushort maxMpxCount,
            ushort vcNumber,
            uint sessionKey,
            Capabilities capabilities,
            CifsUserAccount userInfo,
            string nativeOs,
            string nativeLanMan,
            SmbPacket andxPacket,
            NTLMAuthenticationPolicyValues ntlmAuthenticationPolicy,
            LMAuthenticationPolicyValues lmAuthenticationPolicy)
        {
            #region Check parameters

            if (userInfo == null)
            {
                throw new ArgumentNullException("userInfo");
            }
            if (nativeOs == null)
            {
                nativeOs = string.Empty;
            }
            if (nativeLanMan == null)
            {
                nativeLanMan = string.Empty;
            }

            #endregion

            #region GetConnection and create SmbSessionSetupAndxRequestPacket

            CifsClientPerConnection connection = this.Context.GetConnection(this.connectionId);
            if (connection == null)
            {
                throw new InvalidOperationException("No connection set up."
                    + " Please call this method after receiving successful Negotiate response.");
            }

            this.context.NtlmAuthenticationPolicy = ntlmAuthenticationPolicy;
            this.context.LmAuthenticationPolicy = lmAuthenticationPolicy;
            this.context.PlaintextAuthenticationPolicy = PlaintextAuthenticationPolicyValues.Disabled;

            bool isUnicode = (flags2 & SmbFlags2.SMB_FLAGS2_UNICODE) == SmbFlags2.SMB_FLAGS2_UNICODE;

            SmbSessionSetupAndxRequestPacket packet = new SmbSessionSetupAndxRequestPacket();

            packet.SmbHeader = CifsMessageUtils.CreateSmbHeader(SmbCommand.SMB_COM_SESSION_SETUP_ANDX,
                messageId, 0, 0, flags, flags2);

            SMB_COM_SESSION_SETUP_ANDX_Request_SMB_Parameters smbParameters =
                new SMB_COM_SESSION_SETUP_ANDX_Request_SMB_Parameters();
            smbParameters.AndXReserved = 0;
            smbParameters.MaxBufferSize = maxBufferSize;
            smbParameters.MaxMpxCount = maxMpxCount;
            smbParameters.VcNumber = vcNumber;
            smbParameters.SessionKey = sessionKey;
            smbParameters.OEMPasswordLen = 0;
            smbParameters.UnicodePasswordLen = 0;
            smbParameters.Capabilities = capabilities;
            smbParameters.Reserved = 0;
            smbParameters.WordCount = (byte)(Marshal.SizeOf(smbParameters) / NumBytesOfWord);
            if (andxPacket == null)
            {
                smbParameters.AndXCommand = SmbCommand.SMB_COM_NO_ANDX_COMMAND;
            }
            else
            {
                smbParameters.AndXCommand = andxPacket.SmbHeader.Command;
            }

            SMB_COM_SESSION_SETUP_ANDX_Request_SMB_Data smbData = new SMB_COM_SESSION_SETUP_ANDX_Request_SMB_Data();
            smbData.AccountName = CifsMessageUtils.ToSmbStringBytes(userInfo.UserName, isUnicode);
            smbData.PrimaryDomain = CifsMessageUtils.ToSmbStringBytes(userInfo.DomainName, isUnicode);
            smbData.NativeOS = CifsMessageUtils.ToSmbStringBytes(nativeOs, isUnicode);
            smbData.NativeLanMan = CifsMessageUtils.ToSmbStringBytes(nativeLanMan, isUnicode);
            // The size of the preceding SmbParameters part plus Header part is an odd number for all cifs messages
            // If the format is Unicode, needs to add one 16 bits align pad
            if (isUnicode)
            {
                // pad 1 byte for 16-bits align:
                smbData.Pad = new byte[1];
            }
            else
            {
                smbData.Pad = new byte[0];
            }
            #endregion

            #region Get caseSensitivePassword, caseInsensitivePassword and ImplicitNtlmSessionKey

            // Initialize Implicit NTLM Token:
            NlmpVersion ntlmVersion = new NlmpVersion();
            if (ntlmAuthenticationPolicy == NTLMAuthenticationPolicyValues.Disabled)
            {
                ntlmVersion = NlmpVersion.v1;
            }
            else
            {
                ntlmVersion = NlmpVersion.v2;
            }

            byte[] caseInsensitivePassword = null;
            byte[] caseSensitivePassword = null;
            byte[] sessionBaseKey = null;
            byte[] responseKeyNT = NlmpUtility.GetResponseKeyNt(ntlmVersion, userInfo.DomainName, userInfo.UserName, userInfo.Password);
            byte[] responseKeyLM = NlmpUtility.GetResponseKeyLm(ntlmVersion, userInfo.DomainName, userInfo.UserName, userInfo.Password);
            ulong clientChallenge = BitConverter.ToUInt64(NlmpUtility.Nonce(8), 0);
            NegotiateTypes negotiateFlags = NegotiateTypes.NTLMSSP_NEGOTIATE_NTLM | NegotiateTypes.NTLM_NEGOTIATE_OEM;

            NlmpUtility.ComputeResponse(ntlmVersion,
                negotiateFlags,
                responseKeyNT,
                responseKeyLM,
                connection.Challenge,
                clientChallenge,
                connection.SystemTime,
                Encoding.Unicode.GetBytes(connection.ServerNetbiosName),
                out caseSensitivePassword,
                out caseInsensitivePassword,
                out sessionBaseKey);

            byte[] implicitNtlmSessionKey = new byte[sessionBaseKey.Length + caseSensitivePassword.Length];
            Array.Copy(sessionBaseKey, implicitNtlmSessionKey, sessionBaseKey.Length);
            Array.Copy(caseSensitivePassword, 0, implicitNtlmSessionKey, sessionBaseKey.Length, caseSensitivePassword.Length);
            packet.ImplicitNtlmSessionKey = implicitNtlmSessionKey;

            #endregion

            #region Update Password

            // Update caseSensitivePassword if it is PlainTextPassword
            if (ntlmAuthenticationPolicy == NTLMAuthenticationPolicyValues.Disabled
                && lmAuthenticationPolicy == LMAuthenticationPolicyValues.Disabled)
            {
                if (isUnicode)
                {
                    caseSensitivePassword = NlmpUtility.StringGetBytes(userInfo.Password, true);
                }
                else
                {
                    caseInsensitivePassword = NlmpUtility.StringGetBytes(userInfo.Password, false);
                }
                this.context.PlaintextAuthenticationPolicy = PlaintextAuthenticationPolicyValues.Enabled;
            }

            // Set smbData and smbParameters for the Password
            if (caseSensitivePassword != null)
            {
                smbData.UnicodePassword = caseSensitivePassword;
                smbParameters.UnicodePasswordLen = (ushort)caseSensitivePassword.Length;
            }
            if (caseInsensitivePassword != null)
            {
                smbData.OEMPassword = caseInsensitivePassword;
                smbParameters.OEMPasswordLen = (ushort)caseInsensitivePassword.Length;
            }

            #endregion

            #region Update smbData.ByteCount

            smbData.ByteCount = 0;
            if (smbData.OEMPassword != null)
            {
                smbData.ByteCount += (ushort)smbData.OEMPassword.Length;
            }
            if (smbData.UnicodePassword != null)
            {
                smbData.ByteCount += (ushort)smbData.UnicodePassword.Length;
            }
            if (smbData.Pad != null)
            {
                smbData.ByteCount += (ushort)smbData.Pad.Length;
            }
            if (smbData.AccountName != null)
            {
                smbData.ByteCount += (ushort)smbData.AccountName.Length;
            }
            if (smbData.PrimaryDomain != null)
            {
                smbData.ByteCount += (ushort)smbData.PrimaryDomain.Length;
            }
            if (smbData.NativeOS != null)
            {
                smbData.ByteCount += (ushort)smbData.NativeOS.Length;
            }
            if (smbData.NativeLanMan != null)
            {
                smbData.ByteCount += (ushort)smbData.NativeLanMan.Length;
            }
            #endregion

            packet.SmbParameters = smbParameters;
            packet.SmbData = smbData;
            packet.AndxPacket = andxPacket;

            return packet;
        }