public static void FileOperationVerifyEncryptionResponse(ModelSmb2Status status, ModelResponseType modelResponseType, EncryptionConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);
            Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled);
            Condition.IsTrue(Session_IsExisted);

            ModelFileOperationVerifyEncryptionRequest createFileRequest = ModelHelper.RetrieveOutstandingRequest <ModelFileOperationVerifyEncryptionRequest>(ref request);


            if (!VerifySession(status, createFileRequest.modelRequestType))
            {
                return;
            }

            if (!VerifyTreeConnect(status, createFileRequest.modelRequestType, c))
            {
                return;
            }

            //TODO: To be implemented after TRANSFORM_HEADER added into Smb2FunctionalClient
            if (createFileRequest.modelRequestType == ModelRequestType.EncryptedRequest)
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.EncryptedResponse);
            }
            else
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.UnEncryptedResponse);
            }

            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }
        private static bool VerifySession(ModelSmb2Status status, ModelRequestType modelRequestType, EncryptionConfig c)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.2.9 Verifying the Session");
            if (Smb2Utility.IsSmb3xFamily(negotiateDialect) &&
                Session_EncryptData == SessionEncryptDataType.SessionEncryptDataSet &&
                (modelRequestType == ModelRequestType.UnEncryptedRequest) &&
                (config.MaxSmbVersionSupported == ModelDialectRevision.Smb311 ||
                 ((config.MaxSmbVersionSupported == ModelDialectRevision.Smb30 || config.MaxSmbVersionSupported == ModelDialectRevision.Smb302) &&
                  config.IsGlobalRejectUnencryptedAccessEnabled)))
            {
                ModelHelper.Log(LogType.Requirement,
                                "If Connection.Dialect belongs to the SMB 3.x dialect family, and Session.EncryptData is TRUE, " +
                                "the server MUST do the following: \n" +
                                "\tIf the server supports the 3.1.1 dialect, locate the Request in Connection.RequestList for which " +
                                "Request.MessageId matches the MessageId value in the SMB2 header of the request." +
                                "\tOtherwise, if the server supports 3.0 or 3.0.2 dialect, and RejectUnencryptedAccess is TRUE, " +
                                "locate the Request in Connection.RequestList for which Request.MessageId matches the MessageId " +
                                "value in the SMB2 header of the request.\n" +
                                "If Request.IsEncrypted is FALSE, the server MUST fail the request with STATUS_ACCESS_DENIED");
                ModelHelper.Log(LogType.TestInfo, "Server supports {0}, RejectUnencryptedAccess is {1}",
                                config.MaxSmbVersionSupported, config.IsGlobalRejectUnencryptedAccessEnabled ? "TRUE" : "FALSE");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return(false);
            }
            return(true);
        }
        public static void TreeDisconnectResponse(ModelSmb2Status status)
        {
            Condition.IsTrue(State == ModelState.Connected);

            ModelTreeMgmtTreeDisconnectRequest treeDisconnectRequest = ModelHelper.RetrieveOutstandingRequest <ModelTreeMgmtTreeDisconnectRequest>(ref Request);

            if (!Session_TreeConnectExist ||
                treeDisconnectRequest.treeId != ModelTreeId.ValidExistTreeId)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.2.11: The server MUST look up the TreeConnect in Session.TreeConnectTable by using the TreeId in the SMB2 header of the request." +
                    " If no tree connect is found, the request MUST be failed with STATUS_NETWORK_NAME_DELETED");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "TreeConnect {0} in Session.TreeConnectTable, tree id is {1}",
                    Session_TreeConnectExist ? "exists" : "does not exist", treeDisconnectRequest.treeId);
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_NETWORK_NAME_DELETED);
                return;
            }

            ModelHelper.Log(
                LogType.Requirement,
                "3.3.5.8: The tree connect MUST then be removed from Session.TreeConnectTable and freed");

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
            Session_TreeConnectExist = false;

            ModelHelper.Log(
                LogType.TestInfo,
                "TreeConnect is removed from Session.TreeConnectTable");
        }
Exemple #4
0
        public void ComNegotiateRequest(Sequence <string> dialects)
        {
            Packet_Header      responseHeader  = new Packet_Header();
            DialectRevision    selectedDialect = DialectRevision.Smb2Unknown;
            NEGOTIATE_Response responsePayload = new NEGOTIATE_Response();

            byte[]          smb2ClientGssToken;
            ModelSmb2Status status = ModelSmb2Status.STATUS_SUCCESS;

            try
            {
                status = (ModelSmb2Status)smb2Client.MultiProtocolNegotiate(dialects.ToArray(), out selectedDialect, out smb2ClientGssToken, out responseHeader, out responsePayload);
                if (status != ModelSmb2Status.STATUS_SUCCESS)
                {
                    selectedDialect = DialectRevision.Smb2Unknown;
                }
                this.NegotiateResponse(status, selectedDialect);
                if (selectedDialect == DialectRevision.Smb2Wildcard)
                {
                    messageId = 1;
                }
            }
            catch
            {
            }
        }
 /// <summary>
 /// The server MUST sign the message under the following conditions
 /// </summary>
 private static void VerifyResponseShouldSign(
     ModelSmb2Status status,
     SigningModelRequest request,
     SigningModelSessionId sessionId,
     SigningFlagType signingFlagType)
 {
     if (request.signingFlagType == SigningFlagType.SignedFlagSet &&
         sessionId == SigningModelSessionId.NonZeroSessionId &&
         Session_SigningRequired)
     {
         ModelHelper.Log(LogType.Requirement, "3.3.4.1.1: The server SHOULD<182> sign the message under the following conditions:");
         ModelHelper.Log(LogType.Requirement,
                         "\tIf the request was signed by the client, the response message being sent contains a nonzero SessionId and a zero TreeId in the SMB2 header, " +
                         "and the session identified by SessionId has Session.SigningRequired equal to TRUE.");
         ModelHelper.Log(LogType.TestInfo, "The condition is met.");
         Condition.IsTrue(signingFlagType == SigningFlagType.SignedFlagSet);
     }
     else if (request.signingFlagType == SigningFlagType.SignedFlagSet)
     {
         ModelHelper.Log(LogType.Requirement, "3.3.4.1.1: The server SHOULD<182> sign the message under the following conditions:");
         ModelHelper.Log(LogType.Requirement,
                         "\tIf the request was signed by the client, and the response is not an interim response to an asynchronously processed request.");
         ModelHelper.Log(LogType.TestInfo, "The condition is met.");
         Condition.IsTrue(signingFlagType == SigningFlagType.SignedFlagSet);
     }
 }
        private static void ReAuthentication(ModelSmb2Status status, ModelSessionSetupRequest sessionSetupRequest)
        {
            // Update both GlobalSessionTable and ConnectionList
            ModelHelper.Log(LogType.Requirement, "3.3.5.5.2: Session.State MUST be set to InProgress");
            GlobalSessionTable[sessionSetupRequest.sessionId].State = ModelSessionState.InProgress;

            ModelHelper.Log(LogType.Requirement, "Authentication is continued as specified in section 3.3.5.5.3.");
            HandleGssApiAuth(status, sessionSetupRequest);
        }
        public static void TreeConnectResponse(ModelSmb2Status status, ShareType_Values shareType, TreeMgmtServerConfig config)
        {
            Condition.IsTrue(Config.Platform == config.Platform);
            Condition.IsTrue(State == ModelState.Connected);

            ModelTreeMgmtTreeConnectRequest treeConnectRequest = ModelHelper.RetrieveOutstandingRequest <ModelTreeMgmtTreeConnectRequest>(ref Request);

            if (treeConnectRequest.sharePath == ModelSharePath.InvalidSharePath)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.7: Otherwise, the server MUST provide the tuple <hostname, sharename> parsed from the request message to invoke the event specified in [MS-SRVS] section 3.1.6.8," +
                    " to normalize the hostname by resolving server aliases and evaluating share scope. The server MUST use <normalized hostname, sharename> to look up the Share in ShareList." +
                    " If no share with a matching share name and server name is found, the server MUST fail the request with STATUS_BAD_NETWORK_NAME");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "Share path is an invalid share path");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_BAD_NETWORK_NAME);
                return;
            }

            // Only cover Windows behavior (SHOULD behavior) in one condition when the share is "IPC$" or has STYPE_SPECIAL bit set
            // Other cases for 3.3.5.7 statement below are not covered
            // Assume NonWindows will have same behvior regarding to 3.3.4.13 statement
            if (Session_SecurityContext == ModelSessionSecurityContext.NonAdmin &&
                treeConnectRequest.sharePath == ModelSharePath.SpecialSharePath)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.7: The server MUST determine whether the user represented by Session.SecurityContext should be granted access based on the authorization policy specified in Share.ConnectSecurity." +
                    " If the server determines that access should not be granted, the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.4.13: If Share.Name is equal to \"IPC$\" or Share.Type does not have the STYPE_SPECIAL bit set," +
                    " then Share.ConnectSecurity SHOULD be set to a security descriptor allowing all users." +
                    " Otherwise, Share.ConnectSecurity SHOULD be set to a security descriptor allowing only administrators.");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "User authenticated the session is a NonAdmin, and share in the TreeConnect request has STYPE_SPECIAL bit set");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);

            if (treeConnectRequest.sharePath != ModelSharePath.SpecialSharePath)
            {
                // only check on Basic Share, Share with Special Bit can be any Type of Share
                // currently, only DISK ShareType in FileSharing Family test suite
                // it's not TD requirement but assumption
                Condition.IsTrue(shareType == ShareType_Values.SHARE_TYPE_DISK);
            }

            Session_TreeConnectExist = true;
        }
        public static void FileOperationVerifyEncryptionResponse(ModelSmb2Status status, ModelResponseType modelResponseType, EncryptionConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);
            Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled);
            Condition.IsTrue(Session_IsExisted);

            ModelFileOperationVerifyEncryptionRequest createFileRequest = ModelHelper.RetrieveOutstandingRequest <ModelFileOperationVerifyEncryptionRequest>(ref request);


            if (!VerifySession(status, createFileRequest.modelRequestType, c))
            {
                return;
            }

            if (!VerifyTreeConnect(status, createFileRequest.modelRequestType, c))
            {
                return;
            }
            ModelHelper.Log(LogType.TestInfo,
                            "The server implements {0}, Request.IsEncrypted is {1}, Connection.ServerCapabilities {2}include SMB2_GLOBAL_CAP_ENCRYPTION, " +
                            "TreeConnect.Share.EncryptData is {3}, " +
                            "EncryptData is {4}, RejectUnencryptedAccess is {5}",
                            config.MaxSmbVersionSupported,
                            createFileRequest.modelRequestType == ModelRequestType.UnEncryptedRequest ? "FALSE" : "TRUE",
                            Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION ? "" : "does not ",
                            Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare ? "TRUE" : "FALSE",
                            config.IsGlobalEncryptDataEnabled ? "TRUE" : "FALSE",
                            config.IsGlobalRejectUnencryptedAccessEnabled ? "TRUE" : "FALSE");
            if (((createFileRequest.modelRequestType == ModelRequestType.UnEncryptedRequest &&
                  (config.IsGlobalEncryptDataEnabled ||
                   Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare)) ||
                 (createFileRequest.modelRequestType == ModelRequestType.EncryptedRequest && !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)) &&
                config.IsGlobalRejectUnencryptedAccessEnabled)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.1.5: RejectUnencryptedAccess: A Boolean that, if set, " +
                                "indicates that the server will reject any unencrypted messages. " +
                                "This flag is applicable only if EncryptData is TRUE or if " +
                                "Share.EncryptData (as defined in section 3.3.1.6) is TRUE.");
                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            //TODO: To be implemented after TRANSFORM_HEADER added into Smb2FunctionalClient
            if (createFileRequest.modelRequestType == ModelRequestType.EncryptedRequest)
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.EncryptedResponse);
            }
            else
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.UnEncryptedResponse);
            }

            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }
        public static void LeaseBreakResponse(ModelSmb2Status status, uint leaseState)
        {
            Condition.IsTrue(state == ModelState.Connected);
            Condition.IsTrue(request is ModelLeaseBreakAckRequest);

            ModelLeaseBreakAckRequest leaseBreakAckRequest = ModelHelper.RetrieveOutstandingRequest <ModelLeaseBreakAckRequest>(ref request);

            ModelHelper.Log(
                LogType.Requirement,
                "The server MUST locate the lease on which the client is acknowledging a lease break by performing a lookup in LeaseTable.LeaseList " +
                "using the LeaseKey of the request as the lookup key.");
            if ((leaseBreakAckRequest.modelLeaseKeyType == ModelLeaseKeyType.InvalidLeaseKey) || smb2Lease == null)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "If no lease is found, the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                ModelHelper.Log(LogType.TestInfo, "The lease is not found.");

                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return;
            }

            if (!smb2Lease.Breaking)
            {
                ModelHelper.Log(LogType.Requirement, "If Lease.Breaking is FALSE, the server MUST fail the request with STATUS_UNSUCCESSFUL.");
                ModelHelper.Log(LogType.TestInfo, "Lease.Breaking is FALSE");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_UNSUCCESSFUL);
                return;
            }

            if (!(leaseBreakAckRequest.LeaseState <= smb2Lease.BreakToLeaseState))
            {
                ModelHelper.Log(LogType.Requirement,
                                "If LeaseState is not <= Lease.BreakToLeaseState, the server MUST fail the request with STATUS_REQUEST_NOT_ACCEPTED.");
                ModelHelper.Log(LogType.TestInfo, "LeaseState is not <= Lease.BreakToLeaseState.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_REQUEST_NOT_ACCEPTED);
                return;
            }

            ModelHelper.Log(LogType.Requirement,
                            "The server MUST set Lease.LeaseState to LeaseState received in the request, and MUST set Lease.Breaking to FALSE.");
            smb2Lease.Breaking   = false;
            smb2Lease.LeaseState = leaseState;

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);

            ModelHelper.Log(LogType.Requirement,
                            "The server then MUST construct a lease break response using the syntax specified in section 2.2.25 with the following values:");
            ModelHelper.Log(LogType.Requirement, "\tLeaseState MUST be set to Lease.LeaseState.");
            Condition.IsTrue(leaseState == leaseBreakAckRequest.LeaseState);
        }
Exemple #10
0
 /// <summary>
 /// Check must error.
 /// </summary>
 /// <param name="status">The error code returned by SUT.</param>
 /// <param name="expectedErrorCode">Specified error code according to TD.</param>
 /// <param name="checkMustError">Indicates whether to check that the error code returned by server matches MUST error code in TD strictly.</param>
 public static void CheckMustError(ModelSmb2Status status, ModelSmb2Status expectedErrorCode, MustErrorCheckLevel checkMustError)
 {
     if (checkMustError == MustErrorCheckLevel.CheckMustError)
     {
         Condition.IsTrue(status == expectedErrorCode);
     }
     else
     {
         Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
     }
 }
        public static void CloseResponse(ModelSmb2Status status, QueryResponseStatus queryResponseStatus)
        {
            Condition.IsTrue(State == ModelState.Connected);

            ModelCloseRequest closeRequest = ModelHelper.RetrieveOutstandingRequest <ModelCloseRequest>(ref Request);

            string log = null;

            if (closeRequest.VolatileType == FileIdVolatileType.InvalidFileIdVolatile)
            {
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                log = "FileId.Volatile of the Close Request is invalid, so the server cannot locate the open using FileId.Volatile as the lookup key.";
            }
            else if (closeRequest.PersistentType == FileIdPersistentType.NotEqualToOpenDurableFileID)
            {
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                log = "FileId.Persistent is not equal to Open.DurableFileId.";
            }
            else if (!HasOpen)
            {
                log = "The Open was not be created or was closed before.";
            }

            if (log != null)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.10: Next, the server MUST locate the open being closed by performing a lookup in the Session.OpenTable, using FileId.Volatile of the request as the lookup key. " +
                                "If no open is found, or if Open.DurableFileId is not equal to FileId.Persistent, the server MUST fail the request with STATUS_FILE_CLOSED.");
                ModelHelper.Log(LogType.TestInfo, log);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_CLOSED);
                return;
            }

            ModelHelper.Log(LogType.TestInfo, "The Close Request doesn't contain any invalid fields, the open is closed successfully and server should return STATUS_SUCCESS");
            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
            HasOpen = false;

            if (closeRequest.CloseType == CloseFlagType.PostQueryAttribSet)
            {
                ModelHelper.Log(LogType.Requirement, "3.3.5.10: If SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB is set in the Flags field of the request, the server MUST query the attributes of the file after the close.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB is set in the Flags field of the Close Request.");
                Condition.IsTrue(queryResponseStatus == QueryResponseStatus.QueryResponseExist);
            }
            else
            {
                ModelHelper.Log(LogType.TestInfo, "SMB2_CLOSE_FLAG_POSTQUERY_ATTRIB is not set, then the server should not query the attribute of the file after the close");
                Condition.IsTrue(queryResponseStatus == QueryResponseStatus.QueryResponseNotExist);
            }
        }
        public static void SessionSetupResponse(
            ModelSmb2Status status,
            SigningModelSessionId sessionId,
            SigningFlagType signingFlagType,
            SessionFlags_Values sessionFlag,
            SigningConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsTrue(Config.IsServerSigningRequired == c.IsServerSigningRequired);

            SigningModelRequest sessionSetupRequest = ModelHelper.RetrieveOutstandingRequest <SigningModelRequest>(ref Request);

            if (!VerifySignature(status, sessionSetupRequest))
            {
                State = ModelState.Uninitialized;
                return;
            }

            if (sessionSetupRequest.signingFlagType == SigningFlagType.SignedFlagSet ||
                (!sessionFlag.HasFlag(SessionFlags_Values.SESSION_FLAG_IS_GUEST) &&
                 !Session_IsAnonymous &&
                 (Connection_ShouldSign || c.IsServerSigningRequired)))
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.5.3: 5. Session.SigningRequired MUST be set to TRUE under the following conditions:");
                ModelHelper.Log(LogType.Requirement,
                                "\tIf the SMB2_NEGOTIATE_SIGNING_REQUIRED bit is set in the SecurityMode field of the client request.");
                ModelHelper.Log(LogType.Requirement,
                                "\tIf the SMB2_SESSION_FLAG_IS_GUEST bit is not set in the SessionFlags field " +
                                "and Session.IsAnonymous is FALSE and either Connection.ShouldSign or global RequireMessageSigning is TRUE.");

                ModelHelper.Log(LogType.TestInfo,
                                "SMB2_NEGOTIATE_SIGNING_REQUIRED is {0}set.", sessionSetupRequest.signingFlagType == SigningFlagType.SignedFlagSet ? "" : "not ");
                ModelHelper.Log(LogType.TestInfo,
                                "SMB2_SESSION_FLAG_IS_GUEST bit is {0}set.", sessionFlag.HasFlag(SessionFlags_Values.SESSION_FLAG_IS_GUEST) ? "" : "not ");
                ModelHelper.Log(LogType.TestInfo, "Session.IsAnonymous is {0}.", Session_IsAnonymous);
                ModelHelper.Log(LogType.TestInfo, "Connection.ShouldSign is {0}.", Connection_ShouldSign);
                ModelHelper.Log(LogType.TestInfo, "Global RequireMessageSigning is {0}.", c.IsServerSigningRequired);
                ModelHelper.Log(LogType.TestInfo, "So Session.SigningRequired is set to TRUE.");

                Session_SigningRequired = true;
            }

            VerifyResponseShouldSign(status, sessionSetupRequest, sessionId, signingFlagType);

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);

            Session_IsExisted = true;
        }
        public static void TreeConnectResponse(ModelSmb2Status status, SigningModelSessionId sessionId, SigningFlagType signingFlagType)
        {
            Condition.IsTrue(State == ModelState.Connected);

            SigningModelRequest treeConnectRequest = ModelHelper.RetrieveOutstandingRequest <SigningModelRequest>(ref Request);

            if (!VerifySignature(status, treeConnectRequest))
            {
                return;
            }

            VerifyResponseShouldSign(status, treeConnectRequest, sessionId, signingFlagType);

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        /// <summary>
        /// Cover section 3.3.5.2.4
        /// </summary>
        private static bool VerifySignature(ModelSmb2Status status, SigningModelRequest request)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.2.4: Verifying the Signature");
            if (request.signingFlagType == SigningFlagType.SignedFlagSet)
            {
                ModelHelper.Log(LogType.Requirement,
                                "If the SMB2 header of the request has SMB2_FLAGS_SIGNED set in the Flags field, the server MUST verify the signature. ");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_SIGNED is set in SMB2 header.");

                if (!Session_IsExisted)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "For all other requests, the server MUST look up the session in the Connection.SessionTable using the SessionId in the SMB2 header of the request. " +
                                    "If the session is not found, the request MUST be failed, as specified in section Sending an Error Response (section 3.3.4.4), " +
                                    "with the error code STATUS_USER_SESSION_DELETED.");
                    ModelHelper.Log(LogType.TestInfo, "The session is not found.");
                    ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                    return(false);
                }
            }

            if (request.signingFlagType == SigningFlagType.SignedFlagNotSet)
            {
                ModelHelper.Log(LogType.Requirement,
                                "If the SMB2 header of the request does not have SMB2_FLAGS_SIGNED set in the Flags field, " +
                                "the server MUST determine if the client failed to sign a packet that required it. " +
                                "The server MUST look up the session in the GlobalSessionTable using the SessionId in the SMB2 header of the request.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_SIGNED is not set in the SMB2 header.");

                if (Session_IsExisted && Session_SigningRequired)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If the session is found and Session.SigningRequired is equal to TRUE, the server MUST fail this request with STATUS_ACCESS_DENIED. ");
                    ModelHelper.Log(LogType.TestInfo, "The session is found and Session.SigningRequired is TRUE.");
                    ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                    return(false);
                }
            }

            return(true);
        }
        public static void ValidateNegotiateInfoResponse(ModelSmb2Status status, ValidateNegotiateInfoConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsTrue(IsSameWithNegotiate);
            Condition.IsTrue(Config.Platform == c.Platform);

            State = ModelState.Disconnected;

            if (Config.ValidateNegotiateInfoSupported == ValidateNegotiateInfoInServer.SupportValidateNegotiateInfo)
            {
                ModelHelper.Log(
                    LogType.TestInfo,
                    "FSCTL_VALIDATE_NEGOTIATE_INFO is allowed on the server");

                Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                return;
            }

            ModelHelper.Log(
                LogType.TestInfo,
                "FSCTL_VALIDATE_NEGOTIATE_INFO is not allowed on the server");

            if (Config.Platform != Platform.NonWindows)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.15: The server SHOULD<299> fail the request with STATUS_NOT_SUPPORTED when an FSCTL is not allowed on the server");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "SUT platform is {0}, so follow the SHOULD requirement", Config.Platform);
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_NOT_SUPPORTED);
            }
            else
            {
                ModelHelper.Log(
                    LogType.TestInfo,
                    "SUT platform is {0}, so only assert status is not equal to STATUS_SUCCESS", Config.Platform);

                Condition.IsFalse(status == ModelSmb2Status.STATUS_SUCCESS);
            }
        }
        public static void NegotiateResponse(ModelSmb2Status status, SigningEnabledType signingEnabledType, SigningRequiredType signingRequiredType, SigningConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);

            SigningModelRequest negotiateRequest = ModelHelper.RetrieveOutstandingRequest <SigningModelRequest>(ref Request);

            if (negotiateRequest.signingFlagType == SigningFlagType.SignedFlagSet)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.2.4: If the SMB2 Header of the SMB2 NEGOTIATE request has the SMB2_FLAGS_SIGNED bit set in the Flags field, " +
                                "the server MUST fail the request with STATUS_INVALID_PARAMETER.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_SIGNED bit in the NEGOTIATE request is set.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                State = ModelState.Uninitialized;

                return;
            }

            if (negotiateRequest.signingRequiredType == SigningRequiredType.SigningRequiredSet)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.4: If SMB2_NEGOTIATE_SIGNING_REQUIRED is set in SecurityMode, the server MUST set Connection.ShouldSign to TRUE.");
                ModelHelper.Log(LogType.TestInfo, "Connection.ShouldSign is set to TRUE.");
                Connection_ShouldSign = true;
            }

            ModelHelper.Log(LogType.Requirement, "3.3.5.4: SecurityMode MUST have the SMB2_NEGOTIATE_SIGNING_ENABLED bit set.");
            Condition.IsTrue(signingEnabledType == SigningEnabledType.SigningEnabledSet);

            Condition.IsTrue(Config.IsServerSigningRequired == c.IsServerSigningRequired);
            if (Config.IsServerSigningRequired)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.4: If RequireMessageSigning is TRUE, the server MUST also set SMB2_NEGOTIATE_SIGNING_REQUIRED in the SecurityMode field.");
                ModelHelper.Log(LogType.TestInfo, "RequireMessageSigning is TRUE.");
                Condition.IsTrue(signingRequiredType == SigningRequiredType.SigningRequiredSet);
            }

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        public static void ReEstablishResilientOpenResponse(ModelSmb2Status status)
        {
            if (Open == null)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.9.7: 1. The server MUST look up an existing open in the GlobalOpenTable by doing a lookup with the FileId.Persistent portion of the create context. " +
                                "If the lookup fails, the server SHOULD<268> fail the request with STATUS_OBJECT_NAME_NOT_FOUND " +
                                "and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                ModelHelper.Log(LogType.TestInfo, "The lookup fails.");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return;
            }

            if (!Open.IsResilient && !Open.IsDurable)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.9.7: 5. If Open.IsDurable is FALSE and Open.IsResilient is FALSE or unimplemented, " +
                                "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9");
                ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is FALSE and Open.IsResilient is FALSE.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return;
            }

            ModelReEstablishResilientOpenRequest reEstablishRequest =
                ModelHelper.RetrieveOutstandingRequest <ModelReEstablishResilientOpenRequest>(ref Request);

            if (Open.DurableOwner != reEstablishRequest.User)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.9.7: 9. If the user represented by Session.SecurityContext is not the same user denoted by Open.DurableOwner, " +
                                "the server MUST fail the request with STATUS_ACCESS_DENIED and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                ModelHelper.Log(LogType.TestInfo, "The user is different.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        private static bool VerifySession(ModelSmb2Status status, ModelRequestType modelRequestType)
        {
            if (Smb2Utility.IsSmb3xFamily(negotiateDialect) &&
                Session_EncryptData == SessionEncryptDataType.SessionEncryptDataSet &&
                config.IsGlobalRejectUnencryptedAccessEnabled &&
                modelRequestType == ModelRequestType.UnEncryptedRequest)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.2.9: If Connection.Dialect belongs to the SMB 3.x dialect family, Session.EncryptData is TRUE, " +
                                "and RejectUnencryptedAccess is TRUE, the server MUST locate the Request in Connection.RequestList " +
                                "for which Request.MessageId matches the MessageId value in the SMB2 header of the request. " +
                                "If Request.IsEncrypted is FALSE, the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return(false);
            }

            return(true);
        }
