/// <summary>
        /// Set up connection with server.
        /// Including 4 steps: 1. Tcp connection 2. Negotiation 3. SessionSetup 4. TreeConnect in order
        /// </summary>
        /// <param name="server">server name of ip address</param>
        /// <param name="client">client name of ip address</param>
        /// <param name="domain">user's domain</param>
        /// <param name="userName">user's name</param>
        /// <param name="password">user's password</param>
        /// <param name="timeout">The pending time to get server's response in step 2, 3 or 4</param>
        /// <exception cref="System.Net.ProtocolViolationException">Fail to set up connection with server</exception>
        public override void Connect(
            string server,
            string client,
            string domain,
            string userName,
            string password,
            TimeSpan timeout,
            SecurityPackageType securityPackage = SecurityPackageType.Ntlm,
            bool useServerToken = false)
        {
            this.cifsClient.Connect(server, client);

            SmbPacket request, response;
            uint status;

            // Negotiate:
            SMB_Dialect dialectLM21 = new SMB_Dialect();
            dialectLM21.BufferFormat = dialectBufferFormat;
            dialectLM21.DialectString = dialectLanMan21;
            SMB_Dialect dialectNTLM = new SMB_Dialect();
            dialectNTLM.BufferFormat = dialectBufferFormat;
            dialectNTLM.DialectString = dialectNtLanMan;
            request = this.cifsClient.CreateNegotiateRequest(new SMB_Dialect[] { dialectLM21, dialectNTLM });
            this.cifsClient.SendPacket(request);
            response = this.cifsClient.ExpectPacket(timeout);
            status = (response as SmbNegotiateResponsePacket).SmbHeader.Status;

            if (status != 0)
            {
                throw new ProtocolViolationException("Negotiate Failed. ErrorCode: " + status);
            }

            // Session setup:
            CifsUserAccount userAccount = new CifsUserAccount(domain, userName, password);
            request = this.cifsClient.CreateSessionSetupRequest(userAccount, nativeOS, nativeLanMan);
            this.cifsClient.SendPacket(request);
            response = this.cifsClient.ExpectPacket(timeout);
            SmbSessionSetupAndxResponsePacket sessionSetupResponse = response as SmbSessionSetupAndxResponsePacket;
            status = sessionSetupResponse.SmbHeader.Status;

            if (status != 0)
            {
                throw new ProtocolViolationException("Session Setup Failed. ErrorCode: " + status);
            }
            this.uid = sessionSetupResponse.SmbHeader.Uid;

            // Tree connect:
            string ipcAddress = "\\\\" + server + '\\' + ipcConnectString;
            request = this.cifsClient.CreateTreeConnectAndxRequest(this.uid, TreeConnectAndxFlags.NONE,
                ipcAddress, treeConnectService, null, null);
            this.cifsClient.SendPacket(request);
            response = this.cifsClient.ExpectPacket(timeout);
            SmbTreeConnectAndxResponsePacket treeConnectResponse = response as SmbTreeConnectAndxResponsePacket;
            status = treeConnectResponse.SmbHeader.Status;

            if (status != 0)
            {
                throw new ProtocolViolationException("Tree Connect Failed. ErrorCode: " + status);
            }
            this.treeId = treeConnectResponse.SmbHeader.Tid;
        }
 /// <summary>
 /// copy constructor
 /// </summary>
 /// <param name="userAccount">the source CifsUserAccount</param>
 public CifsUserAccount(CifsUserAccount userAccount)
 {
     if (userAccount != null)
     {
         this.domainName = userAccount.DomainName;
         this.userName = userAccount.UserName;
         this.password = userAccount.Password;
     }
 }
 /// <summary>
 /// to create a SessionSetup request packet with default values and without AndX. 
 /// The appointed Authentication Policy will be used. 
 /// if ntlmAuthenticationPolicy is not Disabled, the value of ntlmAuthenticationPolicy will be used.
 /// else if lmAuthenticationPolicy is not Disabled, the value of lmAuthenticationPolicy will be used.
 /// else the plaintext Authentication Policy will be used.
 /// </summary>
 /// <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="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>     
 /// <exception cref="System.NullReferenceException">There is no connection in context. </exception>
 public SmbSessionSetupAndxRequestPacket CreateSessionSetupRequest(
     CifsUserAccount userInfo,
     string nativeOs,
     string nativeLanMan,
     NTLMAuthenticationPolicyValues ntlmAuthenticationPolicy,
     LMAuthenticationPolicyValues lmAuthenticationPolicy)
 {
     CifsClientPerConnection connection = this.Context.GetConnection(this.connectionId);
     return this.CreateSessionSetupAndxRequest(this.Context.GetMessageId(this.connectionId),
         this.defaultParameters.Flag, this.defaultParameters.Flag2, (ushort)connection.MaxBufferSize,
         connection.MaxMpxCount, 0, connection.SessionKey, connection.ServerCapabilities,
         userInfo, nativeOs, nativeLanMan, null, ntlmAuthenticationPolicy, lmAuthenticationPolicy);
 }
 /// <summary>
 /// to create a SessionSetup request packet with default values and without AndX.
 /// the plaintext Authentication Policy will be used.
 /// </summary>
 /// <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>     
 /// <returns>a SessionSetupAndx request packet</returns>
 /// <exception cref="System.NullReferenceException">There is no connection in context. </exception>
 public SmbSessionSetupAndxRequestPacket CreateSessionSetupRequest(
     CifsUserAccount userInfo,
     string nativeOs,
     string nativeLanMan)
 {
     return this.CreateSessionSetupAndxRequest(userInfo, nativeOs, nativeLanMan, 0, null);
 }
 /// <summary>
 /// to create a SessionSetupAndx request packet. the plaintext Authentication Policy will be used.
 /// </summary>
 /// <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="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="andxPacket">the andx packet.</param>
 /// <returns>a SessionSetupAndx request packet</returns>
 /// <exception cref="System.NullReferenceException">There is no connection in context. </exception>
 public SmbSessionSetupAndxRequestPacket CreateSessionSetupAndxRequest(
     CifsUserAccount userInfo,
     string nativeOs,
     string nativeLanMan,
     ushort vcNumber,
     SmbPacket andxPacket)
 {
     CifsClientPerConnection connection = this.Context.GetConnection(this.connectionId);
     return this.CreateSessionSetupAndxRequest(this.Context.GetMessageId(this.connectionId),
         this.defaultParameters.Flag, this.defaultParameters.Flag2, (ushort)connection.MaxBufferSize,
         connection.MaxMpxCount, vcNumber, connection.SessionKey, connection.ServerCapabilities,
         userInfo, nativeOs, nativeLanMan, andxPacket);
 }
 /// <summary>
 /// to create a SessionSetupAndx request packet. the plaintext Authentication Policy will be used.
 /// </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>
 /// <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)
 {
     return this.CreateSessionSetupAndxRequest(messageId, flags, flags2, maxBufferSize, maxMpxCount,
         vcNumber, sessionKey, capabilities, userInfo, nativeOs, nativeLanMan, andxPacket,
         NTLMAuthenticationPolicyValues.Disabled, LMAuthenticationPolicyValues.Disabled);
 }
        /// <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;
        }