public void ReadConfig(out LeasingConfig c) { uncSharePath = Smb2Utility.GetUncPath(testConfig.SutIPAddress.ToString(), testConfig.BasicFileShare); c = new LeasingConfig { MaxSmbVersionSupported = ModelUtility.GetModelDialectRevision(testConfig.MaxSmbVersionSupported), IsLeasingSupported = testConfig.IsLeasingSupported, IsDirectoryLeasingSupported = testConfig.IsDirectoryLeasingSupported, }; leasingConfig = c; Site.Log.Add(LogEntryKind.Debug, leasingConfig.ToString()); }
public void FileOperationToBreakLeaseRequest(FileOperation operation, OperatorType operatorType, ModelDialectRevision dialect, out LeasingConfig c) { c = leasingConfig; LeasingClientInfo clientInfo = clients[(int)operatorType]; // Avoid to fail because Windows issue if (dialect == ModelDialectRevision.Smb2002) { clientInfo.ClientGuid = Guid.NewGuid(); } if (!clientInfo.IsInitialized) { InitializeClient(clientInfo, dialect); } if (operation == FileOperation.WRITE_DATA) { #region WRITE_DATA uint status = Smb2Status.STATUS_SUCCESS; Packet_Header header; CREATE_Response createResponse; Smb2CreateContextResponse[] serverCreateContexts; if (!clientInfo.IsOpened) { status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN_IF, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts, out clientInfo.FileId, out serverCreateContexts, out header, out createResponse); Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds."); } byte[] data = Encoding.ASCII.GetBytes("Write data to break READ caching."); ushort creditCharge = Smb2Utility.CalculateCreditCharge((uint)data.Length, ModelUtility.GetDialectRevision(dialect)); clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.WriteRequest(creditCharge, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, 0, clientInfo.FileId, Channel_Values.CHANNEL_NONE, WRITE_Request_Flags_Values.None, new byte[0], data); clientInfo.MessageId += (ulong)creditCharge; #endregion } else if (operation == FileOperation.SIZE_CHANGED) { #region SIZE_CHANGED uint status = Smb2Status.STATUS_SUCCESS; Packet_Header header; CREATE_Response createResponse; Smb2CreateContextResponse[] serverCreateContexts; if (!clientInfo.IsOpened) { status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts, out clientInfo.FileId, out serverCreateContexts, out header, out createResponse); Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds."); } FileEndOfFileInformation changeSizeInfo; changeSizeInfo.EndOfFile = 512; byte[] inputBuffer; inputBuffer = TypeMarshal.ToBytes<FileEndOfFileInformation>(changeSizeInfo); clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.SetInfoRequest( 1, 1, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, SET_INFO_Request_InfoType_Values.SMB2_0_INFO_FILE, (byte)FileInformationClasses.FileEndOfFileInformation, SET_INFO_Request_AdditionalInformation_Values.NONE, clientInfo.FileId, inputBuffer); #endregion } else if (operation == FileOperation.RANGE_LOCK) { #region RANGE_LOCK uint status = Smb2Status.STATUS_SUCCESS; Packet_Header header; CREATE_Response createResponse; Smb2CreateContextResponse[] serverCreateContexts; if (!clientInfo.IsOpened) { status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts, out clientInfo.FileId, out serverCreateContexts, out header, out createResponse); Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds."); } clientInfo.Locks = new LOCK_ELEMENT[1]; clientInfo.LockSequence = 0; clientInfo.Locks[0].Offset = 0; clientInfo.Locks[0].Length = (ulong)1 * 1024 / 2; clientInfo.Locks[0].Flags = LOCK_ELEMENT_Flags_Values.LOCKFLAG_SHARED_LOCK; clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.LockRequest( 1, 1, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, clientInfo.LockSequence++, clientInfo.FileId, clientInfo.Locks ); #endregion } else if (operation == FileOperation.OPEN_OVERWRITE) { #region OPEN_OVERWRITE if (clientInfo.IsOpened) { clientInfo.Reset(operatorType == OperatorType.SecondClient); InitializeClient(clientInfo, dialect); } clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.CreateRequest(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OVERWRITE, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts); #endregion } else if (operation == FileOperation.OPEN_WITHOUT_OVERWRITE) { #region OPEN_WITHOUT_OVERWRITE if (clientInfo.IsOpened) { clientInfo.Reset(operatorType == OperatorType.SecondClient); InitializeClient(clientInfo, dialect); } if (!clientInfo.IsOpened) { clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.CreateRequest(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts); } #endregion } else if (operation == FileOperation.OPEN_SHARING_VIOLATION) { #region OPEN_SHARING_VIOLATION if (clientInfo.IsOpened) { clientInfo.Reset(operatorType == OperatorType.SecondClient); InitializeClient(clientInfo, dialect); } if (!clientInfo.IsOpened) { clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.CreateRequest(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ, originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts); } #endregion } else if (operation == FileOperation.OPEN_SHARING_VIOLATION_WITH_OVERWRITE) { #region OPEN_SHARING_VIOLATION_WITH_OVERWRITE if (clientInfo.IsOpened) { clientInfo.Reset(operatorType == OperatorType.SecondClient); InitializeClient(clientInfo, dialect); } if (!clientInfo.IsOpened) { clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.CreateRequest(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ, originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OVERWRITE, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts); } #endregion } else if (operation == FileOperation.DELETED) { #region DELETED if (clientInfo.IsOpened) { clientInfo.Reset(operatorType == OperatorType.SecondClient); InitializeClient(clientInfo, dialect); } uint status = Smb2Status.STATUS_SUCCESS; Packet_Header header; CREATE_Response createResponse; Smb2CreateContextResponse[] serverCreateContexts; if (!clientInfo.IsOpened) { clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, (originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE) | CreateOptions_Values.FILE_DELETE_ON_CLOSE, CreateDisposition_Values.FILE_OPEN, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts, out clientInfo.FileId, out serverCreateContexts, out header, out createResponse); Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds."); } FileDispositionInformation deleteInfo; deleteInfo.DeletePending = 1; byte[] inputBuffer; inputBuffer = TypeMarshal.ToBytes<FileDispositionInformation>(deleteInfo); clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.SetInfoRequest( 1, 1, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, SET_INFO_Request_InfoType_Values.SMB2_0_INFO_FILE, (byte)FileInformationClasses.FileDispositionInformation, SET_INFO_Request_AdditionalInformation_Values.NONE, clientInfo.FileId, inputBuffer); #endregion } else if (operation == FileOperation.RENAMEED) { #region RENAMEED if (clientInfo.IsOpened) { clientInfo.Reset(operatorType == OperatorType.SecondClient); InitializeClient(clientInfo, dialect); } uint status = Smb2Status.STATUS_SUCCESS; Packet_Header header; CREATE_Response createResponse; Smb2CreateContextResponse[] serverCreateContexts; if (!clientInfo.IsOpened) { status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.File, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, originalClient.IsDirectory ? CreateOptions_Values.FILE_DIRECTORY_FILE : CreateOptions_Values.FILE_NON_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, clientInfo.CreateContexts == null ? RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE : RequestedOplockLevel_Values.OPLOCK_LEVEL_LEASE, clientInfo.CreateContexts, out clientInfo.FileId, out serverCreateContexts, out header, out createResponse); Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds."); } string newFileName = originalClient.ParentDirectory + "\\" + Guid.NewGuid().ToString(); FileRenameInformation info = new FileRenameInformation(); info.ReplaceIfExists = 1; info.FileName = ConvertStringToByteArray(newFileName); info.FileNameLength = (uint)info.FileName.Length; info.RootDirectory = FileRenameInformation_RootDirectory_Values.V1; info.Reserved = new byte[7]; byte[] inputBuffer; inputBuffer = TypeMarshal.ToBytes<FileRenameInformation>(info); clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.SetInfoRequest( 1, 1, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, SET_INFO_Request_InfoType_Values.SMB2_0_INFO_FILE, (byte)FileInformationClasses.FileRenameInformation, SET_INFO_Request_AdditionalInformation_Values.NONE, clientInfo.FileId, inputBuffer); originalClient.File = newFileName; #endregion } else if (operation == FileOperation.PARENT_DIR_RENAMED) { #region PARENT_DIR_RENAMED if (clientInfo.IsOpened) { clientInfo.Reset(operatorType == OperatorType.SecondClient); InitializeClient(clientInfo, dialect); } uint status = Smb2Status.STATUS_SUCCESS; Packet_Header header; CREATE_Response createResponse; Smb2CreateContextResponse[] serverCreateContexts; if (!clientInfo.IsOpened) { status = clientInfo.Client.Create(1, 64, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, originalClient.ParentDirectory, AccessMask.GENERIC_READ | AccessMask.GENERIC_WRITE | AccessMask.DELETE, ShareAccess_Values.FILE_SHARE_READ | ShareAccess_Values.FILE_SHARE_WRITE | ShareAccess_Values.FILE_SHARE_DELETE, CreateOptions_Values.FILE_DIRECTORY_FILE, CreateDisposition_Values.FILE_OPEN, File_Attributes.NONE, ImpersonationLevel_Values.Impersonation, SecurityFlags_Values.NONE, RequestedOplockLevel_Values.OPLOCK_LEVEL_NONE, null, out clientInfo.FileId, out serverCreateContexts, out header, out createResponse); Site.Assert.AreEqual(Smb2Status.STATUS_SUCCESS, status, "Expect that creation succeeds."); } string newFileName = "LeasingDir_" + Guid.NewGuid().ToString(); FileRenameInformation info = new FileRenameInformation(); info.ReplaceIfExists = 0; info.FileName = ConvertStringToByteArray(newFileName); info.FileNameLength = (uint)info.FileName.Length; info.RootDirectory = FileRenameInformation_RootDirectory_Values.V1; info.Reserved = new byte[7]; byte[] inputBuffer; inputBuffer = TypeMarshal.ToBytes<FileRenameInformation>(info); clientInfo.LastOperationMessageId = clientInfo.MessageId; clientInfo.Client.SetInfoRequest( 1, 1, clientInfo.Flags, clientInfo.MessageId++, clientInfo.SessionId, clientInfo.TreeId, SET_INFO_Request_InfoType_Values.SMB2_0_INFO_FILE, (byte)FileInformationClasses.FileRenameInformation, SET_INFO_Request_AdditionalInformation_Values.NONE, clientInfo.FileId, inputBuffer); // Does not need to update these two fields File and ParentDirectory in orginal client because the operation will fail. #endregion } lastOperation = new BreakOperation(operation, operatorType); }
public static void FileOperationToBreakLeaseRequestReturn(LeasingConfig c) { Condition.IsTrue(state == ModelState.Connected); ModelFileOperationRequest fileOperationRequest = ModelHelper.RetrieveOutstandingRequest<ModelFileOperationRequest>(ref request); Condition.IsFalse(negotiateDialect == DialectRevision.Smb2002); Condition.IsTrue(config.IsDirectoryLeasingSupported == c.IsDirectoryLeasingSupported); Condition.IsTrue(config.IsLeasingSupported == c.IsLeasingSupported); Condition.IsTrue(c.IsLeasingSupported || c.IsDirectoryLeasingSupported); Condition.IsTrue(config.MaxSmbVersionSupported == c.MaxSmbVersionSupported); // 3.3.1.4 Algorithm for Leasing in an Object Store smb2Lease.BreakToLeaseState = smb2Lease.LeaseState; if (fileOperationRequest.OptorType != OperatorType.SameClientId) { ModelHelper.Log( LogType.Requirement, "3.3.1.4: READ caching permits the SMB2 client to cache data read from the object. Before processing one of the following operations from a client with a different ClientId, " + "the object store MUST request that the server revoke READ caching. The object store is not required to wait for acknowledgment:"); if ((smb2Lease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_READ_CACHING) != 0 && ((fileOperationRequest.Operation == FileOperation.OPEN_OVERWRITE) || (fileOperationRequest.Operation == FileOperation.WRITE_DATA) || (fileOperationRequest.Operation == FileOperation.SIZE_CHANGED) || (fileOperationRequest.Operation == FileOperation.RANGE_LOCK))) { ModelHelper.Log(LogType.Requirement, "READ caching on a file:"); ModelHelper.Log(LogType.Requirement, "\tThe file is opened in a manner that overwrites the existing file."); ModelHelper.Log(LogType.Requirement, "\tData is written to the file."); ModelHelper.Log(LogType.Requirement, "\tThe file size is changed."); ModelHelper.Log(LogType.Requirement, "\tA byte range lock is requested for the file."); ModelHelper.Log(LogType.TestInfo, "READ caching lease state is broken."); smb2Lease.BreakToLeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_READ_CACHING; } } if (fileOperationRequest.OptorType != OperatorType.SameClientId) { ModelHelper.Log( LogType.Requirement, "WRITE caching permits the SMB2 client to cache writes and byte-range locks on an object. " + "Before processing one of the following operations, the underlying object store MUST request that the server revoke WRITE caching, " + "and the object store MUST wait for acknowledgment from the server before proceeding with the operation:"); if ((smb2Lease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING) != 0 && fileOperationRequest.Operation != FileOperation.OPEN_SHARING_VIOLATION && fileOperationRequest.Operation != FileOperation.OPEN_SHARING_VIOLATION_WITH_OVERWRITE && fileOperationRequest.Operation != FileOperation.PARENT_DIR_RENAMED) { ModelHelper.Log( LogType.Requirement, "The file is opened by a local application or via another protocol, " + "or opened via SMB2 without providing the same ClientId, and requested access includes any flags other than FILE_READ_ATTRIBUTES, " + "FILE_WRITE_ATTRIBUTES, and SYNCHRONIZE."); ModelHelper.Log( LogType.TestInfo, "WRITE caching lease state is broken."); smb2Lease.BreakToLeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_WRITE_CACHING; } ModelHelper.Log( LogType.Requirement, "HANDLE caching permits one or more SMB2 clients to delay closing handles it holds open, " + "or to defer sending opens. Before processing one of the following operations, " + "the underlying object store MUST request that the server revoke HANDLE caching, " + "and the object store MUST wait for acknowledgment before proceeding with the operation:"); if ((smb2Lease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_HANDLE_CACHING) != 0 && (fileOperationRequest.Operation == FileOperation.OPEN_SHARING_VIOLATION || fileOperationRequest.Operation == FileOperation.OPEN_SHARING_VIOLATION_WITH_OVERWRITE || fileOperationRequest.Operation == FileOperation.RENAMEED || fileOperationRequest.Operation == FileOperation.DELETED || fileOperationRequest.Operation == FileOperation.PARENT_DIR_RENAMED)) { ModelHelper.Log(LogType.Requirement, "HANDLE caching on a file:"); ModelHelper.Log( LogType.Requirement, "\tA file is opened with an access or share mode incompatible with opens from different ClientIds " + "or local applications as described in [MS-FSA] section 2.1.5.1.2."); ModelHelper.Log(LogType.Requirement, "\tThe parent directory is being renamed."); ModelHelper.Log( LogType.TestInfo, "HANDLE caching lease state is broken."); smb2Lease.BreakToLeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_HANDLE_CACHING; } } // HANDLE caching permits one or more SMB2 clients to delay closing handles it holds open, or to defer sending opens. // Before processing one of the following operations, the underlying object store MUST request that the server revoke HANDLE caching, // and the object store MUST wait for acknowledgment before proceeding with the operation: // The parent directory is being renamed. if ((smb2Lease.LeaseState & (uint)LeaseStateValues.SMB2_LEASE_HANDLE_CACHING) != 0 && fileOperationRequest.Operation == FileOperation.PARENT_DIR_RENAMED) { smb2Lease.BreakToLeaseState &= ~(uint)LeaseStateValues.SMB2_LEASE_HANDLE_CACHING; } if (smb2Lease.BreakToLeaseState != smb2Lease.LeaseState) { if (smb2Lease.LeaseState != (uint)LeaseStateValues.SMB2_LEASE_READ_CACHING) { // 3.3.4.7 Object Store Indicates a Lease Break // The server MUST set Lease.Breaking to TRUE ModelHelper.Log(LogType.TestInfo, "Lease.Breaking is set to TRUE."); smb2Lease.Breaking = true; } // 3.3.4.7 Object Store Indicates a Lease Break if (ModelUtility.IsSmb3xFamily(c.MaxSmbVersionSupported) && smb2Lease.Version == 2) { ModelHelper.Log( LogType.Requirement, "3.3.4.7: If the server implements the SMB 3.x dialect family and Lease.Version is 2, the server MUST set NewEpoch to Lease.Epoch + 1. "); ModelHelper.Log(LogType.TestInfo, "The server implements the SMB 3.x dialect family and Lease.Version is 2."); smb2Lease.Epoch++; } // 3.3.1.4 Algorithm for Leasing in an Object Store // The algorithm SHOULD support the following combinations of caching flags on a file: // No caching, Read caching, Read + Write caching, Read + Handle caching, and Read + Write + Handle caching. if ((smb2Lease.BreakToLeaseState & (uint)LeaseStateValues.SMB2_LEASE_READ_CACHING) == 0) { ModelHelper.Log(LogType.TestInfo, "Lease state is set to No caching."); smb2Lease.BreakToLeaseState = 0; } } }
public static void ReadConfigReturn(LeasingConfig c) { Condition.IsTrue(state == ModelState.Uninitialized); Condition.IsNotNull(c); Condition.IsTrue(c.MaxSmbVersionSupported == ModelDialectRevision.Smb2002 || c.MaxSmbVersionSupported == ModelDialectRevision.Smb21 || c.MaxSmbVersionSupported == ModelDialectRevision.Smb30 || c.MaxSmbVersionSupported == ModelDialectRevision.Smb302); if (c.MaxSmbVersionSupported == ModelDialectRevision.Smb2002) { Condition.IsFalse(c.IsDirectoryLeasingSupported); Condition.IsFalse(c.IsLeasingSupported); } else if (c.MaxSmbVersionSupported == ModelDialectRevision.Smb21) { Condition.IsFalse(c.IsDirectoryLeasingSupported); } config = c; state = ModelState.Initialized; }
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); }