Exemple #19
0
        public void NegotiateRequest(Sequence <DialectRevision> dialects)
        {
            Packet_Header      responseHeader  = new Packet_Header();
            DialectRevision    selectedDialect = DialectRevision.Smb2Unknown;
            NEGOTIATE_Response responsePayload = new NEGOTIATE_Response();

            byte[]          smb2ClientGssToken;
            ModelSmb2Status status = ModelSmb2Status.STATUS_SUCCESS;

            try
            {
                status = (ModelSmb2Status)smb2Client.Negotiate(0, 1, Packet_Header_Flags_Values.NONE, messageId++, dialects.ToArray(), SecurityMode_Values.NONE, Capabilities_Values.NONE, Guid.NewGuid(),
                                                               out selectedDialect, out smb2ClientGssToken, out responseHeader, out responsePayload);
                if (status != ModelSmb2Status.STATUS_SUCCESS)
                {
                    selectedDialect = DialectRevision.Smb2Unknown;
                }
                this.NegotiateResponse(status, selectedDialect);
            }
            catch
            {
            }
        }
        private static void AuthNewSession(ModelSmb2Status status, ModelSessionSetupRequest sessionSetupRequest)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.5.1: A session object MUST be allocated for this request. ");

            ModelSession   session   = new ModelSession();
            ModelSessionId?sessionId = null;

            if (!GlobalSessionTable.ContainsKey(ModelSessionId.MainSessionId))
            {
                sessionId = ModelSessionId.MainSessionId;
            }
            else
            {
                sessionId = ModelSessionId.AlternativeSessionId;
            }

            // Update sessionId to new created one from zero
            sessionSetupRequest.sessionId = sessionId.Value;

            ModelHelper.Log(LogType.Requirement, "The other values MUST be initialized as follows:");
            session.Dialect = ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect;

            ModelHelper.Log(LogType.Requirement, "Session.State is set to InProgress.");
            session.State     = ModelSessionState.InProgress;
            session.SessionId = sessionId.Value;

            ModelHelper.Log(LogType.Requirement,
                            "The session MUST be inserted into the GlobalSessionTable and a unique Session.SessionId is assigned to serve as a lookup key in the table. ");
            GlobalSessionTable.Add(sessionSetupRequest.sessionId, session);

            ModelHelper.Log(LogType.Requirement, "The session MUST be inserted into Connection.SessionTable. ");
            ConnectionList[sessionSetupRequest.connectionId].Session = session;

            ModelHelper.Log(LogType.Requirement, "Using this session, authentication is continued as specified in section 3.3.5.5.3.");
            HandleGssApiAuth(status, sessionSetupRequest);
        }
        public void NegotiateRequest(List <DialectRevision> dialects)
        {
            Smb2NegotiateRequestPacket  negotiateRequest;
            Smb2NegotiateResponsePacket negotiateResponse;
            DialectRevision             selectedDialect = DialectRevision.Smb2Unknown;

            byte[]          smb2ClientGssToken;
            ModelSmb2Status status = ModelSmb2Status.STATUS_SUCCESS;

            try
            {
                status = (ModelSmb2Status)smb2Client.Negotiate(0, 1, Packet_Header_Flags_Values.NONE, messageId++, dialects.ToArray(), SecurityMode_Values.NONE, Capabilities_Values.NONE, Guid.NewGuid(),
                                                               out selectedDialect, out smb2ClientGssToken, out negotiateRequest, out negotiateResponse);
                if (status != ModelSmb2Status.STATUS_SUCCESS)
                {
                    selectedDialect = DialectRevision.Smb2Unknown;
                }
                this.NegotiateResponse(status, selectedDialect);
                testConfig.CheckNegotiateContext(negotiateRequest, negotiateResponse);
            }
            catch
            {
            }
        }
        private static bool VerifyTreeConnect(ModelSmb2Status status, ModelRequestType modelRequestType, EncryptionConfig c)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.2.11 Verifying the Tree Connect");
            if (Encryption_TreeId == EncryptionTreeId.NoTreeId)
            {
                ModelHelper.Log(LogType.Requirement,
                                "The server MUST look up the TreeConnect in Session.TreeConnectTable by using the TreeId in the SMB2 header of the request. " +
                                "If no tree connect is found, the request MUST be failed with STATUS_NETWORK_NAME_DELETED.");
                ModelHelper.Log(LogType.TestInfo, "No tree connect is found.");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_NETWORK_NAME_DELETED);
                return(false);
            }
            if (Smb2Utility.IsSmb3xFamily(negotiateDialect))
            {
                ModelHelper.Log(LogType.Requirement,
                                "If the Connection.Dialect belongs to the SMB 3.x dialect family, the server MUST fail the request with STATUS_ACCESS_DENIED in the following cases");
                ModelHelper.Log(LogType.TestInfo, "The Connection.Dialect is {0}.", negotiateDialect);
                // Actually the "EncryptData is true" is redundant since it would failed in verify session step
                if (Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION &&
                    ((config.MaxSmbVersionSupported == ModelDialectRevision.Smb311 && Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare) ||
                     ((config.MaxSmbVersionSupported == ModelDialectRevision.Smb30 || config.MaxSmbVersionSupported == ModelDialectRevision.Smb302) &&
                      (Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare || config.IsGlobalEncryptDataEnabled) && config.IsGlobalRejectUnencryptedAccessEnabled)) &&
                    modelRequestType == ModelRequestType.UnEncryptedRequest)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "\tServer supports the 3.1.1 dialect, TreeConnect.Share.EncryptData is TRUE, " +
                                    "Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_ENCRYPTION, and Request.IsEncrypted is FALSE\n" +
                                    "\tServer supports the 3.0 or 3.0.2 dialect, EncryptData or TreeConnect.Share.EncryptData is TRUE, " +
                                    "Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_ENCRYPTION, RejectUnencryptedAccess is TRUE, " +
                                    "and Request.IsEncrypted is FALSE");
                    ModelHelper.Log(LogType.TestInfo, "Server supports {0}, RejectUnencryptedAccess is {1}",
                                    config.MaxSmbVersionSupported, config.IsGlobalRejectUnencryptedAccessEnabled ? "TRUE" : "FALSE");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                    Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                    return(false);
                }
                if ((config.IsGlobalEncryptDataEnabled ||
                     Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare ||
                     modelRequestType == ModelRequestType.EncryptedRequest) &&
                    config.IsGlobalRejectUnencryptedAccessEnabled &&
                    !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "\tEncryptData or TreeConnect.Share.EncryptData or Request.IsEncrypted is TRUE, RejectUnencryptedAccess is TRUE, " +
                                    "and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION.");

                    ModelHelper.Log(LogType.TestInfo,
                                    "The server implements {0}, EncryptData is {1}, TreeConnect.Share.EncryptData is {2}, " +
                                    "Request.IsEncrypted is {3}, RejectUnencryptedAccess is TRUE, " +
                                    "and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION.",
                                    config.MaxSmbVersionSupported,
                                    config.IsGlobalEncryptDataEnabled,
                                    Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare ? "TRUE" : "FALSE",
                                    modelRequestType == ModelRequestType.EncryptedRequest ? "TRUE" : "FALSE");
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}.", config.Platform);

                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                    Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                    return(false);
                }
            }

            return(true);
        }
        public static void LogOffResponse(ModelSmb2Status status, ModelConnectionId connectionId, SessionMgmtConfig c)
        {
            Condition.IsTrue(config.Platform == c.Platform);
            if (config.Platform == Platform.NonWindows &&
                ConnectionList.ContainsKey(connectionId) &&
                ConnectionList[connectionId].Session == null &&
                ConnectionList[connectionId].ConstrainedConnection)
            {
                // The TD statements are logged in LogOffRequest
                ModelHelper.Log(LogType.TestInfo, "SUT platform is NonWindows, so server could return an error code instead of disconnect the connection.");
                Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                return;
            }

            if (VerifyFootnote(connectionId, c, status))
            {
                return;
            }

            VerifyConnection(connectionId);
            Condition.IsNotNull(ConnectionList[connectionId].Request);

            ModelLogOffRequest logOffRequest = RetrieveOutstandingRequest <ModelLogOffRequest>(connectionId);

            if (ConnectionList[connectionId].Session != null && ConnectionList[connectionId].Session.SessionId != logOffRequest.sessionId)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.2.9: If Connection.SessionTable is not empty and SessionId is not found in Connection.SessionTable, " +
                                "the server MUST fail the request with STATUS_USER_SESSION_DELETED.");
                ModelHelper.Log(LogType.TestInfo, "Connection.SessionTable is not empty and SessionId of Logoff Request is not found in Connection.SessionTable");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                return;
            }

            if (!ConnectionList[connectionId].ConstrainedConnection && ConnectionList[connectionId].Session == null)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.2.9: If Connection.ConstrainedConnection is FALSE and Connection.SessionTable is empty, then the server MUST fail any request with STATUS_USER_SESSION_DELETED.");
                ModelHelper.Log(LogType.TestInfo, "Connection.ConstrainedConnection is FALSE and Connection.SessionTable is empty.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                return;
            }

            if (GlobalSessionTable.ContainsKey(logOffRequest.sessionId))
            {
                if (GlobalSessionTable[logOffRequest.sessionId].State == ModelSessionState.InProgress)
                {
                    ModelHelper.Log(LogType.Requirement, "3.3.5.2.9: If Session.State is InProgress, the server MUST continue to process the SMB2 LOGOFF, SMB2 CLOSE, and SMB2 LOCK commands. ");
                    ModelHelper.Log(LogType.TestInfo, "Session.State is InProgress");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    // Do nothing for LOGOFF and continue
                }

                ModelHelper.Log(LogType.Requirement, "3.3.5.6: The server MUST remove this session from the GlobalSessionTable and also from the Connection.SessionTable");
                GlobalSessionTable.Remove(logOffRequest.sessionId);
                ConnectionList[logOffRequest.connectionId].Session = null;
            }

            ModelHelper.Log(LogType.TestInfo, "Verifying the Session succeeds.");
            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        /// <summary>
        /// This method is used to verify the SMB2_CREATE_DURABLE_HANDLE_REQUEST Create Context
        /// The client is requesting that the open be marked for durable operation
        /// Cover TD section: 3.3.5.9.6
        /// Return true means the message is handled by this function. 
        /// Return false means the message needs further processing.
        /// </summary>
        private static bool Handling_SMB2_CREATE_DURABLE_HANDLE_REQUEST_CreateContext(
            ModelSmb2Status status,
            ModelOpenFileRequest modelOpenFileRequest,
            DurableHandleResponseContext durableHandleResponseContext,
            HandleConfig c)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.9.6: Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST Create Context");

            if (modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextExist)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the create request also includes an SMB2_CREATE_DURABLE_HANDLE_RECONNECT create context, " +
                    "the server MUST process the create context as specified in section 3.3.5.9.7 and skip this section.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RECONNECT is included.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                return false;
            }

            if (modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextNotExist
                || modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
            {
                // Workaround to force SE explorers the platform field.
                Condition.IsTrue(Config.Platform == c.Platform);

                ModelHelper.Log(LogType.Requirement,
                    "If the create request also includes an SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 or SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 create context, " +
                    "the server SHOULD<266> fail the create request with STATUS_INVALID_PARAMETER.");

                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);

                if (modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextNotExist)
                {
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 is included.");
                }
                if (modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
                {
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is included.");
                }

                if (Config.Platform == Platform.WindowsServer2008 || Config.Platform == Platform.WindowsServer2008R2)
                {
                    ModelHelper.Log(LogType.Requirement, "<266> Section 3.3.5.9.6: Windows Vista SP1, Windows 7, Windows Server 2008, and Windows Server 2008 R2 ignore undefined create contexts.");
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}", Config.Platform);
                    Condition.IsFalse(durableHandleResponseContext == DurableHandleResponseContext.SMB2_CREATE_DURABLE_HANDLE_RESPONSE);
                    return false;
                }
                else if (Config.Platform == Platform.NonWindows)
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is NonWindows, so the server could return other error code.");
                    Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                }
                else
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}", Config.Platform);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                }

                return true;
            }

            if (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.NoOplockOrLease)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the RequestedOplockLevel field in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH and " +
                    "the create request does not include an SMB2_CREATE_REQUEST_LEASE create context with a LeaseState field that includes the SMB2_LEASE_HANDLE_CACHING bit value, " +
                    "the server MUST ignore this create context and skip this section.");
                ModelHelper.Log(LogType.TestInfo, "The create response should not contain SMB2_CREATE_DURABLE_HANDLE_RESPONSE.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                Condition.IsFalse(durableHandleResponseContext == DurableHandleResponseContext.SMB2_CREATE_DURABLE_HANDLE_RESPONSE);
                return false;
            }

            ModelHelper.Log(LogType.Requirement, "In the \"Response Construction\" phase, the server MUST construct an SMB2_CREATE_DURABLE_HANDLE_RESPONSE response create context");
            ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RESPONSE should be contained in create response");
            Condition.IsTrue(durableHandleResponseContext == DurableHandleResponseContext.SMB2_CREATE_DURABLE_HANDLE_RESPONSE);

            return false;
        }
        /// <summary>
        /// This method is used to verify the SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context
        /// The client is requesting a reconnect to an existing durable open
        /// Cover TD section: 3.3.5.9.7
        /// Return true means the message is handled by this function. 
        /// Return false means the message needs further processing.        
        /// </summary>
        private static bool Handling_SMB2_CREATE_DURABLE_HANDLE_RECONNECT_CreateContext(
            ModelSmb2Status status,
            ModelOpenFileRequest modelOpenFileRequest,
            LeaseResponseContext leaseResponseContext,
            HandleConfig c)
        {
            Condition.IsTrue(Config.Platform == c.Platform);

            ModelHelper.Log(LogType.Requirement, "3.3.5.9.7: Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context");

            if (modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextNotExist
                || modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the create request also contains an SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 or SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 create context, " +
                    "the server SHOULD<267> fail the request with STATUS_INVALID_PARAMETER.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);

                if (modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextNotExist)
                {
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 is included.");
                }
                if (modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
                {
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is included.");
                }

                if (Config.Platform == Platform.WindowsServer2008 || Config.Platform == Platform.WindowsServer2008R2)
                {
                    ModelHelper.Log(LogType.Requirement, "<267> Section 3.3.5.9.7: Windows Vista SP1, Windows Server 2008, Windows 7 and Windows Server 2008 R2 ignore undefined create contexts.");
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}.", Config.Platform);
                    Condition.IsTrue(leaseResponseContext == LeaseResponseContext.NONE);
                    return false;
                }
                else if (Config.Platform == Platform.NonWindows)
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is NonWindows, so the server could return other error code.");
                    Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                }
                else
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}", Config.Platform);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                }

                return true;
            }

            ModelHelper.Log(LogType.Requirement,
                "The server MUST look up an existing open in the GlobalOpenTable by doing a lookup with the FileId.Persistent portion of the create context. ");

            if (Open == null)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the lookup fails, the server SHOULD<268> fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                ModelHelper.Log(LogType.TestInfo, "The open does not exist and the SUT platform is {0}.", Config.Platform);
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);

                if (Config.Platform == Platform.NonWindows)
                    Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                else
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            if (Open.IsLeaseExisted && !modelOpenFileRequest.isSameClient)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Open.Lease is not NULL and Open.ClientGuid is not equal to the ClientGuid of the connection that received this request, " +
                    "the server MUST fail the create request with STATUS_OBJECT_NAME_NOT_FOUND.");
                ModelHelper.Log(LogType.TestInfo, "Open.Lease is not NULL and Open.ClientGuid is not equal to the ClientGuid of the connection.");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            if (NegotiateDialect != DialectRevision.Smb2002
                && !Open.IsLeaseExisted
                && (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1 || modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV2))
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Open.Lease is NULL and the SMB2_CREATE_REQUEST_LEASE_V2 or the SMB2_CREATE_REQUEST_LEASE create context is present, " +
                    "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                ModelHelper.Log(LogType.TestInfo,
                    "Open.Lease is NULL and {0} is present.",
                    modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1 ? "SMB2_CREATE_REQUEST_LEASE" : "SMB2_CREATE_REQUEST_LEASE_V2");

                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            if (!Open.IsDurable)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Open.IsDurable is FALSE and Open.IsResilient is FALSE or unimplemented, " +
                    "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9");
                ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is FALSE and Open.IsResilient is FALSE.");

                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            if (Open.IsSessionExisted)
            {
                ModelHelper.Log(LogType.Requirement, "If Open.Session is not NULL, the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                ModelHelper.Log(LogType.TestInfo, "Open.Session is not NULL.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            // workaround for SE bug
            Condition.IsTrue(Config.IsLeasingSupported == c.IsLeasingSupported);
            Condition.IsTrue(Config.IsDirectoryLeasingSupported == c.IsDirectoryLeasingSupported);

            if (Open.IsLeaseExisted
                && modelOpenFileRequest.oplockLeaseType != OplockLeaseType.LeaseV1
                && modelOpenFileRequest.oplockLeaseType != OplockLeaseType.LeaseV2)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3. If Open.Lease is not NULL and the SMB2_CREATE_REQUEST_LEASE_V2 or the SMB2_CREATE_REQUEST_LEASE create context is not present, " +
                    "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            if (!Open.IsLeaseExisted
                && (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1
                || modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV2))
            {
                ModelHelper.Log(LogType.Requirement,
                    "4. If Open.Lease is NULL and the SMB2_CREATE_REQUEST_LEASE_V2 or the SMB2_CREATE_REQUEST_LEASE create context is present, " +
                    "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                ModelHelper.Log(LogType.TestInfo,
                    "Open.Lease is NULL and {0} is present.",
                    modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1 ? "SMB2_CREATE_REQUEST_LEASE" : "SMB2_CREATE_REQUEST_LEASE_V2");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            if (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV2
                && ModelUtility.IsSmb3xFamily(NegotiateDialect)
                && Config.IsDirectoryLeasingSupported
                && Open.IsLeaseExisted
                && !modelOpenFileRequest.isSameLeaseKey)
            {
                ModelHelper.Log(LogType.Requirement,
                    "7. If an SMB2_CREATE_REQUEST_LEASE_V2 create context is also present in the request, Connection.Dialect belongs to the SMB 3.x dialect family, " +
                    "the server supports directory leasing, Open.Lease is not NULL, and Open.Lease.LeaseKey does not match the LeaseKey provided in the SMB2_CREATE_REQUEST_LEASE_V2 create context, " +
                    "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            if (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1
                && (NegotiateDialect == DialectRevision.Smb21 || ModelUtility.IsSmb3xFamily(NegotiateDialect))
                && Config.IsLeasingSupported
                && Open.IsLeaseExisted
                && !modelOpenFileRequest.isSameLeaseKey)
            {
                ModelHelper.Log(LogType.Requirement,
                    "8. If an SMB2_CREATE_REQUEST_LEASE create context is also present in the request, Connection.Dialect is \"2.100\" or belongs to the SMB 3.x dialect family, " +
                    "the server supports leasing, Open.Lease is not NULL, and Open.Lease.LeaseKey does not match the LeaseKey provided in the SMB2_CREATE_REQUEST_LEASE create context, " +
                    "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return true;
            }

            if (ModelUtility.IsSmb3xFamily(NegotiateDialect)
                && Config.IsDirectoryLeasingSupported
                && Open.IsLeaseExisted
                && Open.LeaseVersion == 2)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Connection.Dialect belongs to the SMB 3.x dialect family, the server supports directory leasing, Open.Lease is not NULL, " +
                    "and Lease.Version is 2, then the server MUST construct an SMB2_CREATE_RESPONSE_LEASE_V2 create context");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. So the create response should contain SMB2_CREATE_RESPONSE_LEASE_V2 create context.");
                Condition.IsTrue(leaseResponseContext == LeaseResponseContext.SMB2_CREATE_RESPONSE_LEASE_V2);
            }

            if (ModelUtility.IsSmb3xFamily(NegotiateDialect)
                && Config.IsLeasingSupported
                && Open.IsLeaseExisted
                && Open.LeaseVersion == 1)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Connection.Dialect belongs to the SMB 3.x dialect family, the server supports leasing, Open.Lease is not NULL, and Lease.Version is 1, " +
                    "then the server MUST construct an SMB2_CREATE_RESPONSE_LEASE Create Context");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. So the create response should contain SMB2_CREATE_RESPONSE_LEASE create context.");
                Condition.IsTrue(leaseResponseContext == LeaseResponseContext.SMB2_CREATE_RESPONSE_LEASE);
            }

            if (NegotiateDialect == DialectRevision.Smb21
                && Config.IsLeasingSupported
                && Open.IsLeaseExisted)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Connection.Dialect is \"2.100\", the server supports leasing, and Open.Lease is not NULL, " +
                        "then the server MUST construct an SMB2_CREATE_RESPONSE_LEASE create context");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. So the create response should contain SMB2_CREATE_RESPONSE_LEASE create context.");
                if (Open.LeaseVersion == 1)
                    Condition.IsTrue(leaseResponseContext == LeaseResponseContext.SMB2_CREATE_RESPONSE_LEASE);
                else if (Open.LeaseVersion == 2)
                    Condition.IsTrue(leaseResponseContext == LeaseResponseContext.SMB2_CREATE_RESPONSE_LEASE_V2);
            }

            return false;
        }
        /// <summary>
        /// This method is used to verify the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context
        /// Cover TD section: 3.3.5.9.10
        /// Return true means the message is handled by this function. 
        /// Return false means the message needs further processing.        
        /// </summary>
        private static bool Handling_SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2_CreateContext(
            ModelSmb2Status status,
            ModelOpenFileRequest modelOpenFileRequest,
            DurableHandleResponseContext durableHandleResponseContext)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.9.10: Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context");

            if (modelOpenFileRequest.durableV1RequestContext == DurableV1RequestContext.DurableV1RequestContextExist
                || modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextExist
                || modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the create request also includes an SMB2_CREATE_DURABLE_HANDLE_REQUEST create context, " +
                    "or an SMB2_CREATE_DURABLE_HANDLE_RECONNECT or SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 create context, " +
                    "the server MUST fail the create request with STATUS_INVALID_PARAMETER.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);

                if (modelOpenFileRequest.durableV1RequestContext == DurableV1RequestContext.DurableV1RequestContextExist)
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_REQUEST is included.");
                if (modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextExist)
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RECONNECT is included.");
                if (modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is included.");

                Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                return true;
            }

            if (modelOpenFileRequest.durableV2RequestContext == DurableV2RequestContext.DurableV2RequestContextExistWithoutPersistent
                && modelOpenFileRequest.oplockLeaseType == OplockLeaseType.NoOplockOrLease)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of this create context, " +
                    "if RequestedOplockLevel in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH, " +
                    "and if the create request does not include a SMB2_CREATE_REQUEST_LEASE or SMB2_CREATE_REQUEST_LEASE_V2 create context  " +
                    "with a LeaseState field that includes SMB2_LEASE_HANDLE_CACHING, the server MUST ignore this create context and skip this section.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. ");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(durableHandleResponseContext == DurableHandleResponseContext.NONE);
                return false;
            }

            if (Open != null
                && modelOpenFileRequest.isSameClient
                && modelOpenFileRequest.isSameCreateGuid)
            {
                ModelHelper.Log(LogType.Requirement,
                    "The server MUST locate the Open in GlobalOpenTable where Open.CreateGuid matches the CreateGuid in the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context, " +
                    "and Open.ClientGuid matches the ClientGuid of the connection that received this request.");
                ModelHelper.Log(LogType.TestInfo, "The Open is found.");

                ModelHelper.Log(LogType.Requirement,
                    "If an Open is found and the SMB2_FLAGS_REPLAY_OPERATION bit is not set in the SMB2 header, the server MUST fail the request with STATUS_DUPLICATE_OBJECTID.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_REPLAY_OPERATION is not set.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_DUPLICATE_OBJECTID);
                return true;
            }

            if (Open == null)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If an Open is not found, the server MUST continue the create process specified in the \"Open Execution\" Phase, and perform the following additional steps:");
                Open = new HandleModelOpen();
                ModelHelper.Log(LogType.Requirement,
                    "In the \"Successful Open Initialization\" phase, the server MUST set Open.IsDurable to TRUE. ");
                Open.IsDurable = true;

                if (modelOpenFileRequest.durableV2RequestContext == DurableV2RequestContext.DurableV2RequestContextExistWithPersistent
                    && Share_IsCA
                    && ServerCapabilities_PersistentBitSet)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If the SMB2_DHANDLE_FLAG_PERSISTENT bit is set in the Flags field of the request, TreeConnect.Share.IsCA is TRUE, " +
                        "and Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_PERSISTENT_HANDLES, the server MUST set Open.IsPersistent to TRUE.");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. Open.IsPersistent is set to TRUE.");
                    Open.IsPersistent = true;
                }
            }

            if (modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextExistWithPersistent
                && modelOpenFileRequest.oplockLeaseType == OplockLeaseType.NoOplockOrLease)
            {
                ModelHelper.Log(LogType.Requirement,
                    "The server MUST skip the construction of the SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 create context " +
                    "if the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of the request and if neither of the following conditions are met:" +
                    "\tOpen.OplockLevel is equal to SMB2_OPLOCK_LEVEL_BATCH. " + "\tOpen.Lease.LeaseState has SMB2_LEASE_HANDLE_CACHING bit set.");
                ModelHelper.Log(LogType.TestInfo,
                    "All the above conditions are met. " +
                    "So the server skips the construction of the SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 create context.");
                Condition.IsTrue(durableHandleResponseContext == DurableHandleResponseContext.NONE);
            }
            else
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Open.IsPersistent is TRUE, the server MUST set the SMB2_DHANDLE_FLAG_PERSISTENT bit in the Flags field. ");
                ModelHelper.Log(LogType.TestInfo, "Open.IsPersistent is {0}", Open.IsPersistent);
                if (Open.IsPersistent)
                {
                    Condition.IsTrue(durableHandleResponseContext == DurableHandleResponseContext.SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2_WITH_PERSISTENT);
                }
            }
            return false;
        }
        private static bool VerifyTreeConnect(ModelSmb2Status status, ModelRequestType modelRequestType, EncryptionConfig c)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.2.11 Verifying the Tree Connect");

            if (Encryption_TreeId == EncryptionTreeId.NoTreeId)
            {
                ModelHelper.Log(LogType.Requirement,
                    "The server MUST look up the TreeConnect in Session.TreeConnectTable by using the TreeId in the SMB2 header of the request. " +
                    "If no tree connect is found, the request MUST be failed with STATUS_NETWORK_NAME_DELETED.");
                ModelHelper.Log(LogType.TestInfo, "No tree connect is found.");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_NETWORK_NAME_DELETED);
                return false;
            }

            if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported))
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the server implements the SMB 3.x dialect family, it MUST return STATUS_ACCESS_DENIED for the following cases:");
                ModelHelper.Log(LogType.TestInfo, "The server implements {0}.", config.MaxSmbVersionSupported);

                if (Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare
                    && config.IsGlobalRejectUnencryptedAccessEnabled
                    && modelRequestType == ModelRequestType.UnEncryptedRequest)
                {
                     ModelHelper.Log(LogType.Requirement,
                        "\tIf TreeConnect.Share.EncryptData is TRUE, RejectUnencryptedAccess is TRUE, and Request.IsEncrypted is FALSE.");
                    ModelHelper.Log(LogType.TestInfo, "The above conditions are met.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                    Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                    return false;
                }
                else if (config.IsGlobalEncryptDataEnabled
                        && config.IsGlobalRejectUnencryptedAccessEnabled
                        && modelRequestType == ModelRequestType.UnEncryptedRequest)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "\tIf EncryptData is TRUE, RejectUnencryptedAccess is TRUE, and Request.IsEncrypted is FALSE.");
                    ModelHelper.Log(LogType.TestInfo, "The above conditions are met.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                    Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                    return false;
                }
            }

            if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported)
                && (config.IsGlobalEncryptDataEnabled
                    || Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare
                    || modelRequestType == ModelRequestType.EncryptedRequest)
                && config.IsGlobalRejectUnencryptedAccessEnabled
                && !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the server implements the SMB 3.x dialect family, EncryptData or TreeConnect.Share.EncryptData or Request.IsEncrypted is TRUE, " +
                    "RejectUnencryptedAccess is TRUE, and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION, " +
                    "the server SHOULD fail the request with STATUS_ACCESS_DENIED.");

                Condition.IsTrue(config.Platform == c.Platform);
                ModelHelper.Log(LogType.TestInfo,
                    "The server implements {0}, EncryptData is {1}, TreeConnect.Share.EncryptData is {2}, " +
                    "Request.IsEncrypted is {3}, RejectUnencryptedAccess is TRUE, " +
                    "and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION.",
                    config.MaxSmbVersionSupported,
                    config.IsGlobalEncryptDataEnabled,
                    Encryption_TreeId == EncryptionTreeId.TreeIdToEncryptShare ? "TRUE" : "FALSE",
                    modelRequestType == ModelRequestType.EncryptedRequest ? "TRUE" : "FALSE");
                ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}.", config.Platform);

                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                if (config.Platform == Platform.NonWindows)
                {
                    Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                }
                else
                {
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                }
                return false;
            }

            return true;
        }
        /// <summary>
        /// Handle session channel sequence after receiving request.
        /// 3.3.5.2.10   Verifying the Channel Sequence Number
        /// </summary>
        /// <param name="requestCommand">Request command.</param>
        /// <param name="negotiateDialect">Negotiated dialect.</param>
        /// <param name="channelSequence">Session channel sequence.</param>
        /// <param name="isSetReplayFlag">Indicates whether a replay flag is set or not.</param>
        /// <param name="status">The status that server returns.</param>
        /// <returns></returns>
        private static bool PreCheckChannelSequence(
            ReplayModelRequestCommand requestCommand,
            DialectRevision negotiateDialect,
            ref ReplayModelChannelSequenceType channelSequence,
            bool isSetReplayFlag,
            ModelSmb2Status status)
        {
            if (negotiateDialect == DialectRevision.Smb2002 || negotiateDialect == DialectRevision.Smb21 ||
                requestCommand == ReplayModelRequestCommand.Create)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.2.10: If Connection.Dialect is equal to \"2.002\" or \"2.100\", or the command request does not include FileId," +
                    " this section MUST be skipped");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "Connection.Dialect is {0}. The request command is {1}", negotiateDialect, requestCommand);
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                return true;
            }

            if (!isSetReplayFlag)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.2.10: If the SMB2_FLAGS_REPLAY_OPERATION bit is not set in the Flags field of the SMB2 Header:");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);

                if (channelSequence == ReplayModelChannelSequenceType.DefaultChannelSequence)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "If ChannelSequence in the SMB2 Header is equal to Open.ChannelSequence, the server MUST increment Open.OutstandingRequestCount by 1.");

                    Open.OutstandingRequestCount += 1;

                    ModelHelper.Log(
                        LogType.TestInfo,
                        "Open.OutstandingRequestCount is {0} after increment", Open.OutstandingRequestCount);
                }
                else if (channelSequence == ReplayModelChannelSequenceType.ChannelSequenceIncrementOne ||
                          channelSequence == ReplayModelChannelSequenceType.ChannelSequenceBoundaryValid)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "Otherwise, if the unsigned difference using 16-bit arithmetic between ChannelSequence and Open.ChannelSequence is less than or equal to 0x7FFF," +
                        " the server MUST increment Open.OutstandingPreRequestCount by Open.OutstandingRequestCount, and MUST set Open.OutstandingRequestCount to 1." +
                        " The server MUST set Open.ChannelSequence to ChannelSequence in the SMB2 Header");
                    ModelHelper.Log(
                        LogType.TestInfo,
                        "ChannelSequence is {0}", channelSequence);

                    Open.OutstandingPreRequestCount += Open.OutstandingRequestCount;
                    Open.OutstandingRequestCount = 1;
                    channelSequence = ReplayModelChannelSequenceType.DefaultChannelSequence;

                    ModelHelper.Log(
                        LogType.TestInfo,
                        "Open.OutstandingPreRequestCount is {0} after increment by Open.OutstandingRequestCount with value {1}",
                        Open.OutstandingPreRequestCount, Open.OutstandingRequestCount);
                }
                else
                {
                    if (requestCommand == ReplayModelRequestCommand.Write ||
                        requestCommand == ReplayModelRequestCommand.SetInfo ||
                        requestCommand == ReplayModelRequestCommand.IoCtl)
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "Otherwise, the server MUST fail SMB2 WRITE, SET_INFO, and IOCTL requests with STATUS_FILE_NOT_AVAILABLE");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "requestCommand is {0}", requestCommand);

                        Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_NOT_AVAILABLE);
                        return false;
                    }
                }
            }
            else
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.2.10: If the SMB2_FLAGS_REPLAY_OPERATION bit is set in the Flags field of the SMB2 Header:");

                if (channelSequence == ReplayModelChannelSequenceType.DefaultChannelSequence)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "If ChannelSequence in the SMB2 Header is equal to Open.ChannelSequence and the following:");

                    if (Open.OutstandingPreRequestCount == 0)
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "If ChannelSequence in the SMB2 Header is equal to Open.ChannelSequence and Open.OutstandingPreRequestCount is equal to zero, the server MUST increment Open.OutstandingRequestCount by 1");

                        Open.OutstandingRequestCount += 1;

                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Open.OutstandingRequestCount is {0} after increment", Open.OutstandingRequestCount);
                    }
                }
                else if ((channelSequence == ReplayModelChannelSequenceType.ChannelSequenceIncrementOne ||
                          channelSequence == ReplayModelChannelSequenceType.ChannelSequenceBoundaryValid) &&
                         Open.OutstandingPreRequestCount == 0)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "Otherwise, if the unsigned difference using 16-bit arithmetic between ChannelSequence and Open.ChannelSequence is less than or equal to 0x7FFF and Open.OutstandingPreRequestCount is equal to zero," +
                        " the server MUST increment Open.OutstandingPreRequestCount by Open.OutstandingRequestCount and MUST set Open.OutstandingRequestCount to 1." +
                        " The server MUST set Open.ChannelSequence to ChannelSequence in the SMB2 Header.");

                    Open.OutstandingPreRequestCount += Open.OutstandingRequestCount;
                    Open.OutstandingRequestCount = 1;
                    channelSequence = ReplayModelChannelSequenceType.DefaultChannelSequence;

                    ModelHelper.Log(
                        LogType.TestInfo,
                        "Open.OutstandingPreRequestCount is {0} after increment by Open.OutstandingRequestCount with value {1}",
                        Open.OutstandingPreRequestCount, Open.OutstandingRequestCount);
                }
                else
                {
                    if (requestCommand == ReplayModelRequestCommand.Write ||
                        requestCommand == ReplayModelRequestCommand.SetInfo ||
                        requestCommand == ReplayModelRequestCommand.IoCtl)
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "Otherwise, the server MUST fail SMB2 WRITE, SET_INFO, and IOCTL requests with STATUS_FILE_NOT_AVAILABLE");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "requestCommand is {0}", requestCommand);
                        ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_NOT_AVAILABLE);
                        return false;
                    }
                }
            }

            return true;
        }
        public static void TreeConnectResponse(ModelSmb2Status status, SigningModelSessionId sessionId, SigningFlagType signingFlagType)
        {
            Condition.IsTrue(State == ModelState.Connected);

            SigningModelRequest treeConnectRequest = ModelHelper.RetrieveOutstandingRequest<SigningModelRequest>(ref Request);

            if (!VerifySignature(status, treeConnectRequest))
            {
                return;
            }

            VerifyResponseShouldSign(status, treeConnectRequest, sessionId, signingFlagType);

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        public static void CreateResponse(
            ModelSmb2Status status,
            ReplayModelDurableHandle durableHandleResponse,
            ReplayServerConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsNotNull(Request);

            ModelReplayCreateRequest createRequest = ModelHelper.RetrieveOutstandingRequest<ModelReplayCreateRequest>(ref Request);

            bool openIsFound = false;

            if (PreCheckChannelSequence(ReplayModelRequestCommand.Create, createRequest.channel.Connection_NegotiateDialect, ref createRequest.channelSequence,
                createRequest.isSetReplayFlag == ReplayModelSetReplayFlag.WithReplayFlag, status))
            {
                do
                {
                    if (createRequest.switchChannelType == ReplayModelSwitchChannelType.ReconnectMainChannel && 
                        LastOpen != null &&
                        LastOpen.IsPersistent &&
                        LastOpen.Lease.LeaseState == ReplayModelLeaseState.LeaseStateNotIncludeH &&
                        createRequest.fileName == ReplayModelFileName.DefaultFileName &&
                        createRequest.leaseState == ReplayModelLeaseState.LeaseStateIncludeH &&
                        createRequest.leaseKey == ReplayModelLeaseKey.DefaultLeaseKey)
                    {
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "SwitchChannelType is {0}, LastOpen is NOT null, LastOpen is persistent, LastOpen.Lease is {1}",
                            createRequest.switchChannelType, LastOpen.Lease.LeaseState);
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Parameters in create request is fileName {0}, leaseState {1}, leaseKey {2}", createRequest.fileName, createRequest.leaseState, createRequest.leaseKey);
                        ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_SHARING_VIOLATION);
                        break;
                    }

                    #region 3.3.6.1 Handle Oplock Break Acknowledgment Timer Event

                    if (createRequest.switchChannelType == ReplayModelSwitchChannelType.ReconnectMainChannel ||
                        createRequest.switchChannelType == ReplayModelSwitchChannelType.AlternativeChannelWithDisconnectMainChannel)
                    {
                        //TODO: More comments
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "When switchChannelType == AlternativeChannelWithDisconnectMainChannel or switchChannelType == ReconnectMainChannel (i.e. experiencing connection drop)," +
                            " the server will send oplock/lease break notification to the client, but currently test cases do not send acknowledgement request, so the oplock break acknowledgment timer always expires.");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "createRequest.switchChannelType is {0}", createRequest.switchChannelType);
                        ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                        if (Open != null &&
                            Open.Lease != null &&
                            Open.IsPersistent &&
                            createRequest.fileName == ReplayModelFileName.DefaultFileName)
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.6.1: When the oplock break acknowledgment timer expires, the server MUST scan for oplock breaks that have not been acknowledged by the client within the configured time." +
                                " It does this by enumerating all opens in the GlobalOpenTable. For each open, if Open.OplockState is Breaking and Open.OplockTimeout is earlier than the current time," +
                                " the server MUST acknowledge the oplock break to the underlying object store represented by Open.LocalOpen, set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE, and set Open.OplockState to None");

                            Open.OplockLevel = ReplayModelRequestedOplockLevel.OplockLevelNone;

                            ModelHelper.Log(
                                LogType.Requirement,
                                "For each lease, if Lease.Breaking is TRUE and Lease.LeaseBreakTimeout is earlier than the current time," +
                                " the server MUST acknowledge the lease break to the underlying object store represented by the opens in Lease.LeaseOpens, and set Lease.LeaseState to NONE");

                            Open.Lease.LeaseState = ReplayModelLeaseState.LeaseStateIsNone;

                            if (createRequest.createGuid == ReplayModelCreateGuid.DefaultCreateGuid)
                            {
                                Open.ConnectionIsNotNull = true;
                            }
                            else
                            {
                                LastOpen = Open;
                                Open = null;
                            }
                        }
                    }

                    #endregion

                    if (createRequest.fileName == ReplayModelFileName.DefaultFileName &&
                        Open != null &&
                        Open.IsPersistent &&
                        !Open.ConnectionIsNotNull &&
                        Open.OplockLevel != ReplayModelRequestedOplockLevel.OplockLevelBatch &&
                        ((Open.OplockLevel != ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 &&
                          Open.OplockLevel != ReplayModelRequestedOplockLevel.OplockLevelLeaseV2) ||
                         (Open.Lease != null && Open.Lease.LeaseState != ReplayModelLeaseState.LeaseStateIncludeH)))
                    {
                        // Replay will always use 3.x family
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9: If Connection.Dialect belongs to the SMB 3.x dialect family and the request does not contain SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context" +
                            " or SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context, the server MUST look up an existing open in the GlobalOpenTable" +
                            " where Open.FileName matches the file name in the Buffer field of the request. If an Open entry is found, and if all the following conditions are satisfied," +
                            " the server MUST fail the request with STATUS_FILE_NOT_AVAILABLE");
                        
                        ModelHelper.Log(
                            LogType.Requirement,
                            "\tOpen.IsPersistent is TRUE");
                        ModelHelper.Log(
                            LogType.Requirement,
                            "\tOpen.Connection is NULL");
                        ModelHelper.Log(
                            LogType.Requirement,
                            "\tOpen.OplockLevel is not equal to SMB2_OPLOCK_LEVEL_BATCH");
                        ModelHelper.Log(
                            LogType.Requirement,
                            "\tOpen.OplockLevel is not equal to SMB2_OPLOCK_LEVEL_LEASE or Open.Lease.LeaseState does not include SMB2_LEASE_HANDLE_CACHING");

                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Connection.Dialect is {0}, Open is found from GlobalOpenTable, Open.IsPersistent is {1}, Open.Connection is{2}NULL, Open.OplockLevel is {3}, Open.Lease.LeaseState is {4}",
                            createRequest.channel.Connection_NegotiateDialect, Open.IsPersistent,
                            Open.ConnectionIsNotNull ? " NOT " : " ", Open.OplockLevel, Open.Lease.LeaseState);

                        ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_NOT_AVAILABLE);
                        break;
                    }

                    Condition.IsTrue(Config == c);
                    Condition.IsTrue(Config.TreeConnect_Share_Type_Include_STYPE_CLUSTER_SOFS == c.TreeConnect_Share_Type_Include_STYPE_CLUSTER_SOFS);

                    if (Config.TreeConnect_Share_Type_Include_STYPE_CLUSTER_SOFS &&
                        createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelBatch)
                    {
                        // Replay will always use 3.x family
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9: If Connection.Dialect belongs to the SMB 3.x dialect family TreeConnect.Share.Type includes STYPE_CLUSTER_SOFS" +
                            " and the RequestedOplockLevel is SMB2_OPLOCK_LEVEL_BATCH, the server MUST set RequestedOplockLevel to SMB2_OPLOCK_LEVEL_II");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Connection.Dialect is {0}, TreeConnect.Share.Type includes STYPE_CLUSTER_SOFS and the RequestedOplockLevel is SMB2_OPLOCK_LEVEL_BATCH",
                            createRequest.channel.Connection_NegotiateDialect);

                        createRequest.requestedOplockLevel = ReplayModelRequestedOplockLevel.OplockLevelII;
                    }

                    #region Handle Lease 3.3.5.9.8 and 3.3.5.9.11

                    if (Open != null)
                    {
                        if (Open.Lease != null &&
                            (createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                             createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2) &&
                            createRequest.leaseKey == ReplayModelLeaseKey.DefaultLeaseKey &&
                            createRequest.fileName != ReplayModelFileName.DefaultFileName)
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.8: The server MUST attempt to locate a Lease by performing a lookup in the LeaseTable.LeaseList using the LeaseKey" +
                                " in the SMB2_CREATE_REQUEST_LEASE as the lookup key. If a lease is found but Lease.Filename does not match the file name for the incoming request," +
                                " the request MUST be failed with STATUS_INVALID_PARAMETER");
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.11: The server MUST attempt to locate a Lease by performing a lookup in the LeaseTable.LeaseList using the LeaseKey" +
                                " in the SMB2_CREATE_REQUEST_LEASE_V2 as the lookup key. If a lease is found but Lease.Filename does not match the file name for the incoming request," +
                                " the request MUST be failed with STATUS_INVALID_PARAMETER");

                            ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                            Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                            break;
                        }

                        // At this point, execution of create continues as described in 3.3.5.9 until the Oplock Acquisition phase.
                    }

                    #endregion

                    #region 3.3.5.9.10   Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context

                    if (createRequest.modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2 || 
                        createRequest.modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2Persistent)
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9.10: Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "createRequest.modelDurableHandle is {0}", createRequest.modelDurableHandle);

                        bool hasLeaseCreateContext =
                            (createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                            createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2);

                        ModelHelper.Log(
                            LogType.TestInfo,
                            "createRequest.requestedOplockLevel is {0}", createRequest.requestedOplockLevel);

                        if (createRequest.modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2 &&
                            createRequest.requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelBatch &&
                            !((createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                               createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2) &&
                              createRequest.leaseState == ReplayModelLeaseState.LeaseStateIncludeH))
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: If the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of this create context," +
                                " if RequestedOplockLevel in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH, and if the create request does not include" +
                                " a SMB2_CREATE_REQUEST_LEASE or SMB2_CREATE_REQUEST_LEASE_V2 create context with a LeaseState field that includes SMB2_LEASE_HANDLE_CACHING," +
                                " the server MUST ignore this create context and skip this section");
                            ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                            break;
                        }

                        // If ClientGuid is different, alternative channel cannot be create.
                        if (Open != null)
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: The server MUST locate the Open in GlobalOpenTable where Open.CreateGuid matches the CreateGuid in the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 create context," +
                                " and Open.ClientGuid matches the ClientGuid of the connection that received this request");

                            openIsFound = (createRequest.createGuid == ReplayModelCreateGuid.DefaultCreateGuid && Open.CreateGuidIsNotNull);

                            ModelHelper.Log(
                                LogType.TestInfo,
                                "Open is not NULL and Open could{0}be located", openIsFound ? " " : " not ");
                        }

                        if (!openIsFound)
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: If an Open is not found, the server MUST continue the create process specified in the \"Open Execution\" Phase, and perform the following additional steps:");
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: The server MUST set Open.CreateGuid to the CreateGuid in SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2.");

                            if (Open != null)
                            {
                                LastOpen = Open;
                            }

                            Open = new ReplayOpen();

                            ModelHelper.Log(
                                LogType.Requirement,
                                "In the \"Successful Open Initialization\" phase, the server MUST set Open.IsDurable to TRUE." +
                                " The server MUST also set Open.DurableOwner to a security descriptor accessible only by the user represented by Open.Session.SecurityContext.");

                            Open.IsDurable = true;

                            ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is set to TRUE");

                            if ( createRequest.modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2Persistent &&
                                createRequest.channel.Connection_Session_TreeConnect_Share_IsCA == ReplayModelShareType.CAShare &&
                                createRequest.channel.Connection_ClientCapabilities_SupportPersistent) // assume connection dialect always 3.x
                            {
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    " If the SMB2_DHANDLE_FLAG_PERSISTENT bit is set in the Flags field of the request, TreeConnect.Share.IsCA is TRUE, and Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_PERSISTENT_HANDLES," +
                                    " the server MUST set Open.IsPersistent to TRUE.");

                                Open.IsPersistent = true;

                                ModelHelper.Log(LogType.TestInfo, "Open.IsPersistent is set to {0}", Open.IsPersistent);
                            }

                            // 3.3.5.9.8   Handling the SMB2_CREATE_REQUEST_LEASE Create Context
                            // 3.3.5.9.11  Handling the SMB2_CREATE_REQUEST_LEASE_V2 Create Context
                            if (createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                                createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2)
                            {
                                ModelHelper.Log(
                                    LogType.TestInfo,
                                    "Requested OplockLevel is {0}, Open.leaseState is {1}", createRequest.requestedOplockLevel, createRequest.leaseState);

                                Open.Lease = new ReplayLease(createRequest.leaseState);
                            }
                        }
                        else // Open is found
                        {
                            if (createRequest.isSetReplayFlag == ReplayModelSetReplayFlag.WithoutReplayFlag)
                            {
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "3.3.5.9.10: If an Open is found and the SMB2_FLAGS_REPLAY_OPERATION bit is not set in the SMB2 header," +
                                    " the server MUST fail the request with STATUS_DUPLICATE_OBJECTID.");

                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "Open is found and SMB2_FLAGS_REPLAY_OPERATION bit is not set in the SMB2 header");

                                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                                Condition.IsTrue(status == ModelSmb2Status.STATUS_DUPLICATE_OBJECTID);
                                break;
                            }

                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: If an Open is found and the SMB2_FLAGS_REPLAY_OPERATION bit is set in the SMB2 header, the server MUST verify the following:");

                            if (!Open.IsDurable ||
                                (Open.Lease == null && hasLeaseCreateContext) || 
                                (Open.Lease != null && !hasLeaseCreateContext) || // Open is NOT NULL but request does not have lease context
                                (Open.Lease != null && hasLeaseCreateContext &&
                                 createRequest.leaseKey != ReplayModelLeaseKey.DefaultLeaseKey))
                            {
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "The server MUST fail the create request with STATUS_ACCESS_DENIED in the following cases:");
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "\tOpen.IsDurable is FALSE");
                                // "Open.DurableOwner is not the user represented by Open.Session.SecurityContext." not covered
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "\tIf Open.Lease is not NULL and Open.Lease.LeaseKey is not equal to the LeaseKey specified in the SMB2_CREATE_REQUEST_LEASE or SMB2_CREATE_REQUEST_LEASE_V2 Create Context");

                                if (!Open.IsDurable)
                                {
                                    ModelHelper.Log(
                                        LogType.TestInfo,
                                        "Open.IsDurable is FALSE");
                                }
                                else if (Open.Lease == null && hasLeaseCreateContext)
                                {
                                    ModelHelper.Log(
                                        LogType.TestInfo,
                                        "Open.Lease is NULL but request has lease context");
                                }
                                else if (Open.Lease != null && !hasLeaseCreateContext)
                                {
                                    ModelHelper.Log(
                                        LogType.TestInfo,
                                        "Open is NOT NULL but request does not have lease context");
                                }
                                else
                                {
                                    ModelHelper.Log(
                                        LogType.TestInfo,
                                        "If Open.Lease is not NULL and Open.Lease.LeaseKey is not equal to the LeaseKey specified in the request");
                                }

                                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                                break;
                            }

                            if (createRequest.fileAttributes != ReplayModelFileAttributes.DefaultFileAttributes)
                            {
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "If Open.FileAttributes does not match the FileAttributes field of the SMB2 CREATE request, the server MUST fail the request with STATUS_INVALID_PARAMETER.");

                                break;
                            }

                            if (createRequest.createDisposition != ReplayModelCreateDisposition.DefaultCreateDisposition)
                            {
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "If Open.CreateDisposition does not match the CreateDisposition field of the SMB2 CREATE request, the server MUST fail the request with STATUS_INVALID_PARAMETER");
                            }

                            if (Open.IsPersistent && createRequest.modelDurableHandle != ReplayModelDurableHandle.DurableHandleV2Persistent)
                            {
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "If Open.IsPersistent is TRUE and the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context, the server MUST fail the request with STATUS_INVALID_PARAMETER");
                            }
                        }

                        if (createRequest.modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2 &&
                            Open.OplockLevel != ReplayModelRequestedOplockLevel.OplockLevelBatch && (
                                !hasLeaseCreateContext || (
                                    hasLeaseCreateContext && (
                                        Open.Lease.LeaseState == ReplayModelLeaseState.LeaseStateIsNone ||
                                        Open.Lease.LeaseState == ReplayModelLeaseState.LeaseStateNotIncludeH
                                        )
                                    )
                                )
                            )
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: The server MUST skip the construction of the SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 create context if the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of the request and if neither of the following conditions are met:");
                            ModelHelper.Log(
                                LogType.Requirement,
                                "Open.OplockLevel is equal to SMB2_OPLOCK_LEVEL_BATCH");
                            ModelHelper.Log(
                                LogType.Requirement,
                                "Open.Lease.LeaseState has SMB2_LEASE_HANDLE_CACHING bit set");
                            // Handle normal open
                            break;
                        }

                        if (createRequest.modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2Persistent &&
                            createRequest.requestedOplockLevel != ReplayModelRequestedOplockLevel.OplockLevelBatch && (
                                !hasLeaseCreateContext || (
                                    hasLeaseCreateContext && (
                                        createRequest.leaseState == ReplayModelLeaseState.LeaseStateIsNone ||
                                        createRequest.leaseState == ReplayModelLeaseState.LeaseStateNotIncludeH
                                        )
                                    )
                                )
                            )
                        {
                            // Handle normal open
                            break;
                        }

                        #region Handle Lease

                        if (Open != null)
                        {
                            if ((createRequest.requestedOplockLevel ==
                                 ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                                 createRequest.requestedOplockLevel ==
                                 ReplayModelRequestedOplockLevel.OplockLevelLeaseV2) && Open.Lease != null &&
                                Open.Lease.LeaseState == ReplayModelLeaseState.LeaseStateNotIncludeH &&
                                createRequest.leaseState == ReplayModelLeaseState.LeaseStateIncludeH)
                            {
                                ModelHelper.Log(
                                    LogType.Requirement,
                                    "3.3.5.9.8 & 3.3.5.9.11: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE," +
                                    " the server MUST request promotion of the lease state from the underlying object store to the new caching state.");

                                ModelHelper.Log(
                                    LogType.TestInfo,
                                    "Assume that Lease.Breaking is FALSE as no lease break happens");

                                Open.Lease.LeaseState = ReplayModelLeaseState.LeaseStateIncludeH;

                                ModelHelper.Log(
                                    LogType.TestInfo,
                                    "Open.Lease.LeaseState is {0}", Open.Lease.LeaseState);
                            }
                        }

                        #endregion

                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9.10: The server MUST construct the create response from Open, as specified in the \"Response Construction\" phase," +
                            " with the following additional steps, and send the response to client");

                        if (createRequest.modelDurableHandle == ReplayModelDurableHandle.DurableHandleV2 &&
                            (Open.OplockLevel == ReplayModelRequestedOplockLevel.OplockLevelBatch ||
                             (Open.Lease != null && Open.Lease.LeaseState != ReplayModelLeaseState.LeaseStateIncludeH)))
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: The server MUST skip the construction of the SMB2_CREATE_DURABLE_HANDLE_RESPONSE_V2 create context " +
                                "if the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of the request and if neither of the following conditions are met:");
                            ModelHelper.Log(
                                LogType.Requirement,
                                "Open.OplockLevel is equal to SMB2_OPLOCK_LEVEL_BATCH");
                            ModelHelper.Log(
                                LogType.Requirement,
                                "Open.Lease.LeaseState has SMB2_LEASE_HANDLE_CACHING bit set");

                            Condition.IsTrue(durableHandleResponse == ReplayModelDurableHandle.NormalHandle);
                            break;
                        }

                        if (Open.IsPersistent)
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.10: If Open.IsPersistent is TRUE, the server MUST set the SMB2_DHANDLE_FLAG_PERSISTENT bit in the Flags field.");
                            ModelHelper.Log(
                                LogType.TestInfo,
                                "Open.IsPersistent is TRUE");

                            Condition.IsTrue(durableHandleResponse == ReplayModelDurableHandle.DurableHandleV2Persistent);
                            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                        }
                        else
                        {
                            ModelHelper.Log(
                                LogType.TestInfo,
                                "Open.IsPersistent is FALSE");

                            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                        }
                    }

                    #endregion

                } while (false);

                // Create an open
                if (status == ModelSmb2Status.STATUS_SUCCESS && Open == null)
                {
                    Open = new ReplayOpen();
                }

                if (createRequest.modelDurableHandle == ReplayModelDurableHandle.DurableHandleV1)
                {
                    if (!(createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelBatch ||
                          ((createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV1 ||
                            createRequest.requestedOplockLevel == ReplayModelRequestedOplockLevel.OplockLevelLeaseV2) && 
                           createRequest.leaseState == ReplayModelLeaseState.LeaseStateIncludeH)))
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.9.6: If the RequestedOplockLevel field in the create request is not set to SMB2_OPLOCK_LEVEL_BATCH" +
                            " and the create request does not include an SMB2_CREATE_REQUEST_LEASE create context with a LeaseState field" +
                            " that includes the SMB2_LEASE_HANDLE_CACHING bit value, the server MUST ignore this create context and skip this section");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "RequestedOplockLevel is {0}, LeaseState is {1}", createRequest.requestedOplockLevel,
                            createRequest.leaseState);

                        Condition.IsFalse(durableHandleResponse == ReplayModelDurableHandle.DurableHandleV1);
                    }
                    else
                    {
                        if (Open != null)
                        {
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.9.6 In the \"Successful Open Initialization\" phase, the server MUST set Open.IsDurable to TRUE.");

                            Open.IsDurable = true;

                            ModelHelper.Log(
                                LogType.TestInfo,
                                "Open.IsDurable is set to TRUE");
                        }
                    }
                }
            }

            // 3.3.4.1 Sending Any Outgoing Message
            PostCheckChannelSequence(ReplayModelRequestCommand.Create, createRequest.channel.Connection_NegotiateDialect,
                createRequest.channelSequence);

            Condition.IfThen(status != ModelSmb2Status.STATUS_SUCCESS, durableHandleResponse == ReplayModelDurableHandle.NormalHandle);
        }
        public static void CreateResponse(ModelSmb2Status status, ReturnLeaseContextType returnLeaseContextType, uint leaseState,
                                          LeaseFlagsValues leaseFlags, LeasingConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);

            ModelCreateLeaseRequest createRequest = ModelHelper.RetrieveOutstandingRequest <ModelCreateLeaseRequest>(ref request);

            Condition.IsTrue(config.IsDirectoryLeasingSupported == c.IsDirectoryLeasingSupported);
            Condition.IsTrue(config.IsLeasingSupported == c.IsLeasingSupported);

            if (!c.IsLeasingSupported)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server does not support leasing and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST ignore the \"RqLs\" create context.");
                ModelHelper.Log(LogType.TestInfo, "The above conditions are met.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextNotIncluded);
                return;
            }

            if ((negotiateDialect == DialectRevision.Smb21 || Smb2Utility.IsSmb3xFamily(negotiateDialect)) &&
                c.IsLeasingSupported &&
                (createRequest.ContextType == LeaseContextType.LeaseV1))    // the DataLength field equals 0x20
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server supports leasing, the name of the create context is \"RqLs\" as defined in section 2.2.13.2, " +
                    "and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:");
                ModelHelper.Log(
                    LogType.Requirement,
                    "\tIf Connection.Dialect is \"2.100\" or belongs to the \"3.x\" dialect family, and the DataLength field equals 0x20, " +
                    "the server MUST attempt to acquire a lease on the open from the underlying object store as described in section 3.3.5.9.8.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");

                // 3.3.5.9.8   Handling the SMB2_CREATE_REQUEST_LEASE Create Context
                #region Handle SMB2_CREATE_REQUEST_LEASE
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextIncluded);
                ModelCreateRequestLease requestLease = null;

                requestLease = createRequest.LeaseContext as ModelCreateRequestLease;

                smb2Lease = new Smb2Lease();
                if (Smb2Utility.IsSmb3xFamily(negotiateDialect))
                {
                    ModelHelper.Log(LogType.Requirement, "3.3.5.9.8: If Connection.Dialect belongs to the SMB 3.x dialect family, Lease.Version is set to 1.");
                    smb2Lease.Version = 1;
                }

                if (requestLease.LeaseState != smb2Lease.LeaseState && ((~requestLease.LeaseState) & smb2Lease.LeaseState) == 0 && !smb2Lease.Breaking)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.8: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE, " +
                        "the server MUST request promotion of the lease state from the underlying object store to the new caching state.");
                    ModelHelper.Log(LogType.TestInfo, "The above conditions are met.");
                    //If the object store succeeds this request, Lease.LeaseState MUST be set to the new caching state.
                    smb2Lease.LeaseState = requestLease.LeaseState;
                }

                // LeaseState MUST be set to Lease.LeaseState.
                Condition.IsTrue((uint)leaseState == smb2Lease.LeaseState);
                #endregion

                Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect) &&
                c.IsLeasingSupported &&
                (createRequest.ContextType == LeaseContextType.LeaseV2))    // the DataLength field equals 0x34
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server supports leasing, the name of the create context is \"RqLs\" as defined in section 2.2.13.2, " +
                    "and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:");
                ModelHelper.Log(
                    LogType.Requirement,
                    "\tIf Connection.Dialect belongs to the \"3.x\" dialect family, and the DataLength field equals 0x34, " +
                    "the server MUST attempt to acquire a lease on the open from the underlying object store, as described in section 3.3.5.9.11.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");

                // 3.3.5.9.11   Handling the SMB2_CREATE_REQUEST_LEASE_V2 Create Context
                #region Handle SMB2_CREATE_REQUEST_LEASE_V2
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextIncluded);
                ModelCreateRequestLeaseV2 requestLease = null;

                requestLease = createRequest.LeaseContext as ModelCreateRequestLeaseV2;

                smb2Lease = new Smb2Lease(2);

                // To reduce parameters and states, use CreateOptions instead of FileAttributes here, as we assume settings in CreateOptions and FileAtributes are consistent.
                if (createRequest.CreateOptions.HasFlag(CreateOptions_Values.FILE_DIRECTORY_FILE) &&
                    (requestLease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING) != 0)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.11: If the FileAttributes field in the request indicates that this operation is on a directory and " +
                        "LeaseState includes SMB2_LEASE_WRITE_CACHING, the server MUST clear the bit SMB2_LEASE_WRITE_CACHING in the LeaseState field.");
                    ModelHelper.Log(LogType.TestInfo, "SMB2_LEASE_WRITE_CACHING is cleared.");
                    requestLease.LeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING;
                }

                if (requestLease.LeaseState != smb2Lease.LeaseState && ((~requestLease.LeaseState) & smb2Lease.LeaseState) == 0 && !smb2Lease.Breaking)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.8: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE, " +
                        "the server MUST request promotion of the lease state from the underlying object store to the new caching state.<271> " +
                        "If the object store succeeds this request, Lease.LeaseState MUST be set to the new caching state.");
                    smb2Lease.LeaseState = requestLease.LeaseState;
                    // The server MUST increment Lease.Epoch by 1.
                    ModelHelper.Log(LogType.TestInfo, "Lease.Epoch is incremented by 1.");
                    smb2Lease.Epoch++;
                }

                // LeaseState MUST be set to Lease.LeaseState.
                Condition.IsTrue((uint)leaseState == smb2Lease.LeaseState);

                if (requestLease.LeaseFlags.HasFlag(LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET))
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.11: If SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit is set in the Flags field of the request, " +
                        "ParentLeaseKey MUST be set to the ParentLeaseKey in the request and SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit MUST be set in the Flags field of the response.");
                    ModelHelper.Log(LogType.TestInfo, "SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit is set.");
                    Condition.IsTrue(leaseFlags.HasFlag(LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET));
                }
                #endregion

                Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
                return;
            }

            Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextNotIncluded);
            Condition.IsTrue(leaseState == (uint)LeaseStateValues.SMB2_LEASE_NONE);
            Condition.IsTrue(leaseFlags == LeaseFlagsValues.NONE);
            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }
        public static void OplockBreakResponse(ModelSmb2Status status, OPLOCK_BREAK_Response_OplockLevel_Values oplockLevel, OplockLevel_Values oplockLevelOnOpen)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsNotNull(Request);

            ModelOplockBreakAcknowledgementRequest oplockBreakAckRequest = ModelHelper.RetrieveOutstandingRequest<ModelOplockBreakAcknowledgementRequest>(ref Request);

            ModelHelper.Log(LogType.Requirement,
                "3.3.5.22.1   Processing an Oplock Acknowledgment");

            if (!oplockBreakAckRequest.VolatilePortionFound
                || !oplockBreakAckRequest.PersistentMatchesDurableFileId)
            {
                ModelHelper.Log(LogType.Requirement,
                    "Next, the server MUST locate the open on which the client is acknowledging an oplock break by performing a lookup in Session.OpenTable " +
                    "using FileId.Volatile of the request as the lookup key. If no open is found, or if Open.DurableFileId is not equal to FileId.Persistent, " +
                    "the server MUST fail the request with STATUS_FILE_CLOSED. ");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);

                if (!oplockBreakAckRequest.VolatilePortionFound)
                {
                    ModelHelper.Log(LogType.TestInfo, "Open is not found.");
                }
                if (!oplockBreakAckRequest.PersistentMatchesDurableFileId)
                {
                    ModelHelper.Log(LogType.TestInfo, "Open.DurableFileId is not equal to FileId.Persistent.");
                }
                Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_CLOSED);
                return;
            }

            // We need this to avoid Open.OplockLevel being symbolic which will result case exploration failure
            Condition.IsTrue(Open.OplockLevel == oplockLevelOnOpen);
            Condition.IsTrue(oplockLevelOnOpen == OplockLevel_Values.OPLOCK_LEVEL_NONE
                || oplockLevelOnOpen == OplockLevel_Values.OPLOCK_LEVEL_II
                || oplockLevelOnOpen == OplockLevel_Values.OPLOCK_LEVEL_BATCH);

            if (oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_LEASE)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the OplockLevel in the acknowledgment is SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Open.OplockState is {0}.", Open.OplockState);

                if (Open.OplockState != OplockState.Breaking)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.OplockState is not Breaking, stop processing the acknowledgment, " +
                        "and send an error response with STATUS_INVALID_PARAMETER.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                    return;
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.OplockState is Breaking, complete the oplock break request received from the object store as described in section 3.3.4.6, " +
                        "with a new level SMB2_OPLOCK_LEVEL_NONE in an implementation-specific manner,<350> and set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE, " +
                        "and Open.OplockState to None.");
                    ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                    Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                    Open.OplockState = OplockState.None;

                    // Do not assert implementation-specific manner
                    return;
                }
            }

            if ((Open.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_EXCLUSIVE
                || Open.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_BATCH)
                && (oplockBreakAckRequest.OplockLevel != OplockLevel_Values.OPLOCK_LEVEL_II && oplockBreakAckRequest.OplockLevel != OplockLevel_Values.OPLOCK_LEVEL_NONE))
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Open.OplockLevel is SMB2_OPLOCK_LEVEL_EXCLUSIVE or SMB2_OPLOCK_LEVEL_BATCH, " +
                    "and if OplockLevel is not SMB2_OPLOCK_LEVEL_II or SMB2_OPLOCK_LEVEL_NONE, the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Open.OplockState is {0}.", Open.OplockState);

                if (Open.OplockState != OplockState.Breaking)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.OplockState is not Breaking, stop processing the acknowledgment, " +
                        "and send an error response with STATUS_INVALID_OPLOCK_PROTOCOL.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_OPLOCK_PROTOCOL);
                    return;
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.OplockState is Breaking, complete the oplock break request received from the object store, " +
                        "as described in section 3.3.4.6, with a new level SMB2_OPLOCK_LEVEL_NONE in an implementation-specific manner," +
                        "<351> and set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE and Open.OplockState to None.");
                    ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                    Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                    Open.OplockState = OplockState.None;

                    // Do not assert implementation-specific manner
                    return;
                }
            }

            if (Open.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_II
                && oplockBreakAckRequest.OplockLevel != OplockLevel_Values.OPLOCK_LEVEL_NONE)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If Open.OplockLevel is SMB2_OPLOCK_LEVEL_II, and if OplockLevel is not SMB2_OPLOCK_LEVEL_NONE, " +
                    "the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Open.OplockState is {0}.", Open.OplockState);

                if (Open.OplockState != OplockState.Breaking)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.OplockState is not Breaking, stop processing the acknowledgment, and send an error response with STATUS_INVALID_OPLOCK_PROTOCOL.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_OPLOCK_PROTOCOL);
                    return;
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.OplockState is Breaking, complete the oplock break request received from the object store, " +
                        "as described in section 3.3.4.6, with a new level SMB2_OPLOCK_LEVEL_NONE in an implementation-specific manner," +
                        "<352> and set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE and Open.OplockState to None.");
                    ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                    Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                    Open.OplockState = OplockState.None;

                    // Do not assert implementation-specific manner
                    return;
                }
            }

            if (oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_II
                || oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_NONE)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If OplockLevel is SMB2_OPLOCK_LEVEL_II or SMB2_OPLOCK_LEVEL_NONE, the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Open.OplockState is {0}.", Open.OplockState);

                if (Open.OplockState != OplockState.Breaking)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.OplockState is not Breaking, stop processing the acknowledgment, " +
                        "and send an error response with STATUS_INVALID_DEVICE_STATE.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_DEVICE_STATE);
                    return;
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.OplockState is Breaking, " +
                        "complete the oplock break request received from the object store as described in section 3.3.4.6, " +
                        "with a new level received in OplockLevel in an implementation-specific manner.<353>");

                    if (status != ModelSmb2Status.STATUS_SUCCESS)
                    {
                        ModelHelper.Log(LogType.Requirement,
                            "If the object store indicates an error, set the Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE, " +
                            "the Open.OplockState to None, and send the error response with the error code received.");
                        ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                        Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                        Open.OplockState = OplockState.None;
                        return;
                    }
                    else
                    {
                        ModelHelper.Log(LogType.Requirement,
                            "If the object store indicates success, update Open.OplockLevel and Open.OplockState as follows:");
                        if (oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_II)
                        {
                            ModelHelper.Log(LogType.Requirement,
                                "If OplockLevel is SMB2_OPLOCK_LEVEL_II, " +
                                "set Open.OplockLevel to SMB2_OPLOCK_LEVEL_II and Open.OplockState to Held.");
                            ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to OPLOCK_LEVEL_II, and Open.OplockState is set to None");
                            Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_II;
                            Open.OplockState = OplockState.Held;
                        }
                        if (oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_NONE)
                        {
                            ModelHelper.Log(LogType.Requirement,
                                "If OplockLevel is SMB2_OPLOCK_LEVEL_NONE, " +
                                "set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE and the Open.OplockState to None.");
                            ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                            Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                            Open.OplockState = OplockState.None;
                        }
                    }
                }
            }

            ModelHelper.Log(LogType.Requirement,
                "The server then MUST construct an oplock break response using the syntax specified in section 2.2.25 with the following value:");
            ModelHelper.Log(LogType.Requirement,
                "OplockLevel MUST be set to Open.OplockLevel.");
            ModelHelper.Log(LogType.TestInfo,
                "Open.OplockLevel is {0}.", Open.OplockLevel);

            Condition.IsTrue(Open.OplockLevel == (OplockLevel_Values)oplockLevel);

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
 /// <summary>
 /// The server MUST sign the message under the following conditions
 /// </summary>
 private static void VerifyResponseShouldSign(
     ModelSmb2Status status,
     SigningModelRequest request,
     SigningModelSessionId sessionId,
     SigningFlagType signingFlagType)
 {
     if (request.signingFlagType == SigningFlagType.SignedFlagSet
         && sessionId == SigningModelSessionId.NonZeroSessionId
         && Session_SigningRequired)
     {
         ModelHelper.Log(LogType.Requirement, "3.3.4.1.1: The server SHOULD<182> sign the message under the following conditions:");
         ModelHelper.Log(LogType.Requirement,
             "\tIf the request was signed by the client, the response message being sent contains a nonzero SessionId and a zero TreeId in the SMB2 header, " +
             "and the session identified by SessionId has Session.SigningRequired equal to TRUE.");
         ModelHelper.Log(LogType.TestInfo, "The condition is met.");
         Condition.IsTrue(signingFlagType == SigningFlagType.SignedFlagSet);
     }
     else if (request.signingFlagType == SigningFlagType.SignedFlagSet)
     {
         ModelHelper.Log(LogType.Requirement, "3.3.4.1.1: The server SHOULD<182> sign the message under the following conditions:");
         ModelHelper.Log(LogType.Requirement,
             "\tIf the request was signed by the client, and the response is not an interim response to an asynchronously processed request.");
         ModelHelper.Log(LogType.TestInfo, "The condition is met.");
         Condition.IsTrue(signingFlagType == SigningFlagType.SignedFlagSet);
     }
 }
        /// <summary>
        /// Cover section 3.3.5.2.4
        /// </summary>
        private static bool VerifySignature(ModelSmb2Status status, SigningModelRequest request)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.2.4: Verifying the Signature");
            if (request.signingFlagType == SigningFlagType.SignedFlagSet)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the SMB2 header of the request has SMB2_FLAGS_SIGNED set in the Flags field, the server MUST verify the signature. ");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_SIGNED is set in SMB2 header.");

                if (!Session_IsExisted)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "For all other requests, the server MUST look up the session in the Connection.SessionTable using the SessionId in the SMB2 header of the request. " +
                        "If the session is not found, the request MUST be failed, as specified in section Sending an Error Response (section 3.3.4.4), " +
                        "with the error code STATUS_USER_SESSION_DELETED.");
                    ModelHelper.Log(LogType.TestInfo, "The session is not found.");
                    ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                    return false;
                }
            }

            if (request.signingFlagType == SigningFlagType.SignedFlagNotSet)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the SMB2 header of the request does not have SMB2_FLAGS_SIGNED set in the Flags field, " +
                    "the server MUST determine if the client failed to sign a packet that required it. " +
                    "The server MUST look up the session in the GlobalSessionTable using the SessionId in the SMB2 header of the request.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_SIGNED is not set in the SMB2 header.");

                if (Session_IsExisted && Session_SigningRequired)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If the session is found and Session.SigningRequired is equal to TRUE, the server MUST fail this request with STATUS_ACCESS_DENIED. ");
                    ModelHelper.Log(LogType.TestInfo, "The session is found and Session.SigningRequired is TRUE.");
                    ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                    return false;
                }
            }

            return true;
        }
        public static void SessionSetupResponse(
            ModelSmb2Status status,
            SigningModelSessionId sessionId,
            SigningFlagType signingFlagType,
            SessionFlags_Values sessionFlag,
            SigningConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsTrue(Config.IsServerSigningRequired == c.IsServerSigningRequired);

            SigningModelRequest sessionSetupRequest = ModelHelper.RetrieveOutstandingRequest<SigningModelRequest>(ref Request);

            if (!VerifySignature(status, sessionSetupRequest))
            {
                State = ModelState.Uninitialized;
                return;
            }

            if (sessionSetupRequest.signingFlagType == SigningFlagType.SignedFlagSet
                || (!sessionFlag.HasFlag(SessionFlags_Values.SESSION_FLAG_IS_GUEST)
                    && !Session_IsAnonymous
                    && (Connection_ShouldSign || c.IsServerSigningRequired)))
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.5.3: 5. Session.SigningRequired MUST be set to TRUE under the following conditions:");
                ModelHelper.Log(LogType.Requirement,
                    "\tIf the SMB2_NEGOTIATE_SIGNING_REQUIRED bit is set in the SecurityMode field of the client request.");
                ModelHelper.Log(LogType.Requirement,
                    "\tIf the SMB2_SESSION_FLAG_IS_GUEST bit is not set in the SessionFlags field " +
                    "and Session.IsAnonymous is FALSE and either Connection.ShouldSign or global RequireMessageSigning is TRUE.");

                ModelHelper.Log(LogType.TestInfo,
                    "SMB2_NEGOTIATE_SIGNING_REQUIRED is {0}set.", sessionSetupRequest.signingFlagType == SigningFlagType.SignedFlagSet ? "" : "not ");
                ModelHelper.Log(LogType.TestInfo,
                    "SMB2_SESSION_FLAG_IS_GUEST bit is {0}set.", sessionFlag.HasFlag(SessionFlags_Values.SESSION_FLAG_IS_GUEST) ? "" : "not ");
                ModelHelper.Log(LogType.TestInfo, "Session.IsAnonymous is {0}.", Session_IsAnonymous);
                ModelHelper.Log(LogType.TestInfo, "Connection.ShouldSign is {0}.", Connection_ShouldSign);
                ModelHelper.Log(LogType.TestInfo, "Global RequireMessageSigning is {0}.", c.IsServerSigningRequired);
                ModelHelper.Log(LogType.TestInfo, "So Session.SigningRequired is set to TRUE.");

                Session_SigningRequired = true;
            }

            VerifyResponseShouldSign(status, sessionSetupRequest, sessionId, signingFlagType);

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);

            Session_IsExisted = true;
        }
        private static bool VerifySession(ModelSmb2Status status, ModelRequestType modelRequestType)
        {
            if (Smb2Utility.IsSmb3xFamily(negotiateDialect)
                && Session_EncryptData == SessionEncryptDataType.SessionEncryptDataSet
                && config.IsGlobalRejectUnencryptedAccessEnabled
                && modelRequestType == ModelRequestType.UnEncryptedRequest)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.2.9: If Connection.Dialect belongs to the SMB 3.x dialect family, Session.EncryptData is TRUE, " +
                    "and RejectUnencryptedAccess is TRUE, the server MUST locate the Request in Connection.RequestList " +
                    "for which Request.MessageId matches the MessageId value in the SMB2 header of the request. " +
                    "If Request.IsEncrypted is FALSE, the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return false;
            }

            return true;
        }
        public static void TreeConnectResponse(ModelSmb2Status status, ShareType_Values shareType, TreeMgmtServerConfig config)
        {
            Condition.IsTrue(Config.Platform == config.Platform);
            Condition.IsTrue(State == ModelState.Connected);

            ModelTreeMgmtTreeConnectRequest treeConnectRequest = ModelHelper.RetrieveOutstandingRequest<ModelTreeMgmtTreeConnectRequest>(ref Request);

            if (treeConnectRequest.sharePath == ModelSharePath.InvalidSharePath )
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.7: Otherwise, the server MUST provide the tuple <hostname, sharename> parsed from the request message to invoke the event specified in [MS-SRVS] section 3.1.6.8," +
                    " to normalize the hostname by resolving server aliases and evaluating share scope. The server MUST use <normalized hostname, sharename> to look up the Share in ShareList." +
                    " If no share with a matching share name and server name is found, the server MUST fail the request with STATUS_BAD_NETWORK_NAME");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "Share path is an invalid share path");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_BAD_NETWORK_NAME);
                return;
            }

            // Only cover Windows behavior (SHOULD behavior) in one condition when the share is "IPC$" or has STYPE_SPECIAL bit set
            // Other cases for 3.3.5.7 statement below are not covered
            // Assume NonWindows will have same behvior regarding to 3.3.4.13 statement
            if (Session_SecurityContext == ModelSessionSecurityContext.NonAdmin
                && treeConnectRequest.sharePath == ModelSharePath.SpecialSharePath)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.7: The server MUST determine whether the user represented by Session.SecurityContext should be granted access based on the authorization policy specified in Share.ConnectSecurity." +
                    " If the server determines that access should not be granted, the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.4.13: If Share.Name is equal to \"IPC$\" or Share.Type does not have the STYPE_SPECIAL bit set," +
                    " then Share.ConnectSecurity SHOULD be set to a security descriptor allowing all users." +
                    " Otherwise, Share.ConnectSecurity SHOULD be set to a security descriptor allowing only administrators.");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "User authenticated the session is a NonAdmin, and share in the TreeConnect request has STYPE_SPECIAL bit set");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);

            if (treeConnectRequest.sharePath != ModelSharePath.SpecialSharePath)
            {
                // only check on Basic Share, Share with Special Bit can be any Type of Share
                // currently, only DISK ShareType in FileSharing Family test suite
                // it's not TD requirement but assumption
                Condition.IsTrue(shareType == ShareType_Values.SHARE_TYPE_DISK);
            }

            Session_TreeConnectExist = true;
        }
        public static void ConflictResponse(ModelSmb2Status status, LeaseBreakState leaseBreakState)
        {
            switch (State)
            {
            case FileState.Initial:
                ModelHelper.Log(LogType.TestInfo, "The state of the file is not changed. So any request from the second client should succeed.");
                Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                break;

            case FileState.Locked:
                switch (SecondRequest)
                {
                case RequestType.ExclusiveLock:
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.14.2: If the range being locked is already locked by another open in a way " +
                        "that does not allow this open to take a lock on the range, and if SMB2_LOCKFLAG_FAIL_IMMEDIATELY is set, " +
                        "the server MUST fail the request with STATUS_LOCK_NOT_GRANTED.");
                    ModelHelper.Log(LogType.TestInfo, "The file is already locked and SMB2_LOCKFLAG_FAIL_IMMEDIATELY is set.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_LOCK_NOT_GRANTED);
                    break;

                case RequestType.Lease:
                    ModelHelper.Log(LogType.TestInfo, "Lease succeed even the file is locked.");
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                    break;

                case RequestType.Delete:
                    ModelHelper.Log(LogType.TestInfo, "Delete succeed even the file is locked.");
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                    break;

                case RequestType.Write:
                    ModelHelper.Log(LogType.TestInfo, "Write fails because the file is locked.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_LOCK_CONFLICT);
                    break;

                case RequestType.Read:
                    ModelHelper.Log(LogType.TestInfo, "Read fails because the file is locked.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_LOCK_CONFLICT);
                    break;

                default:
                    break;
                }
                break;

            case FileState.LeaseGranted:
                ModelHelper.Log(
                    LogType.TestInfo,
                    "A lease to this file is granted to the first open, but it will not fail the operation from the second client");
                Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                break;

            case FileState.ToBeDeleted:
                ModelHelper.Log(LogType.TestInfo, "The file is not deleted, and it will be deleted only if the second open is closed.");
                ModelHelper.Log(LogType.TestInfo, "So the other operation ahead of Close request from the second client will succeed.");
                Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                break;

            case FileState.Deleted:
                ModelHelper.Log(LogType.TestInfo, "The file is deleted, so any operation to the non-existed file fails.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                break;

            default:
                break;
            }

            if (State == FileState.LeaseGranted &&
                (SecondRequest == RequestType.Write || SecondRequest == RequestType.ExclusiveLock))
            {
                ModelHelper.Log(LogType.TestInfo, "A lease to this file is granted to the first open. ");
                ModelHelper.Log(LogType.TestInfo, "The {0} request from second client should break the lease state.", SecondRequest);
                Condition.IsTrue(leaseBreakState == LeaseBreakState.LeaseBreakExisted);
            }
            else
            {
                if (State == FileState.LeaseGranted)
                {
                    ModelHelper.Log(
                        LogType.TestInfo,
                        "A lease is granted to the first open, but the {0} request from the second client cannot break the state.", SecondRequest);
                }
                else
                {
                    ModelHelper.Log(LogType.TestInfo, "No lease is granted to the first open, so no lease break.");
                }
                Condition.IsTrue(leaseBreakState == LeaseBreakState.NoLeaseBreak);
            }
        }
        public static void LeaseBreakResponse(ModelSmb2Status status, uint leaseState)
        {
            Condition.IsTrue(state == ModelState.Connected);
            Condition.IsTrue(request is ModelLeaseBreakAckRequest);

            ModelLeaseBreakAckRequest leaseBreakAckRequest = ModelHelper.RetrieveOutstandingRequest<ModelLeaseBreakAckRequest>(ref request);

            ModelHelper.Log(
                LogType.Requirement,
                "The server MUST locate the lease on which the client is acknowledging a lease break by performing a lookup in LeaseTable.LeaseList " +
                "using the LeaseKey of the request as the lookup key.");
            if ((leaseBreakAckRequest.modelLeaseKeyType == ModelLeaseKeyType.InvalidLeaseKey) || smb2Lease == null)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "If no lease is found, the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                ModelHelper.Log(LogType.TestInfo, "The lease is not found.");

                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return;
            }

            if (!smb2Lease.Breaking)
            {
                ModelHelper.Log(LogType.Requirement, "If Lease.Breaking is FALSE, the server MUST fail the request with STATUS_UNSUCCESSFUL.");
                ModelHelper.Log(LogType.TestInfo, "Lease.Breaking is FALSE");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_UNSUCCESSFUL);
                return;
            }

            if (!(leaseBreakAckRequest.LeaseState <= smb2Lease.BreakToLeaseState))
            {
                ModelHelper.Log(LogType.Requirement,
                    "If LeaseState is not <= Lease.BreakToLeaseState, the server MUST fail the request with STATUS_REQUEST_NOT_ACCEPTED.");
                ModelHelper.Log(LogType.TestInfo, "LeaseState is not <= Lease.BreakToLeaseState.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_REQUEST_NOT_ACCEPTED);
                return;
            }

            ModelHelper.Log(LogType.Requirement,
                "The server MUST set Lease.LeaseState to LeaseState received in the request, and MUST set Lease.Breaking to FALSE.");
            smb2Lease.Breaking = false;
            smb2Lease.LeaseState = leaseState;

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);

            ModelHelper.Log(LogType.Requirement,
                "The server then MUST construct a lease break response using the syntax specified in section 2.2.25 with the following values:");
            ModelHelper.Log(LogType.Requirement, "\tLeaseState MUST be set to Lease.LeaseState.");
            Condition.IsTrue(leaseState == leaseBreakAckRequest.LeaseState);
        }
        public static void OpenResponse(
            ModelSmb2Status status,
            DurableHandleResponseContext durableHandleResponseContext,
            LeaseResponseContext leaseResponseContext,
            HandleConfig c)
        {
            Condition.IsNotNull(Request);

            ModelOpenFileRequest modelOpenFileRequest = ModelHelper.RetrieveOutstandingRequest<ModelOpenFileRequest>(ref Request);

            if (ModelUtility.IsSmb3xFamily(NegotiateDialect)
                && modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextNotExist
                && modelOpenFileRequest.durableV2ReconnectContext == DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.9: If Connection.Dialect belongs to the SMB 3.x dialect family and " +
                    "the request does not contain SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context or SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context, " +
                    "the server MUST look up an existing open in the GlobalOpenTable where Open.FileName matches the file name in the Buffer field of the request. ");
                ModelHelper.Log(LogType.TestInfo,
                    "Connection.Dialect is {0} and the request does not contain SMB2_CREATE_DURABLE_HANDLE_RECONNECT or SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context.",
                    NegotiateDialect);

                if (Open != null
                    && !modelOpenFileRequest.isSameClient
                    && Open.IsPersistent
                    && !Open.IsConnectionExisted
                    && !Open.IsBatchOplockExisted
                    && !Open.IsLeaseExisted)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If an Open entry is found, and if all the following conditions are satisfied, " +
                        "the server MUST fail the request with STATUS_FILE_NOT_AVAILABLE.");
                    ModelHelper.Log(LogType.Requirement, "\tOpen.IsPersistent is TRUE");
                    ModelHelper.Log(LogType.Requirement, "\tOpen.Connection is NULL");
                    ModelHelper.Log(LogType.Requirement, "\tOpen.OplockLevel is not equal to SMB2_OPLOCK_LEVEL_BATCH");
                    ModelHelper.Log(LogType.Requirement, "\tOpen.OplockLevel is not equal to SMB2_OPLOCK_LEVEL_LEASE or Open.Lease.LeaseState does not include SMB2_LEASE_HANDLE_CACHING");

                    ModelHelper.Log(LogType.TestInfo, "The Open is found, and all the conditions are satisfied.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                    Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_NOT_AVAILABLE);
                    return;
                }
            }

            // TD section 3.3.5.9.6: Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST Create Context
            if (modelOpenFileRequest.durableV1RequestContext == DurableV1RequestContext.DurableV1RequestContextExist)
            {
                if (Handling_SMB2_CREATE_DURABLE_HANDLE_REQUEST_CreateContext(status, modelOpenFileRequest, durableHandleResponseContext, c))
                    return;
            }

            // TD section 3.3.5.9.7: Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT Create Context
            if (modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextExist)
            {
                if (Handling_SMB2_CREATE_DURABLE_HANDLE_RECONNECT_CreateContext(status, modelOpenFileRequest, leaseResponseContext, c))
                    return;
            }

            // TD section 3.3.5.9.10: Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context
            if (modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextNotExist)
            {
                if (Handling_SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2_CreateContext(status, modelOpenFileRequest, durableHandleResponseContext))
                    return;
            }

            // TD section 3.3.5.9.12: Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context
            if (modelOpenFileRequest.durableV2ReconnectContext != DurableV2ReconnectContext.DurableV2ReconnectContextNotExist)
            {
                if (Handling_SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2_CreateContext(status, modelOpenFileRequest, leaseResponseContext, c))
                    return;
            }

            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }
        public static void ValidateNegotiateInfoResponse(ModelSmb2Status status, ValidateNegotiateInfoConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsTrue(IsSameWithNegotiate);
            Condition.IsTrue(Config.Platform == c.Platform);

            State = ModelState.Disconnected;

            if (Config.ValidateNegotiateInfoSupported == ValidateNegotiateInfoInServer.SupportValidateNegotiateInfo)
            {
                ModelHelper.Log(
                    LogType.TestInfo,
                    "FSCTL_VALIDATE_NEGOTIATE_INFO is allowed on the server");

                Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                return;
            }

            ModelHelper.Log(
                LogType.TestInfo,
                "FSCTL_VALIDATE_NEGOTIATE_INFO is not allowed on the server");

            if (Config.Platform != Platform.NonWindows)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.15: The server SHOULD<299> fail the request with STATUS_NOT_SUPPORTED when an FSCTL is not allowed on the server");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "SUT platform is {0}, so follow the SHOULD requirement", Config.Platform);
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_NOT_SUPPORTED);
            }
            else
            {
                ModelHelper.Log(
                    LogType.TestInfo,
                    "SUT platform is {0}, so only assert status is not equal to STATUS_SUCCESS", Config.Platform);

                Condition.IsFalse(status == ModelSmb2Status.STATUS_SUCCESS);
            }
        }
        /// <summary>
        /// This method is used to verify the SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context
        /// Cover TD section 3.3.5.9.12
        /// Return true means the message is handled by this function. 
        /// Return false means the message needs further processing.        
        /// </summary>
        private static bool Handling_SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2_CreateContext(
            ModelSmb2Status status,
            ModelOpenFileRequest modelOpenFileRequest,
            LeaseResponseContext leaseResponseContext,
            HandleConfig c)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.9.12: Handling the SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context");

            if (modelOpenFileRequest.durableV1RequestContext == DurableV1RequestContext.DurableV1RequestContextExist
                || modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextExist
                || modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextNotExist)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the create request also contains SMB2_CREATE_DURABLE_HANDLE_REQUEST context or SMB2_CREATE_DURABLE_HANDLE_RECONNECT context or " +
                    "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 context, the server MUST fail the request with STATUS_INVALID_PARAMETER.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedContext);

                if (modelOpenFileRequest.durableV1RequestContext == DurableV1RequestContext.DurableV1RequestContextExist)
                {
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_REQUEST is included.");
                }
                if (modelOpenFileRequest.durableV1ReconnectContext == DurableV1ReconnectContext.DurableV1ReconnectContextExist)
                {
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_RECONNECT is included.");
                }
                if (modelOpenFileRequest.durableV2RequestContext != DurableV2RequestContext.DurableV2RequestContextNotExist)
                {
                    ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 is included.");
                }
                Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                return true;
            }

            ModelHelper.Log(LogType.Requirement,
                "The server MUST look up an existing open in the GlobalOpenTable by doing a lookup with the FileId.Persistent portion of the create context.");
            ModelHelper.Log(LogType.TestInfo, "Open {0}.", Open != null ? "exists" : "does not exist");

            Condition.IsTrue(Config.Platform == c.Platform);

            if (Open == null)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If the lookup fails, the server SHOULD<276> fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);

                if (Config.Platform == Platform.NonWindows)
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is NonWindows, so the server could fail the request with other error code.");
                    Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                }
                else if (Config.Platform == Platform.WindowsServer2012
                    && modelOpenFileRequest.durableV2ReconnectContext == DurableV2ReconnectContext.DurableV2ReconnectContextExistWithPersistent)
                {
                    // Windows 2012 fails the request, but the error code is not a fixed one.
                    Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                }
                else
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}.", Config.Platform);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                }

                return true;
            }
            else
            {
                // Workaround to resolve SE bug
                Condition.IsTrue(Config.IsLeasingSupported == c.IsLeasingSupported);
                Condition.IsTrue(Config.IsDirectoryLeasingSupported == c.IsDirectoryLeasingSupported);

                if (Open.IsLeaseExisted && !modelOpenFileRequest.isSameClient)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.Lease is not NULL and Open.ClientGuid is not equal to the ClientGuid of the connection that received this request, " +
                        "the server MUST fail the create request with STATUS_OBJECT_NAME_NOT_FOUND.");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                    ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    return true;
                }

                // TDI 72308
                if (Open.IsPersistent && modelOpenFileRequest.durableV2ReconnectContext == DurableV2ReconnectContext.DurableV2ReconnectContextExistWithoutPersistent)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.IsPersistent is TRUE and the SMB2_DHANDLE_FLAG_PERSISTENT bit is not set in the Flags field of the SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 Create Context, " +
                        "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                    ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    return true;
                }

                if (!modelOpenFileRequest.isSameCreateGuid)
                {
                    if (Config.Platform == Platform.WindowsServer2012
                        && modelOpenFileRequest.durableV2ReconnectContext == DurableV2ReconnectContext.DurableV2ReconnectContextExistWithPersistent)
                    {
                        // Windows 2012 fails the request, but the error code is not a fixed one.
                        Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                    }
                    else
                    {
                        ModelHelper.Log(LogType.Requirement,
                            "If Open.CreateGuid is not equal to the CreateGuid in the request, the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                        ModelHelper.Log(LogType.TestInfo, "Open.CreateGuid is not equal to the CreateGuid in the request.");
                        ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    }
                    return true;
                }

                if (!Open.IsDurable)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.IsDurable is FALSE and Open.IsResilient is FALSE or unimplemented, " +
                        "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                    ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is FALSE and Open.IsResilient is FALSE.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    return true;
                }

                // TDI, if Open.IsPersistent is true, then when reconnecting, if Open.Session is not NULL, the reconnect can still succeed.
                if (!Open.IsPersistent && Open.IsSessionExisted)
                {
                    ModelHelper.Log(LogType.Requirement, "If Open.Session is not NULL, the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND. ");
                    ModelHelper.Log(LogType.TestInfo, "Open.Session is not NULL.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    return true;
                }

                if ((!Open.IsLeaseExisted
                        && (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1
                            || modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV2))
                    || (Open.IsLeaseExisted
                        && modelOpenFileRequest.oplockLeaseType != OplockLeaseType.LeaseV1
                        && modelOpenFileRequest.oplockLeaseType != OplockLeaseType.LeaseV2))
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If Open.Lease is NULL and the SMB2_CREATE_REQUEST_LEASE or SMB2_CREATE_REQUEST_LEASE_V2 create context is present, " +
                        "or if Open.Lease is NOT NULL and the SMB2_CREATE_REQUEST_LEASE or SMB2_CREATE_REQUEST_LEASE_V2 create context is not present, " +
                        "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND.");
                    ModelHelper.Log(LogType.TestInfo, "Open.Lease is{0} NULL.", Open.IsLeaseExisted ? " not" : "");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    if (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1)
                    {
                        ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_REQUEST_LEASE is present.");
                    }
                    else if (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV2)
                    {
                        ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_REQUEST_LEASE_V2 is present.");
                    }
                    else
                    {
                        ModelHelper.Log(LogType.TestInfo, "SMB2_CREATE_REQUEST_LEASE or SMB2_CREATE_REQUEST_LEASE_V2 create context is not present.");
                    }
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    return true;
                }

                if (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV2
                    && Config.IsDirectoryLeasingSupported
                    && Open.IsLeaseExisted
                    && !modelOpenFileRequest.isSameLeaseKey)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If an SMB2_CREATE_REQUEST_LEASE_V2 create context is also present in the request, " +
                        "the server supports directory leasing, and Open.Lease.LeaseKey does not match the LeaseKey provided in the SMB2_CREATE_REQUEST_LEASE_V2 create context, " +
                        "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    return true;
                }

                if (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1
                    && Config.IsLeasingSupported
                    && Open.IsLeaseExisted
                    && !modelOpenFileRequest.isSameLeaseKey)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If an SMB2_CREATE_REQUEST_LEASE create context is also present in the request, the server supports leasing, " +
                        "and Open.Lease.LeaseKey does not match the LeaseKey provided in the SMB2_CREATE_REQUEST_LEASE create context, " +
                        "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");
                    ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    return true;
                }

                ModelHelper.Log(LogType.Requirement, "In the \"Response Construction\" phase:");

                // TDI 71165
                if (Config.IsDirectoryLeasingSupported
                    && modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV2)
                {
                    ModelHelper.Log(LogType.Requirement, "If the server supports directory leasing, and the request contains SMB2_CREATE_REQUEST_LEASE_V2 Create Context, " +
                        "then the server MUST construct an SMB2_CREATE_RESPONSE_LEASE_V2 Create Context");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. So create response should contain an SMB2_CREATE_RESPONSE_LEASE_V2 Create Context.");
                    if (Open.LeaseVersion == 1)
                        Condition.IsTrue(leaseResponseContext == LeaseResponseContext.SMB2_CREATE_RESPONSE_LEASE);
                    else if (Open.LeaseVersion == 2)
                        Condition.IsTrue(leaseResponseContext == LeaseResponseContext.SMB2_CREATE_RESPONSE_LEASE_V2);
                }

                // TDI 71165
                if (modelOpenFileRequest.oplockLeaseType == OplockLeaseType.LeaseV1
                    && Config.IsLeasingSupported
                    && Open.IsLeaseExisted)
                {
                    ModelHelper.Log(LogType.Requirement,
                        "If the request contains an SMB2_CREATE_REQUEST_LEASE Create Context, " +
                        "the server supports leasing and Open.Lease is not NULL, then the server MUST construct an SMB2_CREATE_RESPONSE_LEASE create context");
                    ModelHelper.Log(LogType.TestInfo, "All the above conditions are met. So create response should contain an SMB2_CREATE_RESPONSE_LEASE Create Context.");

                    if (Open.LeaseVersion == 1)
                        Condition.IsTrue(leaseResponseContext == LeaseResponseContext.SMB2_CREATE_RESPONSE_LEASE);
                    else if (Open.LeaseVersion == 2)
                        Condition.IsTrue(leaseResponseContext == LeaseResponseContext.SMB2_CREATE_RESPONSE_LEASE_V2);
                }
            }

            return false;
        }
        public static void CreditOperationResponse(ModelSmb2Status status, uint creditResponse, CreditMgmtConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);

            Condition.IsTrue(c.Platform == config.Platform);

            ModelCreditOperationRequest creditOperationRequest = ModelHelper.RetrieveOutstandingRequest<ModelCreditOperationRequest>(ref request);

            if (config.Platform != Platform.NonWindows)
            {
                if (creditOperationRequest.creditRequestNum == ModelCreditRequestNum.CreditRequestSetNonZero)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.1.2: The server SHOULD<151> grant the client a non-zero value of credits in response to any non-zero value requested");
                    ModelHelper.Log(
                        LogType.TestInfo,
                        "Platform is {0}", config.Platform);

                    Condition.IsTrue(creditResponse != 0);
                }
            }

            if (creditOperationRequest.midType == ModelMidType.UsedMid
                || creditOperationRequest.midType == ModelMidType.UnavailableMid
                || (isMultiCreditSupported && creditOperationRequest.creditCharge == ModelCreditCharge.CreditChargeExceedBoundary))
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.2.3: If the server determines that the MessageId or the range of MessageIds for the incoming request is not valid," +
                    " the server SHOULD<202> terminate the connection. Otherwise, the server MUST remove the MessageId or the range of MessageIds from the Connection.CommandSequenceWindow.");

                if (creditOperationRequest.midType == ModelMidType.UsedMid || creditOperationRequest.midType == ModelMidType.UnavailableMid)
                {
                    ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                }

                if (isMultiCreditSupported && creditOperationRequest.creditCharge == ModelCreditCharge.CreditChargeExceedBoundary)
                {
                    ModelHelper.Log(LogType.TestTag, TestTag.OutOfBoundary);
                }

                //Only NonWindows would run into this case when not following the SHOULD requirement
                Condition.IsTrue(config.Platform == Platform.NonWindows);
                Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                acceptingCondition = true;

                return;
            }

            if (isMultiCreditSupported)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.2.5: If Connection.SupportsMultiCredit is TRUE," +
                    " the server MUST verify the CreditCharge field in the SMB2 header and the payload size (the size of the data within the variable-length field) of the request or the maximum response size");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "Connection.SupportsMultiCredit is TRUE");

                if (creditOperationRequest.creditCharge == ModelCreditCharge.CreditChargeSetZero)
                {
                    //NOTE: When multi-credit request is not supported or credit charge = 0
                    //     Treat PayloadSize > 64K if use "LargerThanCreditCharge"
                    if (creditOperationRequest.payloadSize == ModelPayloadSize.PayloadSizeLargerThanBoundary)
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "If CreditCharge is zero and the payload size of the request or the maximum response size is greater than 64 kilobytes," +
                            " the server MUST fail the request with the error code STATUS_INVALID_PARAMETER.");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Credit charge type in request is {0}, payload size type is {1}",
                            creditOperationRequest.creditCharge, creditOperationRequest.payloadSize);

                        ModelHelper.Log(LogType.TestTag, TestTag.OutOfBoundary);

                        Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                        acceptingCondition = true; //Reaching an accepting condition of exploration
                        return;
                    }
                }
                else
                {
                    if (creditOperationRequest.payloadSize == ModelPayloadSize.PayloadSizeLargerThanBoundary)
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "If CreditCharge is greater than zero, the server MUST calculate the expected CreditCharge for the current operation using the formula specified in section 3.1.5.2." +
                            " If the calculated credit number is greater than the CreditCharge, the server MUST fail the request with the error code STATUS_INVALID_PARAMETER.");
                        ModelHelper.Log(
                            LogType.TestInfo,
                            "Credit charge type in request is {0}, payload size type is {1}," +
                            " that's calculated credit number based on payload size is greater than the CreditCharge",
                            creditOperationRequest.creditCharge, creditOperationRequest.payloadSize);

                        ModelHelper.Log(LogType.TestTag, TestTag.OutOfBoundary);

                        Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                        acceptingCondition = true; //Reaching an accepting condition of exploration
                        return;
                    }
                }
            }

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
            acceptingCondition = true;
        }
        public static void SessionSetupResponse(ModelSmb2Status status, ModelConnectionId connectionId, SessionMgmtConfig c)
        {
            VerifyConnection(connectionId);
            Condition.IsNotNull(ConnectionList[connectionId].Request);

            Condition.IsTrue(config.Platform == c.Platform);
            Condition.IsTrue(config.IsMultiChannelCapable == c.IsMultiChannelCapable);

            ModelSessionSetupRequest sessionSetupRequest = RetrieveOutstandingRequest <ModelSessionSetupRequest>(connectionId);

            if (sessionSetupRequest.isSigned)
            {
                ModelHelper.Log(LogType.Requirement, "3.3.5.2.4: If the SMB2 header of the request has SMB2_FLAGS_SIGNED set in the Flags field, the server MUST verify the signature.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_SIGNED is set in the SMB2 header of the SessionSetup Request.");

                // If server does not support Multiple channel then whether binding is set is meaningless.
                if (config.IsMultiChannelCapable && sessionSetupRequest.flags == ModelFlags.Binding)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If the request is for binding the session, the server MUST look up the session in the GlobalSessionTable using the SessionId in the SMB2 header of the request. ");
                    ModelHelper.Log(LogType.TestInfo, "SMB2_SESSION_FLAG_BINDING bit is set.");

                    if (!GlobalSessionTable.ContainsKey(sessionSetupRequest.sessionId))
                    {
                        ModelHelper.Log(LogType.Requirement,
                                        "If the session is not found, the request MUST be failed, as specified in section Sending an Error Response (section 3.3.4.4), " +
                                        "with the error code STATUS_USER_SESSION_DELETED. ");
                        ModelHelper.Log(LogType.TestInfo, "The session is not found in GlobalSessionTable.");
                        ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                        return;
                    }
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "For all other requests, the server MUST look up the session in the Connection.SessionTable using the SessionId in the SMB2 header of the request.");
                    ModelHelper.Log(LogType.TestInfo, "SMB2_SESSION_FLAG_BINDING bit is not set.");

                    if (ConnectionList[connectionId].Session == null || ConnectionList[connectionId].Session.SessionId != sessionSetupRequest.sessionId)
                    {
                        ModelHelper.Log(LogType.Requirement,
                                        "If the session is not found, the request MUST be failed, as specified in section Sending an Error Response (section 3.3.4.4), " +
                                        "with the error code STATUS_USER_SESSION_DELETED. ");
                        ModelHelper.Log(LogType.TestInfo, "The session is not found in Connection.SessionTable.");
                        ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                        return;
                    }
                }
            }

            if (sessionSetupRequest.sessionId == ModelSessionId.ZeroSessionId)
            {
                ModelHelper.Log(LogType.Requirement, "3.3.5.5: 3. If SessionId in the SMB2 header of the request is zero, the server MUST process the authentication request as specified in section 3.3.5.5.1.");
                ModelHelper.Log(LogType.TestInfo, "The SessionId of the SessionSetup Request is zero");

                AuthNewSession(status, sessionSetupRequest);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS || status == ModelSmb2Status.STATUS_MORE_PROCESSING_REQUIRED);
                return;
            }

            if (ModelUtility.IsSmb3xFamily(ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect) &&
                config.IsMultiChannelCapable &&
                sessionSetupRequest.flags == ModelFlags.Binding)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.5: 4. If Connection.Dialect belongs to the SMB 3.x dialect family, IsMultiChannelCapable is TRUE," +
                                "and the SMB2_SESSION_FLAG_BINDING bit is set in the Flags field of the request, the server MUST perform the following:" +
                                "The server MUST look up the session in GlobalSessionTable using the SessionId from the SMB2 header.");
                ModelHelper.Log(LogType.TestInfo,
                                "Connection.Dialect is {0}, IsMultiChannelCapable is TRUE, and the SMB2_SESSION_FLAG_BINDING bit is set",
                                ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect);

                if (!GlobalSessionTable.ContainsKey(sessionSetupRequest.sessionId))
                {
                    ModelHelper.Log(LogType.Requirement, "If the session is not found, the server MUST fail the session setup request with STATUS_USER_SESSION_DELETED.");
                    ModelHelper.Log(LogType.TestInfo, "The SessionId cannot be found in GlobalSessionTable");
                    ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                    return;
                }

                ModelHelper.Log(LogType.Requirement, "If a session is found, the server MUST do the following:");
                if (ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect != GlobalSessionTable[sessionSetupRequest.sessionId].Dialect)
                {
                    ModelHelper.Log(LogType.Requirement, "If Connection.Dialect is not the same as Session.Connection.Dialect, the server MUST fail the request with STATUS_INVALID_PARAMETER.");
                    ModelHelper.Log(LogType.TestInfo,
                                    "The Connection.Dialect is {0}, Session.Connection.Dialect is {1}",
                                    ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect,
                                    GlobalSessionTable[sessionSetupRequest.sessionId].Dialect);
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                    return;
                }

                if (!sessionSetupRequest.isSigned)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If the SMB2_FLAGS_SIGNED bit is not set in the Flags field in the header, the server MUST fail the request with error STATUS_INVALID_PARAMETER.");
                    ModelHelper.Log(LogType.TestInfo, "The SMB2_FLAGS_SIGNED bit is not set in the SessionSetup Request");
                    ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                    return;
                }

                if (GlobalSessionTable[sessionSetupRequest.sessionId].State == ModelSessionState.InProgress)
                {
                    ModelHelper.Log(LogType.Requirement, "If Session.State is InProgress, the server MUST fail the request with STATUS_REQUEST_NOT_ACCEPTED.");
                    ModelHelper.Log(LogType.TestInfo, "Session.State is InProgress");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_REQUEST_NOT_ACCEPTED);
                    return;
                }

                // If Session.IsAnonymousor Session.IsGuestis TRUE, the server MUST fail the request with STATUS_NOT_SUPPORTED.
                // Skip above requirement according to assumption 6.

                if (ConnectionList[sessionSetupRequest.connectionId].Session != null &&
                    ConnectionList[sessionSetupRequest.connectionId].Session.SessionId == sessionSetupRequest.sessionId)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If there is a session in Connection.SessionTable identified by the SessionId in the request, the server MUST fail the request with STATUS_REQUEST_NOT_ACCEPTED.");
                    ModelHelper.Log(LogType.TestInfo, "There is a session in Connection.SessionTable which has a same SessionId in the request");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_REQUEST_NOT_ACCEPTED);
                    return;
                }

                // The server MUST verify the signature as specified in section 3.3.5.2.4, using the Session.SessionKey.
                // Skip above requirement as it is verified in signing model

                if (sessionSetupRequest.user == ModelUser.DiffUser)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "The server MUST obtain the security context from the GSS authentication subsystem, " +
                                    "and it MUST invoke the GSS_Inquire_context call as specified in [RFC2743] section 2.2.6, " +
                                    "passing the security context as the input parameter." +
                                    "If the returned \"src_name\" does not match with the Session.Username, the server MUST fail the request with error code STATUS_NOT_SUPPORTED.");
                    ModelHelper.Log(LogType.TestInfo, "A different user is used when binding to an existing session");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_NOT_SUPPORTED);
                    return;
                }
            }
            else
            {
                if (config.Platform == Platform.WindowsServer2012 &&
                    sessionSetupRequest.flags == ModelFlags.Binding)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "<232> Section 3.3.5.5: Windows 8 and Windows Server 2012 look up the session in GlobalSessionTable using the SessionId from the SMB2 header " +
                                    "if the SMB2_SESSION_FLAG_BINDING bit is set in the Flags field of the request. ");
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}. The SMB2_SESSION_FLAG_BINDING bit is set.", config.Platform);
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                    if (GlobalSessionTable.ContainsKey(sessionSetupRequest.sessionId))
                    {
                        ModelHelper.Log(LogType.Requirement, "If the session is found, the server fails the request with STATUS_REQUEST_NOT_ACCEPTED. ");
                        ModelHelper.Log(LogType.TestInfo, "The session is found");
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_REQUEST_NOT_ACCEPTED);
                        return;
                    }
                    else
                    {
                        ModelHelper.Log(LogType.Requirement, "If the session is not found, the server fails the request with STATUS_USER_SESSION_DELETED.");
                        ModelHelper.Log(LogType.TestInfo, "The session is not found");
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                        return;
                    }
                }
                if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported) &&
                    ((ModelUtility.IsSmb2Family(ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect) || !config.IsMultiChannelCapable)) &&
                    sessionSetupRequest.flags == ModelFlags.Binding)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "3.3.5.5: Otherwise, if the server implements the SMB 3.x dialect family, " +
                                    "and Connection.Dialect is equal to \"2.002\" or \"2.100\" or IsMultiChannelCapable is FALSE, " +
                                    "and SMB2_SESSION_FLAG_BINDING bit is set in the Flags field of the request, " +
                                    "the server SHOULD<225> fail the session setup request with STATUS_REQUEST_NOT_ACCEPTED.");
                    ModelHelper.Log(LogType.TestInfo,
                                    "Connection.Dialect is {0}, IsMultiChannelCapable is {1}, SUT platform is {2}, Max Smb version supported is {3} and SMB2_SESSION_FLAG_BINDING bit is set.",
                                    ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect,
                                    config.IsMultiChannelCapable,
                                    config.Platform,
                                    config.MaxSmbVersionSupported);
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                    if (config.Platform != Platform.NonWindows)
                    {
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_REQUEST_NOT_ACCEPTED);
                    }
                    else
                    {
                        ModelHelper.Log(LogType.TestInfo, "The SUT platform is NonWindows, so the server could fail the request with other error code.");
                        Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                    }
                    return;
                }
                else
                {
                    if (ConnectionList[sessionSetupRequest.connectionId].Session == null ||
                        ConnectionList[sessionSetupRequest.connectionId].Session.SessionId != sessionSetupRequest.sessionId)
                    {
                        ModelHelper.Log(LogType.Requirement,
                                        "3.3.5.5: Otherwise, the server MUST look up the session in Connection.SessionTable using the SessionId from the SMB2 header." +
                                        "If the session is not found, the server MUST fail the session setup request with STATUS_USER_SESSION_DELETED. ");
                        ModelHelper.Log(LogType.TestInfo, "The session is not found using the SessionId of the request");
                        ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                        Condition.IsTrue(status == ModelSmb2Status.STATUS_USER_SESSION_DELETED);
                        return;
                    }
                }
            }
            if (GlobalSessionTable[sessionSetupRequest.sessionId].State == ModelSessionState.Valid)
            {
                ModelHelper.Log(LogType.Requirement, "3.3.5.5: 6. If Session.State is Valid, the server SHOULD process the session setup request as specified in section 3.3.5.5.2.");
                ModelHelper.Log(LogType.TestInfo, "Session.State is Valid");
                if (config.Platform == Platform.WindowsServer2008)
                {
                    ModelHelper.Log(LogType.Requirement, "Footnote: Windows Vista SP1 and Windows Server 2008 servers fail the session setup request with STATUS_REQUEST_NOT_ACCEPTED.");
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is Windows Server 2008");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_REQUEST_NOT_ACCEPTED);
                    return;
                }

                if (config.Platform != Platform.NonWindows)
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is Windows");
                    ReAuthentication(status, sessionSetupRequest);

                    Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS || status == ModelSmb2Status.STATUS_MORE_PROCESSING_REQUIRED);
                    return;
                }
            }

            ModelHelper.Log(LogType.Requirement, "3.3.5.5: 7. The server MUST continue processing the request as specified in section 3.3.5.5.3.");
            HandleGssApiAuth(status, sessionSetupRequest);
            ModelHelper.Log(LogType.TestInfo, "The authentication should succeed.");
            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS || status == ModelSmb2Status.STATUS_MORE_PROCESSING_REQUIRED);
        }
        public static void SessionSetupResponse(ModelSmb2Status status, SessionEncryptDataType sessionEncryptDataType, EncryptionConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);

            Condition.IsTrue(config.IsGlobalEncryptDataEnabled == c.IsGlobalEncryptDataEnabled);
            Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled);

            if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported) &&
                !Smb2Utility.IsSmb3xFamily(negotiateDialect) &&
                config.IsGlobalEncryptDataEnabled &&
                config.IsGlobalRejectUnencryptedAccessEnabled)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.5: 1. If the server implements the SMB 3.x dialect family, " +
                                "Connection.Dialect does not belong to the SMB 3.x dialect family, EncryptData is TRUE, " +
                                "and RejectUnencryptedAccess is TRUE, the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(LogType.TestInfo,
                                "The server implements {0}, Connection.Dialect is {1}, EncryptData is TRUE and RejectUnencryptedAccess is TRUE",
                                config.MaxSmbVersionSupported, negotiateDialect);

                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect) &&
                config.IsGlobalEncryptDataEnabled &&
                config.IsGlobalRejectUnencryptedAccessEnabled &&
                !Connection_ClientCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.5: 2. If Connection.Dialect belongs to the SMB 3.x dialect family, " +
                                "EncryptData is TRUE, RejectUnencryptedAccess is TRUE, " +
                                "and Connection.ClientCapabilities does not include the SMB2_GLOBAL_CAP_ENCRYPTION bit, " +
                                "the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(LogType.TestInfo,
                                "Connection.Dialect is {0}, EncryptData is TRUE, RejectUnencryptedAccess is TRUE, " +
                                "and Connection.ClientCapabilities does not include the SMB2_GLOBAL_CAP_ENCRYPTION bit.", negotiateDialect);

                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect) &&
                config.IsGlobalEncryptDataEnabled &&
                (Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION ||
                 config.IsGlobalRejectUnencryptedAccessEnabled))
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.5.3: 10.	If global EncryptData is TRUE, the server MUST do the following: " +
                                "If Connection.ServerCapabilities includes SMB2_GLOBAL_CAP_ENCRYPTION or RejectUnencryptedAccess is TRUE,");
                Condition.IsTrue(sessionEncryptDataType == SessionEncryptDataType.SessionEncryptDataSet);
                Session_EncryptData = SessionEncryptDataType.SessionEncryptDataSet;
            }

            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
            Session_IsExisted = true;
        }
        public static void ReEstablishResilientOpenResponse(ModelSmb2Status status)
        {
            if (Open == null)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.9.7: 1. The server MUST look up an existing open in the GlobalOpenTable by doing a lookup with the FileId.Persistent portion of the create context. " +
                    "If the lookup fails, the server SHOULD<268> fail the request with STATUS_OBJECT_NAME_NOT_FOUND " +
                    "and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                ModelHelper.Log(LogType.TestInfo, "The lookup fails.");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return;
            }

            if (!Open.IsResilient && !Open.IsDurable)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.9.7: 5. If Open.IsDurable is FALSE and Open.IsResilient is FALSE or unimplemented, " +
                    "the server MUST fail the request with STATUS_OBJECT_NAME_NOT_FOUND and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9");
                ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is FALSE and Open.IsResilient is FALSE.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                return;
            }

            ModelReEstablishResilientOpenRequest reEstablishRequest =
                ModelHelper.RetrieveOutstandingRequest<ModelReEstablishResilientOpenRequest>(ref Request);
            if (Open.DurableOwner != reEstablishRequest.User)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.9.7: 9. If the user represented by Session.SecurityContext is not the same user denoted by Open.DurableOwner, " +
                    "the server MUST fail the request with STATUS_ACCESS_DENIED and proceed as specified in \"Failed Open Handling\" in section 3.3.5.9.");
                ModelHelper.Log(LogType.TestInfo, "The user is different.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        public static void NegotiateResponse(ModelSmb2Status status, DialectRevision dialectRevision)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsTrue(Request is ModelComNegotiateRequest || Request is NegotiateRequest);

            // Avoid "Microsoft.SpecExplorer.Runtime.Testing.UnboundVariableException: Variable's value cannot be read before it is bound"
            Condition.IsTrue(dialectRevision == DialectRevision.Smb2002 || dialectRevision == DialectRevision.Smb21 ||
                             dialectRevision == DialectRevision.Smb30 || dialectRevision == DialectRevision.Smb302 ||
                             dialectRevision == DialectRevision.Smb2Wildcard ||
                             dialectRevision == DialectRevision.Smb2Unknown);

            if (Request is ModelComNegotiateRequest)
            {
                ModelComNegotiateRequest comNegotiateReq = ModelHelper.RetrieveOutstandingRequest<ModelComNegotiateRequest>(ref Request);

                if (Config.MaxSmbVersionSupported != DialectRevision.Smb21 && !ModelUtility.IsSmb3xFamily(Config.MaxSmbVersionSupported))
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.3.1: If the server does not implement the SMB 2.1 or 3.x dialect family, processing MUST continue as specified in 3.3.5.3.2.");

                    ComNegotiateHandleSmb2002InResponse(dialectRevision);
                }
                else
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.3.1: Otherwise, the server MUST scan the dialects provided for the dialect string \"SMB 2.???\".");

                    if (comNegotiateReq.Dialects.Contains(SMBDialects.SMB_2_X))
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.3.1: If the string is present, the server MUST respond with an SMB2 NEGOTIATE Response as specified in 2.2.4.");

                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.3.1: DialectRevision MUST be set to 0x02FF");

                        NegotiateDialect = DialectRevision.Smb2Wildcard;

                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.3.1: Connection.NegotiateDialect MUST be set to 0x02FF, and the response is sent to the client");

                        Condition.IsTrue(dialectRevision == DialectRevision.Smb2Wildcard);
                    }
                    else
                    {
                        ModelHelper.Log(
                            LogType.Requirement,
                            "3.3.5.3.1: If the string is not present, continue to section 3.3.5.3.2");

                        ComNegotiateHandleSmb2002InResponse(dialectRevision);
                    }
                }
            }
            else
            {
                NegotiateRequest negotiateReq = ModelHelper.RetrieveOutstandingRequest<NegotiateRequest>(ref Request);

                if (negotiateReq.Dialects.Count == 0)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.4: If the DialectCount of the SMB2 NEGOTIATE Request is 0, the server MUST fail the request with STATUS_INVALID_PARAMETER");
                    ModelHelper.Log(
                        LogType.TestInfo,
                        "DialectCount of the SMB2 NEGOTIATE Request is 0");
                    ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                    return;
                }

                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.4: The server MUST select the greatest common dialect between the dialects it implements and the Dialects array of the SMB2 NEGOTIATE request");

                DialectRevision commonDialect = SelectCommonDialect(negotiateReq.Dialects);

                ModelHelper.Log(
                    LogType.TestInfo,
                    "Common dialect is {0}", commonDialect);
                if (commonDialect == DialectRevision.Smb2Unknown)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.4: If a common dialect is not found, the server MUST fail the request with STATUS_NOT_SUPPORTED");
                    ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_NOT_SUPPORTED);
                    return;
                }

                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.4: If a common dialect is found, the server MUST set Connection.Dialect to \"2.002\", \"2.100\", \"3.000\", or \"3.002\"," +
                    " and Connection.NegotiateDialect to 0x0202, 0x0210, 0x0300, or 0x0302 accordingly, to reflect the dialect selected");

                NegotiateDialect = commonDialect;

                ModelHelper.Log(
                    LogType.TestInfo,
                    "Connection.Dialect is set to {0}", NegotiateDialect);

                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.4: The server MUST then construct an SMB2 NEGOTIATE Response, as specified in section 2.2.4, with the following specific values, and return STATUS_SUCCESS to the client.");
                ModelHelper.Log(
                    LogType.Requirement,
                    "\tDialectRevision MUST be set to the common dialect");

                Condition.IsTrue(dialectRevision == commonDialect);
            }

            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }
        private static void HandleGssApiAuth(ModelSmb2Status status, ModelSessionSetupRequest sessionSetupRequest)
        {
            ModelHelper.Log(LogType.Requirement, "3.3.5.5.3: 1. The status code in the SMB2 header of the response MUST be set to STATUS_SUCCESS. ");
            if (status != ModelSmb2Status.STATUS_SUCCESS)
            {
                return;
            }

            if (ModelUtility.IsSmb3xFamily(ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect))
            {
                ModelHelper.Log(LogType.Requirement, "If Connection.Dialect belongs to the SMB 3.x dialect family, the server MUST insert the Session into Connection.SessionTable. ");
                ModelHelper.Log(LogType.TestInfo, "Connection.Dialect is {0}", ConnectionList[sessionSetupRequest.connectionId].NegotiateDialect);
                ConnectionList[sessionSetupRequest.connectionId].Session
                    = GlobalSessionTable[sessionSetupRequest.sessionId];
            }

            ModelHelper.Log(LogType.Requirement, "If Session.IsAnonymous is FALSE, the server MUST set Connection.ConstrainedConnection to FALSE.");
            ModelHelper.Log(LogType.TestInfo, "Session.IsAnonymous is FALSE, so set Connection.ConstrainedConnection to FALSE");
            ConnectionList[sessionSetupRequest.connectionId].ConstrainedConnection = false;

            /*
             * Assuming STATUS_SUCCESS indicates final message in the authentication exchange
             *
             * Skip following requirement according to assumption 6.
             * If the returned anon_state is TRUE, the server MUST set Session.IsAnonymous to TRUE and the server MAY set
             * the SMB2_SESSION_FLAG_IS_NULL flag in the SessionFlags field of the SMB2 SESSION_SETUP Response.
             * Otherwise, if the returned src_name corresponds to an implementation-specific guest user,<211>
             * the server MUST set the SMB2_SESSION_FLAG_IS_GUEST in the SessionFlags field of the SMB2 SESSION_SETUP Response
             * and MUST set Session.IsGuest to TRUE.
             */

            if (sessionSetupRequest.previousSessionId != ModelSessionId.ZeroSessionId)
            {
                ModelHelper.Log(LogType.Requirement, "12. If the PreviousSessionId field of the request is not equal to zero, the server MUST take the following actions:");
                ModelHelper.Log(LogType.TestInfo, "PreviousSessionId is not equal to zero.");

                ModelHelper.Log(LogType.Requirement, "1. The server MUST look up the old session in GlobalSessionTable, where Session.SessionId matches PreviousSessionId. ");
                if (GlobalSessionTable.ContainsKey(sessionSetupRequest.previousSessionId))
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If a session is found with Session.SessionId equal to PreviousSessionId, " +
                                    "the server MUST determine if the old session and the newly established session are created by the same user " +
                                    "by comparing the user identifiers obtained from the Session.SecurityContext on the new and old session.");
                    ModelHelper.Log(LogType.TestInfo, "There is a session with Session.SessionId equal to PreviousSessionId.");

                    if (sessionSetupRequest.previousSessionId == sessionSetupRequest.sessionId)
                    {
                        ModelHelper.Log(LogType.Requirement, "1. If the PreviousSessionId and SessionId values in the SMB2 header of the request are equal, " +
                                        "the server SHOULD<230> ignore PreviousSessionId and no other processing is required.");
                        ModelHelper.Log(LogType.TestInfo, "PreviousSessionId is equal to SessionId.");
                        // Do nothing
                    }
                    else if (sessionSetupRequest.user == ModelUser.DefaultUser)
                    {
                        ModelHelper.Log(LogType.Requirement,
                                        "2.	Otherwise, if the server determines the authentications were for the same user, " +
                                        "the server MUST remove the old session from the GlobalSessionTable and also from the Connection.SessionTable, as specified in section 3.3.7.1.");
                        ModelHelper.Log(LogType.TestInfo, "The authentications were for the same user");
                        GlobalSessionTable.Remove(sessionSetupRequest.previousSessionId);
                    }
                }
            }

            ModelHelper.Log(LogType.Requirement, "13. Session.State MUST be set to Valid.");
            // Update both GlobalSessionTable and ConnectionList
            GlobalSessionTable[sessionSetupRequest.sessionId].State        = ModelSessionState.Valid;
            ConnectionList[sessionSetupRequest.connectionId].Session.State = ModelSessionState.Valid;
        }
        public static void FileOperationResponse(ModelSmb2Status status, ReplayServerConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);

            Condition.IsTrue(Config == c);

            Condition.IsNotNull(Request);

            ModelReplayFileOperationRequest operationRequest = ModelHelper.RetrieveOutstandingRequest<ModelReplayFileOperationRequest>(ref Request);

            // 3.3.5.2.10 Verifying the Channel Sequence Number
            PreCheckChannelSequence(operationRequest.requestCommand,
                operationRequest.channel.Connection_NegotiateDialect,
                ref operationRequest.channelSequence,
                operationRequest.isSetReplayFlag == ReplayModelSetReplayFlag.WithReplayFlag,
                status);

            // 3.3.4.1 Sending Any Outgoing Message
            PostCheckChannelSequence(operationRequest.requestCommand,
                operationRequest.channel.Connection_NegotiateDialect,
                operationRequest.channelSequence);
        }
