diff --git a/SMBLibrary/Server/ConnectionState/SMB2ConnectionState.cs b/SMBLibrary/Server/ConnectionState/SMB2ConnectionState.cs index fe56eae..e9273f4 100644 --- a/SMBLibrary/Server/ConnectionState/SMB2ConnectionState.cs +++ b/SMBLibrary/Server/ConnectionState/SMB2ConnectionState.cs @@ -12,18 +12,14 @@ using Utilities; namespace SMBLibrary.Server { - public delegate ulong? AllocatePersistentFileID(); - internal class SMB2ConnectionState : ConnectionState { // Key is SessionID private Dictionary m_sessions = new Dictionary(); private ulong m_nextSessionID = 1; - public AllocatePersistentFileID AllocatePersistentFileID; - public SMB2ConnectionState(ConnectionState state, AllocatePersistentFileID allocatePersistentFileID) : base(state) + public SMB2ConnectionState(ConnectionState state) : base(state) { - AllocatePersistentFileID = allocatePersistentFileID; } public ulong? AllocateSessionID() diff --git a/SMBLibrary/Server/ConnectionState/SMB2Session.cs b/SMBLibrary/Server/ConnectionState/SMB2Session.cs index 01d412c..1cee357 100644 --- a/SMBLibrary/Server/ConnectionState/SMB2Session.cs +++ b/SMBLibrary/Server/ConnectionState/SMB2Session.cs @@ -24,10 +24,11 @@ namespace SMBLibrary.Server private Dictionary m_connectedTrees = new Dictionary(); private uint m_nextTreeID = 1; // TreeID uniquely identifies a tree connect within the scope of the session - // Key is the persistent portion of the FileID + // Key is the volatile portion of the FileID private Dictionary m_openFiles = new Dictionary(); + private ulong m_nextVolatileFileID = 1; - // Key is the persistent portion of the FileID + // Key is the volatile portion of the FileID private Dictionary m_openSearches = new Dictionary(); public SMB2Session(SMB2ConnectionState connection, ulong sessionID, string userName, string machineName, byte[] sessionKey, object accessToken) @@ -107,39 +108,58 @@ namespace SMBLibrary.Server return m_connectedTrees.ContainsKey(treeID); } - /// The persistent portion of the FileID - public ulong? AddOpenFile(uint treeID, string relativePath, object handle) + // VolatileFileID MUST be unique for all volatile handles within the scope of a session + private ulong? AllocateVolatileFileID() { - ulong? persistentID = m_connection.AllocatePersistentFileID(); - if (persistentID.HasValue) + for (ulong offset = 0; offset < UInt64.MaxValue; offset++) { - lock (m_openFiles) + ulong volatileFileID = (ulong)(m_nextVolatileFileID + offset); + if (volatileFileID == 0 || volatileFileID == 0xFFFFFFFFFFFFFFFF) { - m_openFiles.Add(persistentID.Value, new OpenFileObject(treeID, relativePath, handle)); + continue; + } + if (!m_openFiles.ContainsKey(volatileFileID)) + { + m_nextVolatileFileID = (ulong)(volatileFileID + 1); + return volatileFileID; } } - return persistentID; + return null; } - public OpenFileObject GetOpenFileObject(ulong fileID) + public FileID? AddOpenFile(uint treeID, string relativePath, object handle) { - if (m_openFiles.ContainsKey(fileID)) + ulong? volatileFileID = AllocateVolatileFileID(); + if (volatileFileID.HasValue) { - return m_openFiles[fileID]; - } - else - { - return null; + FileID fileID = new FileID(); + fileID.Volatile = volatileFileID.Value; + // [MS-SMB2] FileId.Persistent MUST be set to Open.DurableFileId. + // Note: We don't support durable handles so we use volatileFileID. + fileID.Persistent = volatileFileID.Value; + lock (m_openFiles) + { + m_openFiles.Add(volatileFileID.Value, new OpenFileObject(treeID, relativePath, handle)); + } + return fileID; } + return null; } - public void RemoveOpenFile(ulong fileID) + public OpenFileObject GetOpenFileObject(FileID fileID) + { + OpenFileObject result; + m_openFiles.TryGetValue(fileID.Volatile, out result); + return result; + } + + public void RemoveOpenFile(FileID fileID) { lock (m_openFiles) { - m_openFiles.Remove(fileID); + m_openFiles.Remove(fileID.Volatile); } - m_openSearches.Remove(fileID); + m_openSearches.Remove(fileID.Volatile); } public List ListOpenFiles() @@ -155,23 +175,23 @@ namespace SMBLibrary.Server return result; } - public OpenSearch AddOpenSearch(ulong fileID, List entries, int enumerationLocation) + public OpenSearch AddOpenSearch(FileID fileID, List entries, int enumerationLocation) { OpenSearch openSearch = new OpenSearch(entries, enumerationLocation); - m_openSearches.Add(fileID, openSearch); + m_openSearches.Add(fileID.Volatile, openSearch); return openSearch; } - public OpenSearch GetOpenSearch(ulong fileID) + public OpenSearch GetOpenSearch(FileID fileID) { OpenSearch openSearch; - m_openSearches.TryGetValue(fileID, out openSearch); + m_openSearches.TryGetValue(fileID.Volatile, out openSearch); return openSearch; } - public void RemoveOpenSearch(ulong fileID) + public void RemoveOpenSearch(FileID fileID) { - m_openSearches.Remove(fileID); + m_openSearches.Remove(fileID.Volatile); } /// diff --git a/SMBLibrary/Server/SMB2/CloseHelper.cs b/SMBLibrary/Server/SMB2/CloseHelper.cs index cce2d1b..4f64a07 100644 --- a/SMBLibrary/Server/SMB2/CloseHelper.cs +++ b/SMBLibrary/Server/SMB2/CloseHelper.cs @@ -17,13 +17,13 @@ namespace SMBLibrary.Server.SMB2 internal static SMB2Command GetCloseResponse(CloseRequest request, ISMBShare share, SMB2ConnectionState state) { SMB2Session session = state.GetSession(request.Header.SessionID); - OpenFileObject openFile = session.GetOpenFileObject(request.FileId.Persistent); + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); } share.FileStore.CloseFile(openFile.Handle); - session.RemoveOpenFile(request.FileId.Persistent); + session.RemoveOpenFile(request.FileId); CloseResponse response = new CloseResponse(); if (request.PostQueryAttributes) { diff --git a/SMBLibrary/Server/SMB2/CreateHelper.cs b/SMBLibrary/Server/SMB2/CreateHelper.cs index 5a9c23a..3e303b1 100644 --- a/SMBLibrary/Server/SMB2/CreateHelper.cs +++ b/SMBLibrary/Server/SMB2/CreateHelper.cs @@ -40,8 +40,8 @@ namespace SMBLibrary.Server.SMB2 return new ErrorResponse(request.CommandName, createStatus); } - ulong? persistentFileID = session.AddOpenFile(request.Header.TreeID, path, handle); - if (!persistentFileID.HasValue) + FileID? fileID = session.AddOpenFile(request.Header.TreeID, path, handle); + if (fileID == null) { share.FileStore.CloseFile(handle); return new ErrorResponse(request.CommandName, NTStatus.STATUS_TOO_MANY_OPENED_FILES); @@ -49,12 +49,12 @@ namespace SMBLibrary.Server.SMB2 if (share is NamedPipeShare) { - return CreateResponseForNamedPipe(persistentFileID.Value, FileStatus.FILE_OPENED); + return CreateResponseForNamedPipe(fileID.Value, FileStatus.FILE_OPENED); } else { FileNetworkOpenInformation fileInfo = NTFileStoreHelper.GetNetworkOpenInformation(share.FileStore, handle); - CreateResponse response = CreateResponseFromFileSystemEntry(fileInfo, persistentFileID.Value, fileStatus); + CreateResponse response = CreateResponseFromFileSystemEntry(fileInfo, fileID.Value, fileStatus); if (request.RequestedOplockLevel == OplockLevel.Batch) { response.OplockLevel = OplockLevel.Batch; @@ -63,16 +63,16 @@ namespace SMBLibrary.Server.SMB2 } } - private static CreateResponse CreateResponseForNamedPipe(ulong persistentFileID, FileStatus fileStatus) + private static CreateResponse CreateResponseForNamedPipe(FileID fileID, FileStatus fileStatus) { CreateResponse response = new CreateResponse(); response.CreateAction = (CreateAction)fileStatus; response.FileAttributes = FileAttributes.Normal; - response.FileId.Persistent = persistentFileID; + response.FileId = fileID; return response; } - private static CreateResponse CreateResponseFromFileSystemEntry(FileNetworkOpenInformation fileInfo, ulong persistentFileID, FileStatus fileStatus) + private static CreateResponse CreateResponseFromFileSystemEntry(FileNetworkOpenInformation fileInfo, FileID fileID, FileStatus fileStatus) { CreateResponse response = new CreateResponse(); response.CreateAction = (CreateAction)fileStatus; @@ -83,7 +83,7 @@ namespace SMBLibrary.Server.SMB2 response.AllocationSize = fileInfo.AllocationSize; response.EndofFile = fileInfo.EndOfFile; response.FileAttributes = fileInfo.FileAttributes; - response.FileId.Persistent = persistentFileID; + response.FileId = fileID; return response; } } diff --git a/SMBLibrary/Server/SMB2/IOCtlHelper.cs b/SMBLibrary/Server/SMB2/IOCtlHelper.cs index 99148be..e3f229b 100644 --- a/SMBLibrary/Server/SMB2/IOCtlHelper.cs +++ b/SMBLibrary/Server/SMB2/IOCtlHelper.cs @@ -24,7 +24,7 @@ namespace SMBLibrary.Server.SMB2 return new ErrorResponse(request.CommandName, NTStatus.STATUS_FS_DRIVER_REQUIRED); } - OpenFileObject openFile = session.GetOpenFileObject(request.FileId.Persistent); + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); object handle; if (openFile == null) { diff --git a/SMBLibrary/Server/SMB2/QueryDirectoryHelper.cs b/SMBLibrary/Server/SMB2/QueryDirectoryHelper.cs index 8e1eb0a..93a7319 100644 --- a/SMBLibrary/Server/SMB2/QueryDirectoryHelper.cs +++ b/SMBLibrary/Server/SMB2/QueryDirectoryHelper.cs @@ -17,7 +17,7 @@ namespace SMBLibrary.Server.SMB2 internal static SMB2Command GetQueryDirectoryResponse(QueryDirectoryRequest request, ISMBShare share, SMB2ConnectionState state) { SMB2Session session = state.GetSession(request.Header.SessionID); - OpenFileObject openFile = session.GetOpenFileObject(request.FileId.Persistent); + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); @@ -30,7 +30,7 @@ namespace SMBLibrary.Server.SMB2 FileSystemShare fileSystemShare = (FileSystemShare)share; - ulong fileID = request.FileId.Persistent; + FileID fileID = request.FileId; OpenSearch openSearch = session.GetOpenSearch(fileID); if (openSearch == null || request.Reopen) { diff --git a/SMBLibrary/Server/SMB2/QueryInfoHelper.cs b/SMBLibrary/Server/SMB2/QueryInfoHelper.cs index 8a9279d..e7004ff 100644 --- a/SMBLibrary/Server/SMB2/QueryInfoHelper.cs +++ b/SMBLibrary/Server/SMB2/QueryInfoHelper.cs @@ -19,7 +19,7 @@ namespace SMBLibrary.Server.SMB2 SMB2Session session = state.GetSession(request.Header.SessionID); if (request.InfoType == InfoType.File) { - OpenFileObject openFile = session.GetOpenFileObject(request.FileId.Persistent); + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); diff --git a/SMBLibrary/Server/SMB2/ReadWriteResponseHelper.cs b/SMBLibrary/Server/SMB2/ReadWriteResponseHelper.cs index 6906527..dd5f0ad 100644 --- a/SMBLibrary/Server/SMB2/ReadWriteResponseHelper.cs +++ b/SMBLibrary/Server/SMB2/ReadWriteResponseHelper.cs @@ -17,7 +17,7 @@ namespace SMBLibrary.Server.SMB2 internal static SMB2Command GetReadResponse(ReadRequest request, ISMBShare share, SMB2ConnectionState state) { SMB2Session session = state.GetSession(request.Header.SessionID); - OpenFileObject openFile = session.GetOpenFileObject(request.FileId.Persistent); + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); @@ -37,7 +37,7 @@ namespace SMBLibrary.Server.SMB2 internal static SMB2Command GetWriteResponse(WriteRequest request, ISMBShare share, SMB2ConnectionState state) { SMB2Session session = state.GetSession(request.Header.SessionID); - OpenFileObject openFile = session.GetOpenFileObject(request.FileId.Persistent); + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); diff --git a/SMBLibrary/Server/SMB2/SetInfoHelper.cs b/SMBLibrary/Server/SMB2/SetInfoHelper.cs index 02ffb3c..4b7dccd 100644 --- a/SMBLibrary/Server/SMB2/SetInfoHelper.cs +++ b/SMBLibrary/Server/SMB2/SetInfoHelper.cs @@ -19,7 +19,7 @@ namespace SMBLibrary.Server.SMB2 SMB2Session session = state.GetSession(request.Header.SessionID); if (request.InfoType == InfoType.File) { - OpenFileObject openFile = session.GetOpenFileObject(request.FileId.Persistent); + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); diff --git a/SMBLibrary/Server/SMBServer.SMB2.cs b/SMBLibrary/Server/SMBServer.SMB2.cs index ed15417..dd97e11 100644 --- a/SMBLibrary/Server/SMBServer.SMB2.cs +++ b/SMBLibrary/Server/SMBServer.SMB2.cs @@ -15,28 +15,6 @@ namespace SMBLibrary.Server { public partial class SMBServer { - // Key is the persistent portion of the FileID - private Dictionary m_globalOpenFiles = new Dictionary(); - private static ulong m_nextPersistentFileID = 1; // A numeric value that uniquely identifies the open handle to a file or a pipe within the scope of all opens granted by the server - - private ulong? AllocatePersistentFileID() - { - for (ulong offset = 0; offset < UInt64.MaxValue; offset++) - { - ulong persistentID = (ulong)(m_nextPersistentFileID + offset); - if (persistentID == 0 || persistentID == 0xFFFFFFFFFFFFFFFF) - { - continue; - } - if (!m_globalOpenFiles.ContainsKey(persistentID)) - { - m_nextPersistentFileID = (ulong)(persistentID + 1); - return persistentID; - } - } - return null; - } - private void ProcessSMB2RequestChain(List requestChain, ref ConnectionState state) { List responseChain = new List(); @@ -77,7 +55,7 @@ namespace SMBLibrary.Server SMB2Command response = NegotiateHelper.GetNegotiateResponse(request, m_securityProvider, state, m_serverGuid, m_serverStartTime); if (state.Dialect != SMBDialect.NotSet) { - state = new SMB2ConnectionState(state, AllocatePersistentFileID); + state = new SMB2ConnectionState(state); m_connectionManager.AddConnection(state); } return response; @@ -188,7 +166,7 @@ namespace SMBLibrary.Server else if (command is FlushRequest) { FlushRequest request = (FlushRequest)command; - OpenFileObject openFile = session.GetOpenFileObject(request.FileId.Persistent); + OpenFileObject openFile = session.GetOpenFileObject(request.FileId); if (openFile == null) { return new ErrorResponse(request.CommandName, NTStatus.STATUS_FILE_CLOSED); diff --git a/SMBLibrary/Server/SMBServer.cs b/SMBLibrary/Server/SMBServer.cs index 0a7272e..cca44a9 100644 --- a/SMBLibrary/Server/SMBServer.cs +++ b/SMBLibrary/Server/SMBServer.cs @@ -272,7 +272,7 @@ namespace SMBLibrary.Server SMB2Command response = SMB2.NegotiateHelper.GetNegotiateResponse(smb2Dialects, m_securityProvider, state, m_serverGuid, m_serverStartTime); if (state.Dialect != SMBDialect.NotSet) { - state = new SMB2ConnectionState(state, AllocatePersistentFileID); + state = new SMB2ConnectionState(state); m_connectionManager.AddConnection(state); } EnqueueResponse(state, response);