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"); }
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); }
/// <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); }
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> /// 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); }
/// <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); }
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 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); }