Exemple #50
0
        public static void OplockBreakResponse(ModelSmb2Status status, OPLOCK_BREAK_Response_OplockLevel_Values oplockLevel, OplockLevel_Values oplockLevelOnOpen)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsNotNull(Request);

            ModelOplockBreakAcknowledgementRequest oplockBreakAckRequest = ModelHelper.RetrieveOutstandingRequest <ModelOplockBreakAcknowledgementRequest>(ref Request);

            ModelHelper.Log(LogType.Requirement,
                            "3.3.5.22.1   Processing an Oplock Acknowledgment");

            if (!oplockBreakAckRequest.VolatilePortionFound ||
                !oplockBreakAckRequest.PersistentMatchesDurableFileId)
            {
                ModelHelper.Log(LogType.Requirement,
                                "Next, the server MUST locate the open on which the client is acknowledging an oplock break by performing a lookup in Session.OpenTable " +
                                "using FileId.Volatile of the request as the lookup key. If no open is found, or if Open.DurableFileId is not equal to FileId.Persistent, " +
                                "the server MUST fail the request with STATUS_FILE_CLOSED. ");
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);

                if (!oplockBreakAckRequest.VolatilePortionFound)
                {
                    ModelHelper.Log(LogType.TestInfo, "Open is not found.");
                }
                if (!oplockBreakAckRequest.PersistentMatchesDurableFileId)
                {
                    ModelHelper.Log(LogType.TestInfo, "Open.DurableFileId is not equal to FileId.Persistent.");
                }
                Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_CLOSED);
                return;
            }

            // We need this to avoid Open.OplockLevel being symbolic which will result case exploration failure
            Condition.IsTrue(Open.OplockLevel == oplockLevelOnOpen);
            Condition.IsTrue(oplockLevelOnOpen == OplockLevel_Values.OPLOCK_LEVEL_NONE ||
                             oplockLevelOnOpen == OplockLevel_Values.OPLOCK_LEVEL_II ||
                             oplockLevelOnOpen == OplockLevel_Values.OPLOCK_LEVEL_BATCH);

            if (oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_LEASE)
            {
                ModelHelper.Log(LogType.Requirement,
                                "If the OplockLevel in the acknowledgment is SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Open.OplockState is {0}.", Open.OplockState);

                if (Open.OplockState != OplockState.Breaking)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If Open.OplockState is not Breaking, stop processing the acknowledgment, " +
                                    "and send an error response with STATUS_INVALID_PARAMETER.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                    return;
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If Open.OplockState is Breaking, complete the oplock break request received from the object store as described in section 3.3.4.6, " +
                                    "with a new level SMB2_OPLOCK_LEVEL_NONE in an implementation-specific manner,<350> and set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE, " +
                                    "and Open.OplockState to None.");
                    ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                    Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                    Open.OplockState = OplockState.None;

                    // Do not assert implementation-specific manner
                    return;
                }
            }

            if ((Open.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_EXCLUSIVE ||
                 Open.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_BATCH) &&
                (oplockBreakAckRequest.OplockLevel != OplockLevel_Values.OPLOCK_LEVEL_II && oplockBreakAckRequest.OplockLevel != OplockLevel_Values.OPLOCK_LEVEL_NONE))
            {
                ModelHelper.Log(LogType.Requirement,
                                "If Open.OplockLevel is SMB2_OPLOCK_LEVEL_EXCLUSIVE or SMB2_OPLOCK_LEVEL_BATCH, " +
                                "and if OplockLevel is not SMB2_OPLOCK_LEVEL_II or SMB2_OPLOCK_LEVEL_NONE, the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Open.OplockState is {0}.", Open.OplockState);

                if (Open.OplockState != OplockState.Breaking)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If Open.OplockState is not Breaking, stop processing the acknowledgment, " +
                                    "and send an error response with STATUS_INVALID_OPLOCK_PROTOCOL.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_OPLOCK_PROTOCOL);
                    return;
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If Open.OplockState is Breaking, complete the oplock break request received from the object store, " +
                                    "as described in section 3.3.4.6, with a new level SMB2_OPLOCK_LEVEL_NONE in an implementation-specific manner," +
                                    "<351> and set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE and Open.OplockState to None.");
                    ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                    Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                    Open.OplockState = OplockState.None;

                    // Do not assert implementation-specific manner
                    return;
                }
            }

            if (Open.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_II &&
                oplockBreakAckRequest.OplockLevel != OplockLevel_Values.OPLOCK_LEVEL_NONE)
            {
                ModelHelper.Log(LogType.Requirement,
                                "If Open.OplockLevel is SMB2_OPLOCK_LEVEL_II, and if OplockLevel is not SMB2_OPLOCK_LEVEL_NONE, " +
                                "the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Open.OplockState is {0}.", Open.OplockState);

                if (Open.OplockState != OplockState.Breaking)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If Open.OplockState is not Breaking, stop processing the acknowledgment, and send an error response with STATUS_INVALID_OPLOCK_PROTOCOL.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_OPLOCK_PROTOCOL);
                    return;
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If Open.OplockState is Breaking, complete the oplock break request received from the object store, " +
                                    "as described in section 3.3.4.6, with a new level SMB2_OPLOCK_LEVEL_NONE in an implementation-specific manner," +
                                    "<352> and set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE and Open.OplockState to None.");
                    ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                    Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                    Open.OplockState = OplockState.None;

                    // Do not assert implementation-specific manner
                    return;
                }
            }

            if (oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_II ||
                oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_NONE)
            {
                ModelHelper.Log(LogType.Requirement,
                                "If OplockLevel is SMB2_OPLOCK_LEVEL_II or SMB2_OPLOCK_LEVEL_NONE, the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Open.OplockState is {0}.", Open.OplockState);

                if (Open.OplockState != OplockState.Breaking)
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If Open.OplockState is not Breaking, stop processing the acknowledgment, " +
                                    "and send an error response with STATUS_INVALID_DEVICE_STATE.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_DEVICE_STATE);
                    return;
                }
                else
                {
                    ModelHelper.Log(LogType.Requirement,
                                    "If Open.OplockState is Breaking, " +
                                    "complete the oplock break request received from the object store as described in section 3.3.4.6, " +
                                    "with a new level received in OplockLevel in an implementation-specific manner.<353>");

                    if (status != ModelSmb2Status.STATUS_SUCCESS)
                    {
                        ModelHelper.Log(LogType.Requirement,
                                        "If the object store indicates an error, set the Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE, " +
                                        "the Open.OplockState to None, and send the error response with the error code received.");
                        ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                        Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                        Open.OplockState = OplockState.None;
                        return;
                    }
                    else
                    {
                        ModelHelper.Log(LogType.Requirement,
                                        "If the object store indicates success, update Open.OplockLevel and Open.OplockState as follows:");
                        if (oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_II)
                        {
                            ModelHelper.Log(LogType.Requirement,
                                            "If OplockLevel is SMB2_OPLOCK_LEVEL_II, " +
                                            "set Open.OplockLevel to SMB2_OPLOCK_LEVEL_II and Open.OplockState to Held.");
                            ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to OPLOCK_LEVEL_II, and Open.OplockState is set to None");
                            Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_II;
                            Open.OplockState = OplockState.Held;
                        }
                        if (oplockBreakAckRequest.OplockLevel == OplockLevel_Values.OPLOCK_LEVEL_NONE)
                        {
                            ModelHelper.Log(LogType.Requirement,
                                            "If OplockLevel is SMB2_OPLOCK_LEVEL_NONE, " +
                                            "set Open.OplockLevel to SMB2_OPLOCK_LEVEL_NONE and the Open.OplockState to None.");
                            ModelHelper.Log(LogType.TestInfo, "Open.OplockLevel is set to SMB2_OPLOCK_LEVEL_NONE, and Open.OplockState is set to None");
                            Open.OplockLevel = OplockLevel_Values.OPLOCK_LEVEL_NONE;
                            Open.OplockState = OplockState.None;
                        }
                    }
                }
            }

            ModelHelper.Log(LogType.Requirement,
                            "The server then MUST construct an oplock break response using the syntax specified in section 2.2.25 with the following value:");
            ModelHelper.Log(LogType.Requirement,
                            "OplockLevel MUST be set to Open.OplockLevel.");
            ModelHelper.Log(LogType.TestInfo,
                            "Open.OplockLevel is {0}.", Open.OplockLevel);

            Condition.IsTrue(Open.OplockLevel == (OplockLevel_Values)oplockLevel);

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        public static void FileOperationVerifyEncryptionResponse(ModelSmb2Status status, ModelResponseType modelResponseType, EncryptionConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);
            Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled);

            ModelFileOperationVerifyEncryptionRequest createFileRequest = ModelHelper.RetrieveOutstandingRequest<ModelFileOperationVerifyEncryptionRequest>(ref request);

            if (!VerifySession(status, createFileRequest.modelRequestType))
            {
                return;
            }

            if (!VerifyTreeConnect(status, createFileRequest.modelRequestType, c))
            {
                return;
            }

            //TODO: To be implemented after TRANSFORM_HEADER added into Smb2FunctionalClient
            if (createFileRequest.modelRequestType == ModelRequestType.EncryptedRequest)
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.EncryptedResponse);
            }
            else
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.UnEncryptedResponse);
            }

            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }
        public static void TreeConnectResponse(
            ModelSmb2Status status,
            ShareEncryptDataType shareEncryptDataType,
            ModelResponseType modelResponseType,
            EncryptionConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);
            Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled);
            Condition.IsTrue(Session_IsExisted);

            ModelTreeConnectRequest treeConnectRequest = ModelHelper.RetrieveOutstandingRequest <ModelTreeConnectRequest>(ref request);

            if (!VerifySession(status, treeConnectRequest.modelRequestType, c))
            {
                return;
            }

            if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported) &&
                (config.IsGlobalEncryptDataEnabled ||
                 treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare) &&
                config.IsGlobalRejectUnencryptedAccessEnabled &&
                !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.7: If the server implements the SMB 3.x dialect family, EncryptData or Share.EncryptData is TRUE, " +
                                "RejectUnencryptedAccess is TRUE, and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION, " +
                                "the server MUST fail the request with STATUS_ACCESS_DENIED.");
                Condition.IsTrue(config.Platform == c.Platform);
                ModelHelper.Log(LogType.TestInfo,
                                "The server implements {0}, EncryptData is {1}, Share.EncryptData is {2}, RejectUnencryptedAccess is TRUE, " +
                                "Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION.",
                                config.MaxSmbVersionSupported,
                                config.IsGlobalEncryptDataEnabled,
                                treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare ? "TRUE" : "FALSE");
                ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}.", config.Platform);
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);

                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect) &&
                treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare &&
                config.IsGlobalRejectUnencryptedAccessEnabled &&
                !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)
            {
                ModelHelper.Log(LogType.Requirement,
                                "3.3.5.7: If Connection.Dialect belongs to the SMB 3.x dialect family, " +
                                "Share.EncryptData is TRUE, RejectUnencryptedAccess is TRUE, " +
                                "and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION, " +
                                "the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(LogType.Requirement,
                                "\tSet the SMB2_SHAREFLAG_ENCRYPT_DATA bit.");
                ModelHelper.Log(LogType.TestInfo, "Connection.Dialect is {0}, and Share.EncryptData is TRUE.", negotiateDialect);
                Condition.IsTrue(shareEncryptDataType == ShareEncryptDataType.ShareEncryptDataSet);
            }

            //TODO: To be implemented after TRANSFORM_HEADER added into Smb2FunctionalClient
            if (treeConnectRequest.modelRequestType == ModelRequestType.EncryptedRequest)
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.EncryptedResponse);
            }
            else
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.UnEncryptedResponse);
            }
            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);

            Encryption_TreeId = (treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare) ? EncryptionTreeId.TreeIdToEncryptShare : EncryptionTreeId.TreeIdToUnEncryptShare;
        }
        public static void SessionSetupResponse(ModelSmb2Status status, SessionEncryptDataType sessionEncryptDataType, EncryptionConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);

            Condition.IsTrue(config.IsGlobalEncryptDataEnabled == c.IsGlobalEncryptDataEnabled);
            Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled);

            if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported)
                && !Smb2Utility.IsSmb3xFamily(negotiateDialect)
                && config.IsGlobalEncryptDataEnabled
                && config.IsGlobalRejectUnencryptedAccessEnabled)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.5: 1. If the server implements the SMB 3.x dialect family, " +
                    "Connection.Dialect does not belong to the SMB 3.x dialect family, EncryptData is TRUE, " +
                    "and RejectUnencryptedAccess is TRUE, the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(LogType.TestInfo,
                    "The server implements {0}, Connection.Dialect is {1}, EncryptData is TRUE and RejectUnencryptedAccess is TRUE",
                    config.MaxSmbVersionSupported, negotiateDialect);

                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect)
                && config.IsGlobalEncryptDataEnabled
                && config.IsGlobalRejectUnencryptedAccessEnabled
                && !Connection_ClientCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.5: 2. If Connection.Dialect belongs to the SMB 3.x dialect family, " +
                    "EncryptData is TRUE, RejectUnencryptedAccess is TRUE, " +
                    "and Connection.ClientCapabilities does not include the SMB2_GLOBAL_CAP_ENCRYPTION bit, " +
                    "the server MUST fail the request with STATUS_ACCESS_DENIED.");
                ModelHelper.Log(LogType.TestInfo,
                    "Connection.Dialect is {0}, EncryptData is TRUE, RejectUnencryptedAccess is TRUE, " +
                    "and Connection.ClientCapabilities does not include the SMB2_GLOBAL_CAP_ENCRYPTION bit.", negotiateDialect);

                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect)
                && config.IsGlobalEncryptDataEnabled
                && Connection_ClientCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.5.3: 10.	If Connection.Dialect belongs to the SMB 3.x dialect family, global EncryptData is TRUE, " +
                    "and Connection.ClientCapabilities includes the SMB2_GLOBAL_CAP_ENCRYPTION bit, the server MUST do the following:");
                ModelHelper.Log(LogType.TestInfo, "Connection.Dialect is {0}, global EncryptData is TRUE, " +
                    "and Connection.ClientCapabilities includes the SMB2_GLOBAL_CAP_ENCRYPTION bit", negotiateDialect);

                ModelHelper.Log(LogType.Requirement,
                    "\tSet the SMB2_SESSION_FLAG_ENCRYPT_DATA flag in the SessionFlags field of the SMB2 SESSION_SETUP Response.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_SESSION_FLAG_ENCRYPT_DATA flag is set in SESSION_SETUP Response.");
                Condition.IsTrue(sessionEncryptDataType == SessionEncryptDataType.SessionEncryptDataSet);
                Session_EncryptData = SessionEncryptDataType.SessionEncryptDataSet;
            }

            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }
        public static void IoCtlResiliencyResponse(ModelSmb2Status status, ResilientHandleServerConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);
            Condition.IsNotNull(Open);

            Condition.IsTrue(Config.Platform == c.Platform);
            Condition.IsTrue(Config.MaxSmbVersionSupported == c.MaxSmbVersionSupported);
            Condition.IsTrue(Config.IsIoCtlCodeResiliencySupported == c.IsIoCtlCodeResiliencySupported);

            ModelResiliencyRequest resiliencyRequest = ModelHelper.RetrieveOutstandingRequest<ModelResiliencyRequest>(ref Request);

            ModelHelper.Log(LogType.Requirement, "3.3.5.15.9 Handling a Resiliency Request");
            ModelHelper.Log(LogType.Requirement, "This section applies only to servers that implement the SMB 2.1 or the SMB 3.x dialect family.");
            if (c.MaxSmbVersionSupported == ModelDialectRevision.Smb2002)
            {
                ModelHelper.Log(LogType.TestInfo, "The server only supports SMB 2.002.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                return;
            }

            if (Connection_Dialect == DialectRevision.Smb2002)
            {
                ModelHelper.Log(LogType.Requirement, "If Open.Connection.Dialect is \"2.002\", the server MAY<320> fail the request with STATUS_INVALID_DEVICE_REQUEST.");
                ModelHelper.Log(LogType.TestInfo, "Open.Connection.Dialect is \"2.002\".");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                if (c.Platform == Platform.NonWindows)
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is NonWindows.");
                    if (status == ModelSmb2Status.STATUS_INVALID_DEVICE_REQUEST)
                    {
                        return;
                    }
                }
                else
                {
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is Windows.");
                    Condition.IsFalse(status == ModelSmb2Status.STATUS_INVALID_DEVICE_REQUEST);
                }

            }

            if (!c.IsIoCtlCodeResiliencySupported)
            {
                ModelHelper.Log(LogType.Requirement,
                    "Otherwise, if the server does not support FSCTL_LMR_REQUEST_RESILIENCY requests, the server SHOULD fail the request with STATUS_NOT_SUPPORTED.");
                ModelHelper.Log(LogType.TestInfo,
                    "The server does not support FSCTL_LMR_REQUEST_RESILIENCY requests.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                if (c.Platform == Platform.NonWindows)
                {// Non Windows
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is NonWindows.");
                    Condition.IsFalse(status == ModelSmb2Status.STATUS_SUCCESS);
                }
                else
                {// Windows
                    ModelHelper.Log(LogType.TestInfo, "The SUT platform is Windows.");
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_NOT_SUPPORTED);
                    return;
                }
            }

            if (resiliencyRequest.InputCount == IoCtlInputCount.InputCountSmallerThanRequestSize
                || resiliencyRequest.Timeout == ResilientTimeout.InvalidTimeout)
            {
                ModelHelper.Log(LogType.Requirement,
                    "If InputCount is smaller than the size of the NETWORK_RESILIENCY_REQUEST request as specified in section 2.2.31.3, " +
                    "or if the requested Timeout in seconds is greater than MaxResiliencyTimeout in seconds, the request MUST be failed with STATUS_INVALID_PARAMETER.");
                ModelHelper.Log(LogType.TestInfo,
                    "InputCount is {0}smaller than the size of the NETWORK_RESILIENCY_REQUEST request.",
                    resiliencyRequest.InputCount == IoCtlInputCount.InputCountSmallerThanRequestSize ? "" : "not ");
                ModelHelper.Log(LogType.TestInfo,
                    "The requested Timeout is {0} greater than MaxResiliencyTimeout.",
                    resiliencyRequest.Timeout == ResilientTimeout.InvalidTimeout ? "" : "not ");
                ModelHelper.Log(LogType.TestTag, TestTag.OutOfBoundary);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                return;
            }

            ModelHelper.Log(LogType.Requirement, "Open.IsDurable MUST be set to FALSE. Open.IsResilient MUST be set to TRUE. ");
            ModelHelper.Log(LogType.TestInfo, "Open.IsDurable is set to FALSE. Open.IsResilient is set to TRUE.");
            Open.IsDurable = false;
            Open.IsResilient = true;

            ModelHelper.Log(LogType.Requirement,
                "Open.DurableOwner MUST be set to a security descriptor accessible only by the user represented by Open.Session.SecurityContext.");
            ModelHelper.Log(LogType.TestInfo, "Open.DurableOwner is set to default user.");
            Open.DurableOwner = ModelUser.DefaultUser; // In Resilient Handle Mode, Resilient always be requested as default user

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        public static void TreeConnectResponse(
            ModelSmb2Status status,
            ShareEncryptDataType shareEncryptDataType,
            ModelResponseType modelResponseType,
            EncryptionConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);
            Condition.IsTrue(config.IsGlobalRejectUnencryptedAccessEnabled == c.IsGlobalRejectUnencryptedAccessEnabled);

            ModelTreeConnectRequest treeConnectRequest = ModelHelper.RetrieveOutstandingRequest<ModelTreeConnectRequest>(ref request);

            if (!VerifySession(status, treeConnectRequest.modelRequestType))
            {
                return;
            }

            if (ModelUtility.IsSmb3xFamily(config.MaxSmbVersionSupported)
                && (config.IsGlobalEncryptDataEnabled
                    || treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare)
                && config.IsGlobalRejectUnencryptedAccessEnabled
                && !Connection_ServerCapabilities_SMB2_GLOBAL_CAP_ENCRYPTION)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.7: If the server implements the SMB 3.x dialect family, EncryptData or Share.EncryptData is TRUE, " +
                    "RejectUnencryptedAccess is TRUE, and Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION, " +
                    "the server SHOULD fail the request with STATUS_ACCESS_DENIED.");
                Condition.IsTrue(config.Platform == c.Platform);
                ModelHelper.Log(LogType.TestInfo,
                    "The server implements {0}, EncryptData is {1}, Share.EncryptData is {2}, RejectUnencryptedAccess is TRUE, " +
                    "Connection.ServerCapabilities does not include SMB2_GLOBAL_CAP_ENCRYPTION.",
                    config.MaxSmbVersionSupported,
                    config.IsGlobalEncryptDataEnabled,
                    treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare ? "TRUE" : "FALSE");
                ModelHelper.Log(LogType.TestInfo, "The SUT platform is {0}.", config.Platform);
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);

                if (config.Platform == Platform.NonWindows)
                {
                    Condition.IsTrue(status != ModelSmb2Status.STATUS_SUCCESS);
                }
                else
                {
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_ACCESS_DENIED);
                }
                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect)
                && treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.7: If Connection.Dialect belongs to the SMB 3.x dialect family, " +
                    "and Share.EncryptData is TRUE, the server MUST do the following:");
                ModelHelper.Log(LogType.Requirement,
                    "\tSet the SMB2_SHAREFLAG_ENCRYPT_DATA bit.");
                ModelHelper.Log(LogType.TestInfo, "Connection.Dialect is {0}, and Share.EncryptData is TRUE.", negotiateDialect);
                Condition.IsTrue(shareEncryptDataType== ShareEncryptDataType.ShareEncryptDataSet);
            }

            //TODO: To be implemented after TRANSFORM_HEADER added into Smb2FunctionalClient
            if (treeConnectRequest.modelRequestType == ModelRequestType.EncryptedRequest)
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.EncryptedResponse);
            }
            else
            {
                Condition.IsTrue(modelResponseType == ModelResponseType.UnEncryptedResponse);
            }
            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);

            Encryption_TreeId = (treeConnectRequest.connectToShareType == ConnectToShareType.ConnectToEncryptedShare) ? EncryptionTreeId.TreeIdToEncryptShare : EncryptionTreeId.TreeIdToUnEncryptShare;
        }
        public static void ConflictResponse(ModelSmb2Status status, LeaseBreakState leaseBreakState)
        {
            switch (State)
            {
                case FileState.Initial:
                    ModelHelper.Log(LogType.TestInfo, "The state of the file is not changed. So any request from the second client should succeed.");
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                    break;
                case FileState.Locked:
                    switch (SecondRequest)
                    {
                        case RequestType.ExclusiveLock:
                            ModelHelper.Log(
                                LogType.Requirement,
                                "3.3.5.14.2: If the range being locked is already locked by another open in a way " +
                                "that does not allow this open to take a lock on the range, and if SMB2_LOCKFLAG_FAIL_IMMEDIATELY is set, " +
                                "the server MUST fail the request with STATUS_LOCK_NOT_GRANTED.");
                            ModelHelper.Log(LogType.TestInfo, "The file is already locked and SMB2_LOCKFLAG_FAIL_IMMEDIATELY is set.");
                            ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                            Condition.IsTrue(status == ModelSmb2Status.STATUS_LOCK_NOT_GRANTED);
                            break;
                        case RequestType.Lease:
                            ModelHelper.Log(LogType.TestInfo, "Lease succeed even the file is locked.");
                            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                            break;
                        case RequestType.Delete:
                            ModelHelper.Log(LogType.TestInfo, "Delete succeed even the file is locked.");
                            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                            break;
                        case RequestType.Write:
                            ModelHelper.Log(LogType.TestInfo, "Write fails because the file is locked.");
                            ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                            Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_LOCK_CONFLICT);
                            break;
                        case RequestType.Read:
                            ModelHelper.Log(LogType.TestInfo, "Read fails because the file is locked.");
                            ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                            Condition.IsTrue(status == ModelSmb2Status.STATUS_FILE_LOCK_CONFLICT);
                            break;
                        default:
                            break;
                    }
                    break;
                case FileState.LeaseGranted:
                    ModelHelper.Log(
                        LogType.TestInfo,
                        "A lease to this file is granted to the first open, but it will not fail the operation from the second client");
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                    break;
                case FileState.ToBeDeleted:
                    ModelHelper.Log(LogType.TestInfo, "The file is not deleted, and it will be deleted only if the second open is closed.");
                    ModelHelper.Log(LogType.TestInfo, "So the other operation ahead of Close request from the second client will succeed.");
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
                    break;
                case FileState.Deleted:
                    ModelHelper.Log(LogType.TestInfo, "The file is deleted, so any operation to the non-existed file fails.");
                    ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                    Condition.IsTrue(status == ModelSmb2Status.STATUS_OBJECT_NAME_NOT_FOUND);
                    break;
                default:
                    break;
            }

            if (State == FileState.LeaseGranted
                && (SecondRequest == RequestType.Write || SecondRequest == RequestType.ExclusiveLock))
            {
                ModelHelper.Log(LogType.TestInfo, "A lease to this file is granted to the first open. ");
                ModelHelper.Log(LogType.TestInfo, "The {0} request from second client should break the lease state.", SecondRequest);
                Condition.IsTrue(leaseBreakState == LeaseBreakState.LeaseBreakExisted);
            }
            else
            {
                if (State == FileState.LeaseGranted)
                {
                    ModelHelper.Log(
                        LogType.TestInfo,
                        "A lease is granted to the first open, but the {0} request from the second client cannot break the state.", SecondRequest);
                }
                else
                {
                    ModelHelper.Log(LogType.TestInfo, "No lease is granted to the first open, so no lease break.");
                }
                Condition.IsTrue(leaseBreakState == LeaseBreakState.NoLeaseBreak);
            }
        }
        public static void NegotiateResponse(ModelSmb2Status status, SigningEnabledType signingEnabledType, SigningRequiredType signingRequiredType, SigningConfig c)
        {
            Condition.IsTrue(State == ModelState.Connected);

            SigningModelRequest negotiateRequest = ModelHelper.RetrieveOutstandingRequest<SigningModelRequest>(ref Request);

            if (negotiateRequest.signingFlagType == SigningFlagType.SignedFlagSet)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.2.4: If the SMB2 Header of the SMB2 NEGOTIATE request has the SMB2_FLAGS_SIGNED bit set in the Flags field, " +
                    "the server MUST fail the request with STATUS_INVALID_PARAMETER.");
                ModelHelper.Log(LogType.TestInfo, "SMB2_FLAGS_SIGNED bit in the NEGOTIATE request is set.");
                ModelHelper.Log(LogType.TestTag, TestTag.UnexpectedFields);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_INVALID_PARAMETER);
                State = ModelState.Uninitialized;

                return;
            }

            if (negotiateRequest.signingRequiredType == SigningRequiredType.SigningRequiredSet)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.4: If SMB2_NEGOTIATE_SIGNING_REQUIRED is set in SecurityMode, the server MUST set Connection.ShouldSign to TRUE.");
                ModelHelper.Log(LogType.TestInfo, "Connection.ShouldSign is set to TRUE.");
                Connection_ShouldSign = true;
            }

            ModelHelper.Log(LogType.Requirement, "3.3.5.4: SecurityMode MUST have the SMB2_NEGOTIATE_SIGNING_ENABLED bit set.");
            Condition.IsTrue(signingEnabledType == SigningEnabledType.SigningEnabledSet);

            Condition.IsTrue(Config.IsServerSigningRequired == c.IsServerSigningRequired);
            if (Config.IsServerSigningRequired)
            {
                ModelHelper.Log(LogType.Requirement,
                    "3.3.5.4: If RequireMessageSigning is TRUE, the server MUST also set SMB2_NEGOTIATE_SIGNING_REQUIRED in the SecurityMode field.");
                ModelHelper.Log(LogType.TestInfo, "RequireMessageSigning is TRUE.");
                Condition.IsTrue(signingRequiredType == SigningRequiredType.SigningRequiredSet);
            }

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
        }
        public static void TreeDisconnectResponse(ModelSmb2Status status)
        {
            Condition.IsTrue(State == ModelState.Connected);

            ModelTreeMgmtTreeDisconnectRequest treeDisconnectRequest = ModelHelper.RetrieveOutstandingRequest<ModelTreeMgmtTreeDisconnectRequest>(ref Request);

            if (!Session_TreeConnectExist
                || treeDisconnectRequest.treeId != ModelTreeId.ValidExistTreeId)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.2.11: The server MUST look up the TreeConnect in Session.TreeConnectTable by using the TreeId in the SMB2 header of the request." +
                    " If no tree connect is found, the request MUST be failed with STATUS_NETWORK_NAME_DELETED");
                ModelHelper.Log(
                    LogType.TestInfo,
                    "TreeConnect {0} in Session.TreeConnectTable, tree id is {1}",
                    Session_TreeConnectExist ? "exists" : "does not exist", treeDisconnectRequest.treeId);
                ModelHelper.Log(LogType.TestTag, TestTag.InvalidIdentifier);
                Condition.IsTrue(status == ModelSmb2Status.STATUS_NETWORK_NAME_DELETED);
                return;
            }

            ModelHelper.Log(
                LogType.Requirement,
                "3.3.5.8: The tree connect MUST then be removed from Session.TreeConnectTable and freed");

            Condition.IsTrue(status == ModelSmb2Status.STATUS_SUCCESS);
            Session_TreeConnectExist = false;

            ModelHelper.Log(
                LogType.TestInfo,
                "TreeConnect is removed from Session.TreeConnectTable");
        }
        public static void CreateResponse(ModelSmb2Status status, ReturnLeaseContextType returnLeaseContextType, uint leaseState, 
            LeaseFlagsValues leaseFlags, LeasingConfig c)
        {
            Condition.IsTrue(state == ModelState.Connected);

            ModelCreateLeaseRequest createRequest = ModelHelper.RetrieveOutstandingRequest<ModelCreateLeaseRequest>(ref request);

            Condition.IsTrue(config.IsDirectoryLeasingSupported == c.IsDirectoryLeasingSupported);
            Condition.IsTrue(config.IsLeasingSupported == c.IsLeasingSupported);

            if (!c.IsLeasingSupported)
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server does not support leasing and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST ignore the \"RqLs\" create context.");
                ModelHelper.Log(LogType.TestInfo, "The above conditions are met.");
                ModelHelper.Log(LogType.TestTag, TestTag.Compatibility);
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextNotIncluded);
                return;
            }

            if ((negotiateDialect == DialectRevision.Smb21 || Smb2Utility.IsSmb3xFamily(negotiateDialect))
                && c.IsLeasingSupported
                && (createRequest.ContextType == LeaseContextType.LeaseV1)) // the DataLength field equals 0x20
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server supports leasing, the name of the create context is \"RqLs\" as defined in section 2.2.13.2, " +
                    "and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:");
                ModelHelper.Log(
                    LogType.Requirement,
                    "\tIf Connection.Dialect is \"2.100\" or belongs to the \"3.x\" dialect family, and the DataLength field equals 0x20, " +
                        "the server MUST attempt to acquire a lease on the open from the underlying object store as described in section 3.3.5.9.8.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");

                // 3.3.5.9.8   Handling the SMB2_CREATE_REQUEST_LEASE Create Context
                #region Handle SMB2_CREATE_REQUEST_LEASE
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextIncluded);
                ModelCreateRequestLease requestLease = null;

                requestLease = createRequest.LeaseContext as ModelCreateRequestLease;

                smb2Lease = new Smb2Lease();
                if (Smb2Utility.IsSmb3xFamily(negotiateDialect))
                {
                    ModelHelper.Log(LogType.Requirement, "3.3.5.9.8: If Connection.Dialect belongs to the SMB 3.x dialect family, Lease.Version is set to 1.");
                    smb2Lease.Version = 1;
                }

                if (requestLease.LeaseState != smb2Lease.LeaseState && ((~requestLease.LeaseState) & smb2Lease.LeaseState) == 0 && !smb2Lease.Breaking)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.8: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE, " +
                        "the server MUST request promotion of the lease state from the underlying object store to the new caching state.");
                    ModelHelper.Log(LogType.TestInfo, "The above conditions are met.");
                    //If the object store succeeds this request, Lease.LeaseState MUST be set to the new caching state.
                    smb2Lease.LeaseState = requestLease.LeaseState;
                }

                // LeaseState MUST be set to Lease.LeaseState.
                Condition.IsTrue((uint)leaseState == smb2Lease.LeaseState);
                #endregion

                Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
                return;
            }

            if (Smb2Utility.IsSmb3xFamily(negotiateDialect)
                && c.IsLeasingSupported
                && (createRequest.ContextType == LeaseContextType.LeaseV2)) // the DataLength field equals 0x34
            {
                ModelHelper.Log(
                    LogType.Requirement,
                    "3.3.5.9: If the server supports leasing, the name of the create context is \"RqLs\" as defined in section 2.2.13.2, " +
                    "and RequestedOplockLevel is set to SMB2_OPLOCK_LEVEL_LEASE, the server MUST do the following:");
                ModelHelper.Log(
                    LogType.Requirement,
                    "\tIf Connection.Dialect belongs to the \"3.x\" dialect family, and the DataLength field equals 0x34, " +
                    "the server MUST attempt to acquire a lease on the open from the underlying object store, as described in section 3.3.5.9.11.");
                ModelHelper.Log(LogType.TestInfo, "All the above conditions are met.");

                // 3.3.5.9.11   Handling the SMB2_CREATE_REQUEST_LEASE_V2 Create Context
                #region Handle SMB2_CREATE_REQUEST_LEASE_V2
                Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextIncluded);
                ModelCreateRequestLeaseV2 requestLease = null;

                requestLease = createRequest.LeaseContext as ModelCreateRequestLeaseV2;

                smb2Lease = new Smb2Lease(2);

                // To reduce parameters and states, use CreateOptions instead of FileAttributes here, as we assume settings in CreateOptions and FileAtributes are consistent.
                if (createRequest.CreateOptions.HasFlag(CreateOptions_Values.FILE_DIRECTORY_FILE)
                    && (requestLease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING) != 0)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.11: If the FileAttributes field in the request indicates that this operation is on a directory and " +
                        "LeaseState includes SMB2_LEASE_WRITE_CACHING, the server MUST clear the bit SMB2_LEASE_WRITE_CACHING in the LeaseState field.");
                    ModelHelper.Log(LogType.TestInfo, "SMB2_LEASE_WRITE_CACHING is cleared.");
                    requestLease.LeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING;
                }

                if (requestLease.LeaseState != smb2Lease.LeaseState && ((~requestLease.LeaseState) & smb2Lease.LeaseState) == 0 && !smb2Lease.Breaking)
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.8: If the lease state requested is a superset of Lease.LeaseState and Lease.Breaking is FALSE, " +
                        "the server MUST request promotion of the lease state from the underlying object store to the new caching state.<271> " +
                        "If the object store succeeds this request, Lease.LeaseState MUST be set to the new caching state.");
                    smb2Lease.LeaseState = requestLease.LeaseState;
                    // The server MUST increment Lease.Epoch by 1.
                    ModelHelper.Log(LogType.TestInfo, "Lease.Epoch is incremented by 1.");
                    smb2Lease.Epoch++;
                }

                // LeaseState MUST be set to Lease.LeaseState.
                Condition.IsTrue((uint)leaseState == smb2Lease.LeaseState);

                if (requestLease.LeaseFlags.HasFlag(LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET))
                {
                    ModelHelper.Log(
                        LogType.Requirement,
                        "3.3.5.9.11: If SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit is set in the Flags field of the request, " +
                        "ParentLeaseKey MUST be set to the ParentLeaseKey in the request and SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit MUST be set in the Flags field of the response.");
                    ModelHelper.Log(LogType.TestInfo, "SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET bit is set.");
                    Condition.IsTrue(leaseFlags.HasFlag(LeaseFlagsValues.SMB2_LEASE_FLAG_PARENT_LEASE_KEY_SET));
                }
                #endregion

                Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
                return;
            }

            Condition.IsTrue(returnLeaseContextType == ReturnLeaseContextType.ReturnLeaseContextNotIncluded);
            Condition.IsTrue(leaseState == (uint)LeaseStateValues.SMB2_LEASE_NONE);
            Condition.IsTrue(leaseFlags == LeaseFlagsValues.NONE);
            Condition.IsTrue(status == Smb2Status.STATUS_SUCCESS);
        }