public void UserLogon(
            DetectionInfo info,
            Smb2Client client,
            out ulong messageId,
            out ulong sessionId,
            out Guid clientGuid,
            out NEGOTIATE_Response negotiateResp,
            out bool encryptionRequired)
        {
            messageId = 1;
            sessionId = 0;
            logWriter.AddLog(LogLevel.Information, "Client connects to server");
            client.ConnectOverTCP(SUTIpAddress);

            #region Negotiate

            DialectRevision selectedDialect;
            byte[] gssToken;
            Packet_Header header;
            clientGuid = Guid.NewGuid();
            logWriter.AddLog(LogLevel.Information, "Client sends multi-protocol Negotiate to server");
            MultiProtocolNegotiate(
                client,
                1,
                1,
                Packet_Header_Flags_Values.NONE,
                messageId++,
                info.requestDialect,
                SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU
                | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES | Capabilities_Values.GLOBAL_CAP_ENCRYPTION,
                clientGuid,
                out selectedDialect,
                out gssToken,
                out header,
                out negotiateResp);

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("NEGOTIATE", header.Status);
                throw new Exception(string.Format("NEGOTIATE failed with {0}", Smb2Status.GetStatusCode(header.Status)));
            }

            #endregion

            #region Session Setup

            SESSION_SETUP_Response sessionSetupResp;

            SspiClientSecurityContext sspiClientGss =
                new SspiClientSecurityContext(
                    SecurityPackageType,
                    Credential,
                    Smb2Utility.GetCifsServicePrincipalName(SUTName),
                    ClientSecurityContextAttribute.None,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            // Server GSS token is used only for Negotiate authentication when enabled
            if (SecurityPackageType == SecurityPackageType.Negotiate)
                sspiClientGss.Initialize(gssToken);
            else
                sspiClientGss.Initialize(null);

            do
            {
                logWriter.AddLog(LogLevel.Information, "Client sends SessionSetup to server");
                client.SessionSetup(
                    1,
                    64,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    SESSION_SETUP_Request_Flags.NONE,
                    SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                    0,
                    sspiClientGss.Token,
                    out sessionId,
                    out gssToken,
                    out header,
                    out sessionSetupResp);

                if ((header.Status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || header.Status == Smb2Status.STATUS_SUCCESS) && gssToken != null && gssToken.Length > 0)
                {
                    sspiClientGss.Initialize(gssToken);
                }
            } while (header.Status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

            if (header.Status != Smb2Status.STATUS_SUCCESS)
            {
                LogFailedStatus("SESSIONSETUP", header.Status);
                throw new Exception(string.Format("SESSIONSETUP failed with {0}", Smb2Status.GetStatusCode(header.Status)));
            }

            byte[] sessionKey;
            sessionKey = sspiClientGss.SessionKey;
            encryptionRequired = sessionSetupResp.SessionFlags == SessionFlags_Values.SESSION_FLAG_ENCRYPT_DATA;
            client.GenerateCryptoKeys(
                sessionId,
                sessionKey,
                info.smb2Info.IsRequireMessageSigning, // Enable signing according to the configuration of SUT
                encryptionRequired,
                null,
                false);

            #endregion
        }
        /// <summary>
        /// Connect to server.
        /// </summary>
        /// <param name="client">Fsrvp client.</param>
        /// <param name="server">The name of server.</param>
        /// <returns>Return true if success, otherwise return false.</returns>
        private bool ConnectServer(ref FsrvpClient client, string server)
        {
            AccountCredential accountCredential =
                new AccountCredential(TestConfig.DomainName, TestConfig.UserName, TestConfig.UserPassword);

            ClientSecurityContext securityContext =
                new SspiClientSecurityContext(
                    TestConfig.DefaultSecurityPackage,
                    accountCredential,
                    Smb2Utility.GetCifsServicePrincipalName(server),
                    ClientSecurityContextAttribute.Connection
                        | ClientSecurityContextAttribute.DceStyle
                        | ClientSecurityContextAttribute.Integrity
                        | ClientSecurityContextAttribute.ReplayDetect
                        | ClientSecurityContextAttribute.SequenceDetect
                        | ClientSecurityContextAttribute.UseSessionKey,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            // This indicates that the RPC message is just integrity-protected.
            client.Context.AuthenticationLevel = TestConfig.DefaultRpceAuthenticationLevel;

            try
            {
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Connect to server {0}.", server);
                client.BindOverNamedPipe(server, accountCredential, securityContext,
                    new TimeSpan(0, 0, (int)FsrvpUtility.FSRVPTimeoutInSeconds));
            }
            catch (Exception ex)
            {
                BaseTestSite.Log.Add(LogEntryKind.Debug,
                    "Connect to server {0} failed. Exception: {1}",
                    server,
                    ex.Message);
                client.Unbind(TestConfig.Timeout);
                return false;
            }

            BaseTestSite.Log.Add(LogEntryKind.Debug, "Connect to server {0} successfully.", server);
            return true;
        }
        public void OpenFile(
            string server,
            string share,
            string file,
            SecurityPackageType securityPackageType,
            string domainName,
            string userName,
            string password,
            AccessMask accessMask)
        {
            IPHostEntry hostEntry = Dns.GetHostEntry(server);
            client.ConnectOverTCP(hostEntry.AddressList[0]);
            serverPrincipleName = Smb2Utility.GetPrincipleName(hostEntry.HostName);

            Packet_Header header;
            NEGOTIATE_Response negotiateResponse;
            DialectRevision selectedDialect;
            byte[] serverGssToken;

            CheckStatusCode(
                Negotiate(
                1,
                1,
                messageId++,
                clientGuid,
                out selectedDialect,
                out serverGssToken,
                out header,
                out negotiateResponse));

            // 3.2.5.2: If the SecurityMode field in the SMB2 header of the response has the SMB2_NEGOTIATE_SIGNING_REQUIRED bit set,
            // the client MUST set Connection.RequireSigning to TRUE.
            // 3.2.5.3.1: If the global setting RequireMessageSigning is set to TRUE or
            // Connection.RequireSigning is set to TRUE then Session.SigningRequired MUST be set to TRUE
            bool session_SigningRequired = negotiateResponse.SecurityMode.HasFlag(NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED);
            if (session_SigningRequired)
            {
                // 3.2.4.1.1: If the client signs the request, it MUST set the SMB2_FLAGS_SIGNED bit in the Flags field of the SMB2 header.
                headerFlags |= Packet_Header_Flags_Values.FLAGS_SIGNED;
            }

            SESSION_SETUP_Response sessionSetupResponse;

            SspiClientSecurityContext sspiClientGss =
                new SspiClientSecurityContext(
                    securityPackageType,
                    new AccountCredential(domainName, userName, password),
                    Smb2Utility.GetCifsServicePrincipalName(server),
                    ClientSecurityContextAttribute.None,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            if (securityPackageType == SecurityPackageType.Negotiate)
                sspiClientGss.Initialize(serverGssToken);
            else
                sspiClientGss.Initialize(null);

            uint status;
            do
            {
                status = client.SessionSetup(
                    1,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    SESSION_SETUP_Request_Flags.NONE,
                    SESSION_SETUP_Request_SecurityMode_Values.NONE,
                    SESSION_SETUP_Request_Capabilities_Values.NONE,
                    0,
                    sspiClientGss.Token,
                    out sessionId,
                    out serverGssToken,
                    out header,
                    out sessionSetupResponse);

                CheckStatusCode(status);

                if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) &&
                    serverGssToken != null && serverGssToken.Length > 0)
                {
                    sspiClientGss.Initialize(serverGssToken);
                }
            } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

            client.GenerateCryptoKeys(sessionId, sspiClientGss.SessionKey, session_SigningRequired, false);

            TREE_CONNECT_Response treeConnectResponse;

            CheckStatusCode(
                TreeConnect(
                1,
                1,
                headerFlags,
                messageId++,
                sessionId,
                server,
                share,
                out header,
                out treeConnectResponse));

            CREATE_Response createResponse;
            Smb2CreateContextResponse[] serverCreateContexts;

            CheckStatusCode(
                client.Create(
                    1,
                    1,
                    headerFlags,
                    messageId++,
                    sessionId,
                    treeId,
                    file,
                    accessMask,
                    ShareAccess_Values.FILE_SHARE_READ,
                    CreateOptions_Values.NONE,
                    CreateDisposition_Values.FILE_OPEN_IF,
                    File_Attributes.NONE,
                    ImpersonationLevel_Values.Impersonation,
                    SecurityFlags_Values.NONE,
                    RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE,
                    null,
                    out fileId,
                    out serverCreateContexts,
                    out header,
                    out createResponse));
        }
        /// <summary>
        /// Bind RPC server.
        /// </summary>
        /// <param name="swnClient">SWN rpc client</param>
        /// <param name="networkAddress">RPC network address</param>
        /// <param name="domainName">Domain name</param>
        /// <param name="userName">User name</param>
        /// <param name="password">Password</param>
        /// <param name="securityPackage">Security package</param>
        /// <param name="authLevel">Authentication level</param>
        /// <param name="timeout">Timeout</param>
        /// <param name="serverComputerName">ServerComputerName</param>
        /// <returns>Return true if success, otherwise return false</returns>
        public static bool BindServer(SwnClient swnClient, IPAddress networkAddress, string domainName, string userName, string password,
            SecurityPackageType securityPackage, RpceAuthenticationLevel authLevel, TimeSpan timeout,string serverComputerName = null)
        {
            AccountCredential accountCredential = new AccountCredential(domainName, userName, password);
            string cifsServicePrincipalName = string.Empty;
            if (!string.IsNullOrEmpty(serverComputerName))
            {
                cifsServicePrincipalName = "cifs/" + serverComputerName;
            }
            else
            {
                IPHostEntry hostEntry = null;
                try
                {
                    hostEntry = Dns.GetHostEntry(networkAddress);
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Failed to resolve network address {0} with exception: {1}", networkAddress.ToString(), ex.Message));
                }

                if (hostEntry != null && !string.IsNullOrEmpty(hostEntry.HostName))
                {
                    cifsServicePrincipalName = "cifs/" + hostEntry.HostName;
                }
                else
                {
                    throw new Exception("Failed to get HostName from network address " + networkAddress.ToString());
                }
            }
            ClientSecurityContext securityContext =
                new SspiClientSecurityContext(
                    securityPackage,
                    accountCredential,
                    cifsServicePrincipalName,
                    ClientSecurityContextAttribute.Connection
                        | ClientSecurityContextAttribute.DceStyle
                        | ClientSecurityContextAttribute.Integrity
                        | ClientSecurityContextAttribute.ReplayDetect
                        | ClientSecurityContextAttribute.SequenceDetect
                        | ClientSecurityContextAttribute.UseSessionKey,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            try
            {
                //Bind
                BaseTestSite.Log.Add(LogEntryKind.Debug, "Start to Bind RPC to {0}.", networkAddress.ToString());
                swnClient.SwnBind(networkAddress.ToString(), accountCredential, securityContext, authLevel, timeout);
            }
            catch (Exception ex)
            {
                BaseTestSite.Log.Add(LogEntryKind.Debug,
                    "Bind server {0} failed. Exception: {1}",
                    networkAddress.ToString(),
                    ex.Message);
                swnClient.SwnUnbind(timeout);
                return false;
            }

            BaseTestSite.Log.Add(LogEntryKind.Debug, "Bind server {0} successfully.", networkAddress.ToString());
            return true;
        }
        /// <summary>
        /// SessionSetup method, will be called automatically when initialize
        /// </summary>
        /// <returns>NTStatus code</returns>
        protected MessageStatus SessionSetup()
        {
            uint status;
            SESSION_SETUP_Response sessionSetupResponse;

            SspiClientSecurityContext sspiClientGss =
                new SspiClientSecurityContext(
                    SecurityPackageType.Negotiate,
                    new AccountCredential(this.domainName, this.userName, this.password),
                    Smb2Utility.GetCifsServicePrincipalName(this.serverName),
                    ClientSecurityContextAttribute.None,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            sspiClientGss.Initialize(this.gssToken);
            this.sessionId = 0;

            do
            {
                status = this.smb2Client.SessionSetup(
                    1,
                    64,
                    Packet_Header_Flags_Values.NONE,
                    this.messageId++,
                    this.sessionId,
                    SESSION_SETUP_Request_Flags.NONE,
                    SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                    0,
                    sspiClientGss.Token,
                    out sessionId,
                    out this.gssToken,
                    out packetHeader,
                    out sessionSetupResponse);

                if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) &&
                    this.gssToken != null && this.gssToken.Length > 0)
                {
                    sspiClientGss.Initialize(this.gssToken);
                }
            } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

            if (status == Smb2Status.STATUS_SUCCESS)
            {
                sessionKey = sspiClientGss.SessionKey;
                this.smb2Client.GenerateCryptoKeys(sessionId, sessionKey, true, false);
            }

            return (MessageStatus)status;
        }
        private void InternalConnectShare(string domain, string userName, string password, string shareName, TimeSpan timeout,
            SecurityPackageType securityPackage, bool useServerToken)
        {
            uint status;
            DialectRevision selectedDialect;
            Packet_Header header;
            byte[] serverGssToken;

            Array allDialects = Enum.GetValues(typeof(DialectRevision));
            DialectRevision[] validDialects = new DialectRevision[allDialects.Length - 2];
            int index = 0;
            foreach (var dialect in allDialects)
            {
                if ((DialectRevision)dialect != DialectRevision.Smb2Unknown && (DialectRevision)dialect != DialectRevision.Smb2Wildcard)
                {
                    validDialects[index++] = (DialectRevision)dialect;
                }
            }

            PreauthIntegrityHashID[] preauthIntegrityHashIDArray = null;
            EncryptionAlgorithm[] encryptionAlgorithmArray = null;
            if (validDialects.Contains(DialectRevision.Smb311))
            {
                preauthIntegrityHashIDArray = new PreauthIntegrityHashID[] { PreauthIntegrityHashID.SHA_512 };
                encryptionAlgorithmArray = new EncryptionAlgorithm[] { EncryptionAlgorithm.ENCRYPTION_AES128_GCM, EncryptionAlgorithm.ENCRYPTION_AES128_CCM };
            }

            // Negotiate:
            NEGOTIATE_Response negotiateResponse;
            CheckStatusCode(
                client.Negotiate(
                    1,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    // Will negotiate highest dialect server supports
                    validDialects,
                    SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_ENCRYPTION | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_LARGE_MTU,
                    clientGuid,
                    out selectedDialect,
                    out serverGssToken,
                    out header,
                    out negotiateResponse,
                    preauthHashAlgs: preauthIntegrityHashIDArray,
                    encryptionAlgs: encryptionAlgorithmArray));

            negotiatedDialect = selectedDialect;

            serverCapabilities = (Capabilities_Values)negotiateResponse.Capabilities;

            // 3.2.5.2: If the SecurityMode field in the SMB2 header of the response has the SMB2_NEGOTIATE_SIGNING_REQUIRED bit set,
            // the client MUST set Connection.RequireSigning to TRUE.
            // 3.2.5.3.1: If the global setting RequireMessageSigning is set to TRUE or
            // Connection.RequireSigning is set to TRUE then Session.SigningRequired MUST be set to TRUE
            bool session_SigningRequired = negotiateResponse.SecurityMode.HasFlag(NEGOTIATE_Response_SecurityMode_Values.NEGOTIATE_SIGNING_REQUIRED);
            if (session_SigningRequired)
            {
                // 3.2.4.1.1: If the client signs the request, it MUST set the SMB2_FLAGS_SIGNED bit in the Flags field of the SMB2 header.
                headerFlags |= Packet_Header_Flags_Values.FLAGS_SIGNED;
            }

            // Session setup:
            SESSION_SETUP_Response sessionSetupResponse;

            SspiClientSecurityContext sspiClientGss =
                new SspiClientSecurityContext(
                    securityPackage,
                    new AccountCredential(domain, userName, password),
                    Smb2Utility.GetCifsServicePrincipalName(serverPrincipleName),
                    ClientSecurityContextAttribute.None,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            if (securityPackage == SecurityPackageType.Negotiate)
                sspiClientGss.Initialize(serverGssToken);
            else
                sspiClientGss.Initialize(null);

            do
            {
                status = client.SessionSetup(
                    1,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    SESSION_SETUP_Request_Flags.NONE,
                    SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                    0,
                    sspiClientGss.Token,
                    out sessionId,
                    out serverGssToken,
                    out header,
                    out sessionSetupResponse);

                CheckStatusCode(status);

                if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) &&
                    serverGssToken != null && serverGssToken.Length > 0)
                {
                    sspiClientGss.Initialize(serverGssToken);
                }
            } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

            // 3.2.4.1.1 If Connection.Dialect is "3.1.1" and the message being sent is a TREE_CONNECT Request and the session identified by SessionId has Session.EncryptData equal to FALSE
            bool treeconnect_SigningRequired = session_SigningRequired || (selectedDialect >= DialectRevision.Smb311);
            client.GenerateCryptoKeys(sessionId, sspiClientGss.SessionKey, treeconnect_SigningRequired, false);

            this.sessionId = header.SessionId;

            // Session Key will be used in the MS-LSA SDK, see LsaClient.cs Line 179 SessionKey
            // Insert the session key to the global context
            Smb2ClientSession smb2CliSession = new Smb2ClientSession();
            smb2CliSession.SessionKey = client.GetSessionKeyForAuthenticatedContext(sessionId);

            Smb2ClientConnection smb2CliConn = new Smb2ClientConnection();
            smb2CliConn.SessionTable = new Dictionary<ulong, Smb2ClientSession>();
            smb2CliConn.SessionTable.Add(sessionId, smb2CliSession);

            context.ConnectionTable = new Dictionary<string, Smb2ClientConnection>();
            context.ConnectionTable.Add("Smb2ClientConnection", smb2CliConn);

            // Tree connect:
            TREE_CONNECT_Response treeConnectResponse;

            status = client.TreeConnect(
                    1,
                    1,
                    treeconnect_SigningRequired? headerFlags| Packet_Header_Flags_Values.FLAGS_SIGNED:headerFlags,
                    messageId++,
                    sessionId,
                    "\\\\" + serverPrincipleName + "\\" + shareName,
                    out treeId,
                    out header,
                    out treeConnectResponse);

            this.treeId = header.TreeId;

            // For the messages followed by TREE_CONNECT, set them as signed/not signed following the normal proces
            client.EnableSessionSigningAndEncryption(sessionId, session_SigningRequired, false);
        }
        private void InitializeClient(LeasingClientInfo clientInfo, ModelDialectRevision dialect, bool isClientSupportDirectoryLeasing = false)
        {
            #region Connect to server
            switch (testConfig.UnderlyingTransport)
            {
                case Smb2TransportType.Tcp:
                    Site.Assert.IsTrue(
                        testConfig.SutIPAddress != null && testConfig.SutIPAddress != System.Net.IPAddress.None,
                        "Server IP should not be empty when transport type is TCP.");
                    Site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over TCP", testConfig.SutIPAddress.ToString());
                    clientInfo.Client.ConnectOverTCP(testConfig.SutIPAddress);
                    break;
                case Smb2TransportType.NetBios:
                    Site.Assert.IsFalse(string.IsNullOrEmpty(testConfig.SutComputerName), "Server name should not be null when transport type is NetBIOS.");
                    Site.Log.Add(LogEntryKind.Debug, "Connect to server {0} over NetBios", testConfig.SutComputerName);
                    clientInfo.Client.ConnectOverNetbios(testConfig.SutComputerName);
                    break;
                default:
                    Site.Assert.Fail("The transport type is {0}, but currently only Tcp and NetBIOS are supported.", testConfig.UnderlyingTransport);
                    break;
            }
            #endregion

            uint status = 0;
            Packet_Header responseHeader = new Packet_Header();
            DialectRevision selectedDialect;
            DialectRevision[] dialects = Smb2Utility.GetDialects(ModelUtility.GetDialectRevision(dialect));
            NEGOTIATE_Response negotiatePayload;

            #region Negotiate
            status = clientInfo.Client.Negotiate(0, 1, Packet_Header_Flags_Values.NONE, clientInfo.MessageId++,
                dialects, SecurityMode_Values.NONE, isClientSupportDirectoryLeasing ? Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING : Capabilities_Values.NONE,
                clientInfo.ClientGuid,
                out selectedDialect,
                out clientInfo.ServerGssToken,
                out responseHeader,
                out negotiatePayload);
            Site.Assert.AreEqual(ModelUtility.GetDialectRevision(dialect), negotiatePayload.DialectRevision,
                "DialectRevision 0x{0:x4} is expected.", (ushort)ModelUtility.GetDialectRevision(dialect));
            Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Negotiation is expected success");
            clientInfo.Dialect = selectedDialect;

            #region Validate Negotiate Response
            if (Smb2Utility.IsSmb3xFamily(selectedDialect))
            {
                Site.Assert.AreEqual<bool>(leasingConfig.IsLeasingSupported,
                    negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING),
                    "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_LEASING 0x00000002.", leasingConfig.IsLeasingSupported ? "contains" : "does not contain");
                Site.Assert.AreEqual<bool>(leasingConfig.IsDirectoryLeasingSupported & isClientSupportDirectoryLeasing,
                    negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING),
                    "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020.",
                    leasingConfig.IsDirectoryLeasingSupported & isClientSupportDirectoryLeasing ? "contains" : "does not contain");
            }
            else if (selectedDialect == DialectRevision.Smb21)
            {
                Site.Assert.AreEqual<bool>(leasingConfig.IsLeasingSupported,
                    negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING),
                    "Expect that the Capabilities in the response {0} SMB2_GLOBAL_CAP_LEASING 0x00000002.", leasingConfig.IsLeasingSupported ? "contains" : "does not contain");
                Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING),
                    "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020.");
            }
            else
            {
                Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_LEASING),
                    "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_LEASING 0x00000002.");
                Site.Assert.IsFalse(negotiatePayload.Capabilities.HasFlag(NEGOTIATE_Response_Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING),
                    "Expect that the Capabilities in the response does not contain SMB2_GLOBAL_CAP_DIRECTORY_LEASING 0x00000020.");
            }
            #endregion
            #endregion

            #region SESSION_SETUP
            Packet_Header header;
            SESSION_SETUP_Response sessionSetupResponse;

            SspiClientSecurityContext sspiClientGss =
                new SspiClientSecurityContext(
                    testConfig.DefaultSecurityPackage,
                    testConfig.AccountCredential,
                    Smb2Utility.GetCifsServicePrincipalName(testConfig.SutComputerName),
                    ClientSecurityContextAttribute.None,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

            // Server GSS token is used only for Negotiate authentication when enabled
            if (testConfig.DefaultSecurityPackage == SecurityPackageType.Negotiate && testConfig.UseServerGssToken)
                sspiClientGss.Initialize(clientInfo.ServerGssToken);
            else
                sspiClientGss.Initialize(null);

            do
            {
                status = clientInfo.Client.SessionSetup(
                    1,
                    64,
                    Packet_Header_Flags_Values.NONE,
                    clientInfo.MessageId++,
                    clientInfo.SessionId,
                    SESSION_SETUP_Request_Flags.NONE,
                    SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    SESSION_SETUP_Request_Capabilities_Values.NONE,
                    0,
                    sspiClientGss.Token,
                    out clientInfo.SessionId,
                    out clientInfo.ServerGssToken,
                    out header,
                    out sessionSetupResponse);

                if ((status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || status == Smb2Status.STATUS_SUCCESS) &&
                    clientInfo.ServerGssToken != null && clientInfo.ServerGssToken.Length > 0)
                {
                    sspiClientGss.Initialize(clientInfo.ServerGssToken);
                }
            } while (status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

            if (status == Smb2Status.STATUS_SUCCESS)
            {
                clientInfo.SessionKey = sspiClientGss.SessionKey;
                clientInfo.Client.GenerateCryptoKeys(clientInfo.SessionId, clientInfo.SessionKey, true, false);
            }

            clientInfo.GrantedCredit = header.CreditRequestResponse;
            Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "SessionSetup should succeed, actual status is {0}", Smb2Status.GetStatusCode(status));
            #endregion

            #region TREE_CONNECT to share
            TREE_CONNECT_Response treeConnectPayload;
            status = clientInfo.Client.TreeConnect(1, 1, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, uncSharePath,
                out clientInfo.TreeId, out header, out treeConnectPayload);
            Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "TreeConnect to {0} should succeed, actual status is {1}", uncSharePath, Smb2Status.GetStatusCode(status));
            if (treeConnectPayload.ShareFlags.HasFlag(ShareFlags_Values.SHAREFLAG_FORCE_LEVELII_OPLOCK))
            {
                Site.Assert.Inconclusive("This test case is not applicable for the share whose ShareFlags includes SHAREFLAG_FORCE_LEVELII_OPLOCK.");
            }
            if (treeConnectPayload.Capabilities.HasFlag(Share_Capabilities_Values.SHARE_CAP_SCALEOUT))
            {
                Site.Assert.Inconclusive("This test case is not applicable for the share whose Capabilities includes SHARE_CAP_SCALEOUT.");
            }
            #endregion
        }
        public DetectResult CheckIOCTL_ValidateNegotiateInfo(string sharename, ref DetectionInfo info)
        {
            logWriter.AddLog(LogLevel.Information, "===== Detecting IOCTL ValidateNegotiateInfo =====");

            using (Smb2Client client = new Smb2Client(new TimeSpan(0, 0, defaultTimeoutInSeconds)))
            {
                ulong messageId = 1;
                ulong sessionId = 0;
                uint treeId;
                NEGOTIATE_Response negotiateResponse;
                Guid clientGuid;
                bool encryptionRequired = false;
                DialectRevision[] preferredDialects;

                logWriter.AddLog(LogLevel.Information, "Client connects to server");
                client.ConnectOverTCP(SUTIpAddress);

                if (info.CheckHigherDialect(info.smb2Info.MaxSupportedDialectRevision, DialectRevision.Smb311))
                {
                    // VALIDATE_NEGOTIATE_INFO request is only used in 3.0 and 3.0.2
                    preferredDialects = Smb2Utility.GetDialects(DialectRevision.Smb302);
                }
                else
                {
                    preferredDialects = info.requestDialect;
                }

                #region Negotiate

                DialectRevision selectedDialect;
                byte[] gssToken;
                Packet_Header header;
                clientGuid = Guid.NewGuid();
                logWriter.AddLog(LogLevel.Information, "Client sends multi-protocol Negotiate to server");
                MultiProtocolNegotiate(
                    client,
                    1,
                    1,
                    Packet_Header_Flags_Values.NONE,
                    messageId++,
                    preferredDialects,
                    SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU
                    | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES | Capabilities_Values.GLOBAL_CAP_ENCRYPTION,
                    clientGuid,
                    out selectedDialect,
                    out gssToken,
                    out header,
                    out negotiateResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("NEGOTIATE", header.Status);
                    throw new Exception(string.Format("NEGOTIATE failed with {0}", Smb2Status.GetStatusCode(header.Status)));
                }

                #endregion

                #region Session Setup

                SESSION_SETUP_Response sessionSetupResp;

                SspiClientSecurityContext sspiClientGss =
                    new SspiClientSecurityContext(
                        SecurityPackageType,
                        Credential,
                        Smb2Utility.GetCifsServicePrincipalName(SUTName),
                        ClientSecurityContextAttribute.None,
                        SecurityTargetDataRepresentation.SecurityNativeDrep);

                // Server GSS token is used only for Negotiate authentication when enabled
                if (SecurityPackageType == SecurityPackageType.Negotiate)
                    sspiClientGss.Initialize(gssToken);
                else
                    sspiClientGss.Initialize(null);

                do
                {
                    logWriter.AddLog(LogLevel.Information, "Client sends SessionSetup to server");
                    client.SessionSetup(
                        1,
                        64,
                        Packet_Header_Flags_Values.NONE,
                        messageId++,
                        sessionId,
                        SESSION_SETUP_Request_Flags.NONE,
                        SESSION_SETUP_Request_SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED,
                        SESSION_SETUP_Request_Capabilities_Values.GLOBAL_CAP_DFS,
                        0,
                        sspiClientGss.Token,
                        out sessionId,
                        out gssToken,
                        out header,
                        out sessionSetupResp);

                    if ((header.Status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED || header.Status == Smb2Status.STATUS_SUCCESS) && gssToken != null && gssToken.Length > 0)
                    {
                        sspiClientGss.Initialize(gssToken);
                    }
                } while (header.Status == Smb2Status.STATUS_MORE_PROCESSING_REQUIRED);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("SESSIONSETUP", header.Status);
                    throw new Exception(string.Format("SESSIONSETUP failed with {0}", Smb2Status.GetStatusCode(header.Status)));
                }

                byte[] sessionKey;
                sessionKey = sspiClientGss.SessionKey;
                encryptionRequired = sessionSetupResp.SessionFlags == SessionFlags_Values.SESSION_FLAG_ENCRYPT_DATA;
                client.GenerateCryptoKeys(
                    sessionId,
                    sessionKey,
                    info.smb2Info.IsRequireMessageSigning, // Enable signing according to the configuration of SUT
                    encryptionRequired,
                    null,
                    false);

                #endregion

                #region TreeConnect

                TREE_CONNECT_Response treeConnectResp;
                string uncShare = string.Format(@"\\{0}\{1}", SUTName, sharename);

                logWriter.AddLog(LogLevel.Information, "Client sends TreeConnect to server");
                client.TreeConnect(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    uncShare,
                    out treeId,
                    out header,
                    out treeConnectResp);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREECONNECT", header.Status);
                    throw new Exception("TREECONNECT failed with " + Smb2Status.GetStatusCode(header.Status));
                }

                #endregion

                TREE_DISCONNECT_Response treeDisconnectResponse;

                #region IOCTL FSCTL_VALIDATE_NEGOTIATE_INFO

                VALIDATE_NEGOTIATE_INFO_Request validateNegotiateInfoReq;
                validateNegotiateInfoReq.Guid = clientGuid;
                validateNegotiateInfoReq.Capabilities =
                    Capabilities_Values.GLOBAL_CAP_DFS | Capabilities_Values.GLOBAL_CAP_DIRECTORY_LEASING | Capabilities_Values.GLOBAL_CAP_LARGE_MTU
                    | Capabilities_Values.GLOBAL_CAP_LEASING | Capabilities_Values.GLOBAL_CAP_MULTI_CHANNEL | Capabilities_Values.GLOBAL_CAP_PERSISTENT_HANDLES
                    | Capabilities_Values.GLOBAL_CAP_ENCRYPTION;
                validateNegotiateInfoReq.SecurityMode = SecurityMode_Values.NEGOTIATE_SIGNING_ENABLED;
                validateNegotiateInfoReq.DialectCount = (ushort)(preferredDialects.Length);
                validateNegotiateInfoReq.Dialects = preferredDialects;
                byte[] inputBuffer = TypeMarshal.ToBytes<VALIDATE_NEGOTIATE_INFO_Request>(validateNegotiateInfoReq);
                byte[] outputBuffer;
                VALIDATE_NEGOTIATE_INFO_Response validateNegotiateInfoResp;
                IOCTL_Response ioCtlResponse;

                byte[] respInput = new byte[1024];
                FILEID ioCtlFileId = new FILEID();
                ioCtlFileId.Persistent = 0xFFFFFFFFFFFFFFFF;
                ioCtlFileId.Volatile = 0xFFFFFFFFFFFFFFFF;

                logWriter.AddLog(LogLevel.Information, "Client sends FSCTL_VALIDATE_NEGOTIATE_INFO to server");
                client.IoCtl(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    CtlCode_Values.FSCTL_VALIDATE_NEGOTIATE_INFO,
                    ioCtlFileId,
                    0,
                    inputBuffer,
                    64 * 1024,
                    IOCTL_Request_Flags_Values.SMB2_0_IOCTL_IS_FSCTL,
                    out respInput,
                    out outputBuffer,
                    out header,
                    out ioCtlResponse,
                    0);

                DetectResult result = DetectResult.UnSupported;
                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("Validate Negotiate Information", header.Status);
                }
                else
                {
                    validateNegotiateInfoResp = TypeMarshal.ToStruct<VALIDATE_NEGOTIATE_INFO_Response>(outputBuffer);

                    if ((Capabilities_Values)negotiateResponse.Capabilities != validateNegotiateInfoResp.Capabilities)
                    {
                        logWriter.AddLog(LogLevel.Information, "Capabilities returned in ValidateNegotiateInfo response doesn't eaqual to server capabilities in original Negotiate response");
                    }

                    if (negotiateResponse.ServerGuid != validateNegotiateInfoResp.Guid)
                    {
                        logWriter.AddLog(LogLevel.Information, "ServerGuid returned in ValidateNegotiateInfo response doesn't eaqual to server ServerGuid in original Negotiate response");
                    }

                    if ((SecurityMode_Values)negotiateResponse.SecurityMode != validateNegotiateInfoResp.SecurityMode)
                    {
                        logWriter.AddLog(LogLevel.Information, "SecurityMode returned in ValidateNegotiateInfo response doesn't eaqual to server SecurityMode in original Negotiate response");
                    }

                    if (negotiateResponse.DialectRevision != validateNegotiateInfoResp.Dialect)
                    {
                        logWriter.AddLog(LogLevel.Information, "Validation failed for dialect supported on server");
                    }

                    result = DetectResult.Supported;
                    logWriter.AddLog(LogLevel.Information, "FSCTL_VALIDATE_NEGOTIATE_INFO is supported");
                }

                #endregion

                #region Tree Disconnect

                client.TreeDisconnect(
                    1,
                    1,
                    info.smb2Info.IsRequireMessageSigning ? Packet_Header_Flags_Values.FLAGS_SIGNED : Packet_Header_Flags_Values.NONE,
                    messageId++,
                    sessionId,
                    treeId,
                    out header,
                    out treeDisconnectResponse);

                if (header.Status != Smb2Status.STATUS_SUCCESS)
                {
                    LogFailedStatus("TREEDISCONNECT", header.Status);
                }

                #endregion

                return result;
            }
        }
        /// <summary>
        /// Implements IDisposable interface(from NetworkStream)
        /// </summary>
        /// <param name="disposing">Indicates if there's managed resource to release</param>
        protected override void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    // Clean managed resource
                    CloseClientStream();

                    if (context != null)
                    {
                        context.Dispose();
                        context = null;
                    }
                }
                this.disposed = true;
                this.isAuthenticated = false;
            }

            base.Dispose(disposing);
        }
        /// <summary>
        /// Performs CredSSP authentication.
        /// </summary>
        /// <exception cref="IOException">Raised when attempting to read from/write to the remote connection which
        /// has been closed</exception>
        /// <exception cref="EndOfStreamException">Raised when the username or password doesn't match or authentication
        /// fails</exception>
        public void Authenticate()
        {
            // Authenticated already, do nothing
            if (isAuthenticated)
            {
                return;
            }

            credential = new AccountCredential(domain, userName, password);

            byte[] receivedBuffer = new byte[MaxBufferSize];
            int bytesReceived = 0;

            // Dispose the context as it may be timed out
            if (context != null)
            {
                context.Dispose();
            }
            context = new SspiClientSecurityContext(
                SecurityPackageType.CredSsp,
                credential,
                serverPrincipal,
                attribute,
                SecurityTargetDataRepresentation.SecurityNativeDrep);

            context.Initialize(null);
            // Get first token
            byte[] token = context.Token;
            // SSL handshake
            while (context.NeedContinueProcessing)
            {
                // Send handshake request
                clientStream.Write(token, 0, token.Length);
                // Get handshake resopnse
                bytesReceived = clientStream.Read(receivedBuffer, 0, receivedBuffer.Length);
                // The remote connection has been closed
                if (bytesReceived == 0)
                {
                    throw new EndOfStreamException("Authentication failed: remote connection has been closed.");
                }

                byte[] inToken = new byte[bytesReceived];
                Array.Copy(receivedBuffer, inToken, bytesReceived);
                // Get next token from response
                context.Initialize(inToken);
                token = context.Token;
            }
            // Send the last token, handshake over, CredSSP is established
            // Note if there're errors during authentication, an SSPIException will be raised
            // and isAuthentication will not be true.
            clientStream.Write(token, 0, token.Length);
            isAuthenticated = true;
        }
        protected void SetShareInfo(string sharePath, SHARE_INFO_502_I shareInfo)
        {
            using (SrvsClient srvsClient = new SrvsClient(TestConfig.Timeout))
            {
                ClientSecurityContext securityContext =
                new SspiClientSecurityContext(
                    TestConfig.DefaultSecurityPackage,
                    TestConfig.AccountCredential,
                    Smb2Utility.GetCifsServicePrincipalName(TestConfig.SutComputerName),
                    ClientSecurityContextAttribute.Connection
                        | ClientSecurityContextAttribute.DceStyle
                        | ClientSecurityContextAttribute.Integrity
                        | ClientSecurityContextAttribute.ReplayDetect
                        | ClientSecurityContextAttribute.SequenceDetect
                        | ClientSecurityContextAttribute.UseSessionKey,
                    SecurityTargetDataRepresentation.SecurityNativeDrep);

                srvsClient.Bind(TestConfig.SutComputerName, TestConfig.AccountCredential, securityContext);
                SHARE_INFO info = new SHARE_INFO { ShareInfo502 = shareInfo };
                uint? parmErr = 0;
                uint retVal = srvsClient.NetrShareSetInfo(@"\\" + TestConfig.SutComputerName, sharePath, SHARE_ENUM_STRUCT_LEVEL.Level502, info, ref parmErr);
                if (retVal != 0)
                {
                    BaseTestSite.Assert.Fail("Fail to get share info through MS-SRVS.");
                }
                srvsClient.UnBind();
            }
        }