Improved session management logic

This commit is contained in:
Tal Aloni 2017-01-17 18:21:14 +02:00
parent 54efee89a4
commit 049cb5b104
14 changed files with 305 additions and 226 deletions

View file

@ -29,6 +29,7 @@ namespace SMBLibrary
STATUS_TOO_MANY_SESSIONS = 0xC00000CE, STATUS_TOO_MANY_SESSIONS = 0xC00000CE,
STATUS_TOO_MANY_OPENED_FILES = 0xC000011F, STATUS_TOO_MANY_OPENED_FILES = 0xC000011F,
STATUS_CANNOT_DELETE = 0xC0000121, STATUS_CANNOT_DELETE = 0xC0000121,
STATUS_USER_SESSION_DELETED = 0xC0000203,
STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205, STATUS_INSUFF_SERVER_RESOURCES = 0xC0000205,
STATUS_INVALID_SMB = 0x00010002, // CIFS/SMB1: A corrupt or invalid SMB request was received STATUS_INVALID_SMB = 0x00010002, // CIFS/SMB1: A corrupt or invalid SMB request was received

View file

@ -108,6 +108,7 @@
<Compile Include="Server\ConnectionState\OpenFileObject.cs" /> <Compile Include="Server\ConnectionState\OpenFileObject.cs" />
<Compile Include="Server\ConnectionState\ProcessStateObject.cs" /> <Compile Include="Server\ConnectionState\ProcessStateObject.cs" />
<Compile Include="Server\ConnectionState\SMB1ConnectionState.cs" /> <Compile Include="Server\ConnectionState\SMB1ConnectionState.cs" />
<Compile Include="Server\ConnectionState\SMB1Session.cs" />
<Compile Include="Server\Exceptions\EmptyPasswordNotAllowedException.cs" /> <Compile Include="Server\Exceptions\EmptyPasswordNotAllowedException.cs" />
<Compile Include="Server\Exceptions\InvalidRequestException.cs" /> <Compile Include="Server\Exceptions\InvalidRequestException.cs" />
<Compile Include="Server\Exceptions\UnsupportedInformationLevelException.cs" /> <Compile Include="Server\Exceptions\UnsupportedInformationLevelException.cs" />

View file

@ -18,24 +18,14 @@ namespace SMBLibrary.Server
public bool LargeWrite; public bool LargeWrite;
// Key is UID // Key is UID
private Dictionary<ushort, string> m_connectedUsers = new Dictionary<ushort, string>(); private Dictionary<ushort, SMB1Session> m_sessions = new Dictionary<ushort, SMB1Session>();
private ushort m_nextUID = 1; private ushort m_nextUID = 1; // UID MUST be unique within an SMB connection
private ushort m_nextTID = 1; // TID MUST be unique within an SMB connection
private ushort m_nextFID = 1; // FID MUST be unique within an SMB connection
// Key is TID // Key is PID (PID MUST be unique within an SMB connection)
private Dictionary<ushort, ISMBShare> m_connectedTrees = new Dictionary<ushort, ISMBShare>();
private ushort m_nextTID = 1;
// Key is FID
private Dictionary<ushort, OpenFileObject> m_openFiles = new Dictionary<ushort, OpenFileObject>();
private ushort m_nextFID = 1;
// Key is PID
private Dictionary<uint, ProcessStateObject> m_processStateList = new Dictionary<uint, ProcessStateObject>(); private Dictionary<uint, ProcessStateObject> m_processStateList = new Dictionary<uint, ProcessStateObject>();
private const int MaxSearches = 2048; // Windows servers initialize Server.MaxSearches to 2048.
public Dictionary<ushort, List<FileSystemEntry>> OpenSearches = new Dictionary<ushort, List<FileSystemEntry>>();
private ushort m_nextSearchHandle = 1;
public SMB1ConnectionState(ConnectionState state) : base(state) public SMB1ConnectionState(ConnectionState state) : base(state)
{ {
} }
@ -44,7 +34,7 @@ namespace SMBLibrary.Server
/// An open UID MUST be unique within an SMB connection. /// An open UID MUST be unique within an SMB connection.
/// The value of 0xFFFE SHOULD NOT be used as a valid UID. All other possible values for a UID, excluding zero (0x0000), are valid. /// The value of 0xFFFE SHOULD NOT be used as a valid UID. All other possible values for a UID, excluding zero (0x0000), are valid.
/// </summary> /// </summary>
private ushort? AllocateUserID() public ushort? AllocateUserID()
{ {
for (ushort offset = 0; offset < UInt16.MaxValue; offset++) for (ushort offset = 0; offset < UInt16.MaxValue; offset++)
{ {
@ -53,7 +43,7 @@ namespace SMBLibrary.Server
{ {
continue; continue;
} }
if (!m_connectedUsers.ContainsKey(userID)) if (!m_sessions.ContainsKey(userID))
{ {
m_nextUID = (ushort)(userID + 1); m_nextUID = (ushort)(userID + 1);
return userID; return userID;
@ -62,43 +52,41 @@ namespace SMBLibrary.Server
return null; return null;
} }
public ushort? AddConnectedUser(string userName) public SMB1Session CreateSession(ushort userID, string userName)
{
SMB1Session session = new SMB1Session(this, userID, userName);
m_sessions.Add(userID, session);
return session;
}
/// <returns>null if all UserID values have already been allocated</returns>
public SMB1Session CreateSession(string userName)
{ {
ushort? userID = AllocateUserID(); ushort? userID = AllocateUserID();
if (userID.HasValue) if (userID.HasValue)
{ {
m_connectedUsers.Add(userID.Value, userName); return CreateSession(userID.Value, userName);
} }
return userID;
}
public string GetConnectedUserName(ushort userID)
{
if (m_connectedUsers.ContainsKey(userID))
{
return m_connectedUsers[userID];
}
else
{
return null; return null;
} }
public SMB1Session GetSession(ushort userID)
{
SMB1Session session;
m_sessions.TryGetValue(userID, out session);
return session;
} }
public bool IsAuthenticated(ushort userID) public void RemoveSession(ushort userID)
{ {
return m_connectedUsers.ContainsKey(userID); m_sessions.Remove(userID);
}
public void RemoveConnectedUser(ushort userID)
{
m_connectedUsers.Remove(userID);
} }
/// <summary> /// <summary>
/// An open TID MUST be unique within an SMB connection. /// An open TID MUST be unique within an SMB connection.
/// The value 0xFFFF MUST NOT be used as a valid TID. All other possible values for TID, including zero (0x0000), are valid. /// The value 0xFFFF MUST NOT be used as a valid TID. All other possible values for TID, including zero (0x0000), are valid.
/// </summary> /// </summary>
private ushort? AllocateTreeID() public ushort? AllocateTreeID()
{ {
for (ushort offset = 0; offset < UInt16.MaxValue; offset++) for (ushort offset = 0; offset < UInt16.MaxValue; offset++)
{ {
@ -107,7 +95,7 @@ namespace SMBLibrary.Server
{ {
continue; continue;
} }
if (!m_connectedTrees.ContainsKey(treeID)) if (!IsTreeIDAllocated(treeID))
{ {
m_nextTID = (ushort)(treeID + 1); m_nextTID = (ushort)(treeID + 1);
return treeID; return treeID;
@ -116,36 +104,51 @@ namespace SMBLibrary.Server
return null; return null;
} }
public ushort? AddConnectedTree(ISMBShare share) private bool IsTreeIDAllocated(ushort treeID)
{ {
ushort? treeID = AllocateTreeID(); foreach (SMB1Session session in m_sessions.Values)
if (treeID.HasValue)
{ {
m_connectedTrees.Add(treeID.Value, share); if (session.GetConnectedTree(treeID) != null)
{
return true;
} }
return treeID; }
return false;
} }
public ISMBShare GetConnectedTree(ushort treeID) /// <summary>
/// A FID returned from an Open or Create operation MUST be unique within an SMB connection.
/// The value 0xFFFF MUST NOT be used as a valid FID. All other possible values for FID, including zero (0x0000) are valid.
/// </summary>
/// <returns></returns>
public ushort? AllocateFileID()
{ {
if (m_connectedTrees.ContainsKey(treeID)) for (ushort offset = 0; offset < UInt16.MaxValue; offset++)
{ {
return m_connectedTrees[treeID]; ushort fileID = (ushort)(m_nextFID + offset);
if (fileID == 0 || fileID == 0xFFFF)
{
continue;
} }
else if (!IsFileIDAllocated(fileID))
{ {
m_nextFID = (ushort)(fileID + 1);
return fileID;
}
}
return null; return null;
} }
}
public void RemoveConnectedTree(ushort treeID) private bool IsFileIDAllocated(ushort fileID)
{ {
m_connectedTrees.Remove(treeID); foreach (SMB1Session session in m_sessions.Values)
{
if (session.GetOpenFileObject(fileID) != null)
{
return true;
} }
}
public bool IsTreeConnected(ushort treeID) return false;
{
return m_connectedTrees.ContainsKey(treeID);
} }
public ProcessStateObject GetProcessState(uint processID) public ProcessStateObject GetProcessState(uint processID)
@ -177,73 +180,6 @@ namespace SMBLibrary.Server
} }
} }
/// <summary>
/// The value 0xFFFF MUST NOT be used as a valid FID. All other possible values for FID, including zero (0x0000) are valid.
/// </summary>
/// <returns></returns>
private ushort? AllocateFileID()
{
for (ushort offset = 0; offset < UInt16.MaxValue; offset++)
{
ushort fileID = (ushort)(m_nextFID + offset);
if (fileID == 0 || fileID == 0xFFFF)
{
continue;
}
if (!m_openFiles.ContainsKey(fileID))
{
m_nextFID = (ushort)(fileID + 1);
return fileID;
}
}
return null;
}
/// <param name="relativePath">Should include the path relative to the share</param>
/// <returns>FileID</returns>
public ushort? AddOpenFile(string relativePath)
{
return AddOpenFile(relativePath, null);
}
public ushort? AddOpenFile(string relativePath, Stream stream)
{
return AddOpenFile(relativePath, stream, false);
}
public ushort? AddOpenFile(string relativePath, Stream stream, bool deleteOnClose)
{
ushort? fileID = AllocateFileID();
if (fileID.HasValue)
{
m_openFiles.Add(fileID.Value, new OpenFileObject(relativePath, stream, deleteOnClose));
}
return fileID;
}
public OpenFileObject GetOpenFileObject(ushort fileID)
{
if (m_openFiles.ContainsKey(fileID))
{
return m_openFiles[fileID];
}
else
{
return null;
}
}
public void RemoveOpenFile(ushort fileID)
{
Stream stream = m_openFiles[fileID].Stream;
if (stream != null)
{
LogToServer(Severity.Verbose, "Closing file '{0}'", m_openFiles[fileID].Path);
stream.Close();
}
m_openFiles.Remove(fileID);
}
public uint? GetMaxDataCount(uint processID) public uint? GetMaxDataCount(uint processID)
{ {
ProcessStateObject processState = GetProcessState(processID); ProcessStateObject processState = GetProcessState(processID);
@ -256,31 +192,5 @@ namespace SMBLibrary.Server
return null; return null;
} }
} }
public ushort? AllocateSearchHandle()
{
for (ushort offset = 0; offset < UInt16.MaxValue; offset++)
{
ushort searchHandle = (ushort)(m_nextSearchHandle + offset);
if (searchHandle == 0 || searchHandle == 0xFFFF)
{
continue;
}
if (!OpenSearches.ContainsKey(searchHandle))
{
m_nextSearchHandle = (ushort)(searchHandle + 1);
return searchHandle;
}
}
return null;
}
public void ReleaseSearchHandle(ushort searchHandle)
{
if (OpenSearches.ContainsKey(searchHandle))
{
OpenSearches.Remove(searchHandle);
}
}
} }
} }

View file

@ -0,0 +1,147 @@
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
*
* You can redistribute this program and/or modify it under the terms of
* the GNU Lesser Public License as published by the Free Software Foundation,
* either version 3 of the License, or (at your option) any later version.
*/
using System;
using System.Collections.Generic;
using System.IO;
using Utilities;
namespace SMBLibrary.Server
{
public class SMB1Session
{
private const int MaxSearches = 2048; // Windows servers initialize Server.MaxSearches to 2048.
private SMB1ConnectionState m_connection;
private ushort m_userID;
private string m_userName;
// Key is TID
private Dictionary<ushort, ISMBShare> m_connectedTrees = new Dictionary<ushort, ISMBShare>();
// Key is FID
private Dictionary<ushort, OpenFileObject> m_openFiles = new Dictionary<ushort, OpenFileObject>();
// Key is search handle a.k.a. Search ID
public Dictionary<ushort, List<FileSystemEntry>> OpenSearches = new Dictionary<ushort, List<FileSystemEntry>>();
private ushort m_nextSearchHandle = 1;
public SMB1Session(SMB1ConnectionState connection, ushort userID, string userName)
{
m_connection = connection;
m_userID = userID;
m_userName = userName;
}
public ushort? AddConnectedTree(ISMBShare share)
{
ushort? treeID = m_connection.AllocateTreeID();
if (treeID.HasValue)
{
m_connectedTrees.Add(treeID.Value, share);
}
return treeID;
}
public ISMBShare GetConnectedTree(ushort treeID)
{
ISMBShare share;
m_connectedTrees.TryGetValue(treeID, out share);
return share;
}
public void RemoveConnectedTree(ushort treeID)
{
m_connectedTrees.Remove(treeID);
}
public bool IsTreeConnected(ushort treeID)
{
return m_connectedTrees.ContainsKey(treeID);
}
/// <param name="relativePath">Should include the path relative to the share</param>
/// <returns>FileID</returns>
public ushort? AddOpenFile(string relativePath)
{
return AddOpenFile(relativePath, null);
}
public ushort? AddOpenFile(string relativePath, Stream stream)
{
return AddOpenFile(relativePath, stream, false);
}
public ushort? AddOpenFile(string relativePath, Stream stream, bool deleteOnClose)
{
ushort? fileID = m_connection.AllocateFileID();
if (fileID.HasValue)
{
m_openFiles.Add(fileID.Value, new OpenFileObject(relativePath, stream, deleteOnClose));
}
return fileID;
}
public OpenFileObject GetOpenFileObject(ushort fileID)
{
OpenFileObject openFile;
m_openFiles.TryGetValue(fileID, out openFile);
return openFile;
}
public void RemoveOpenFile(ushort fileID)
{
Stream stream = m_openFiles[fileID].Stream;
if (stream != null)
{
stream.Close();
}
m_openFiles.Remove(fileID);
}
public ushort? AllocateSearchHandle()
{
for (ushort offset = 0; offset < UInt16.MaxValue; offset++)
{
ushort searchHandle = (ushort)(m_nextSearchHandle + offset);
if (searchHandle == 0 || searchHandle == 0xFFFF)
{
continue;
}
if (!OpenSearches.ContainsKey(searchHandle))
{
m_nextSearchHandle = (ushort)(searchHandle + 1);
return searchHandle;
}
}
return null;
}
public void ReleaseSearchHandle(ushort searchHandle)
{
if (OpenSearches.ContainsKey(searchHandle))
{
OpenSearches.Remove(searchHandle);
}
}
public ushort UserID
{
get
{
return m_userID;
}
}
public string UserName
{
get
{
return m_userName;
}
}
}
}

View file

@ -17,8 +17,8 @@ namespace SMBLibrary.Server.SMB1
{ {
internal static SMB1Command GetCreateDirectoryResponse(SMB1Header header, CreateDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state) internal static SMB1Command GetCreateDirectoryResponse(SMB1Header header, CreateDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
{ {
string userName = state.GetConnectedUserName(header.UID); SMB1Session session = state.GetSession(header.UID);
if (!share.HasWriteAccess(userName)) if (!share.HasWriteAccess(session.UserName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY); return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
@ -47,8 +47,8 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetDeleteDirectoryResponse(SMB1Header header, DeleteDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state) internal static SMB1Command GetDeleteDirectoryResponse(SMB1Header header, DeleteDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
{ {
string userName = state.GetConnectedUserName(header.UID); SMB1Session session = state.GetSession(header.UID);
if (!share.HasWriteAccess(userName)) if (!share.HasWriteAccess(session.UserName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY); return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
@ -102,8 +102,8 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state) internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state)
{ {
string userName = state.GetConnectedUserName(header.UID); SMB1Session session = state.GetSession(header.UID);
if (!share.HasWriteAccess(userName)) if (!share.HasWriteAccess(session.UserName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return new ErrorResponse(CommandName.SMB_COM_DELETE); return new ErrorResponse(CommandName.SMB_COM_DELETE);
@ -145,8 +145,8 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state) internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state)
{ {
string userName = state.GetConnectedUserName(header.UID); SMB1Session session = state.GetSession(header.UID);
if (!share.HasWriteAccess(userName)) if (!share.HasWriteAccess(session.UserName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return new ErrorResponse(CommandName.SMB_COM_RENAME); return new ErrorResponse(CommandName.SMB_COM_RENAME);
@ -209,8 +209,8 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetSetInformationResponse(SMB1Header header, SetInformationRequest request, FileSystemShare share, SMB1ConnectionState state) internal static SMB1Command GetSetInformationResponse(SMB1Header header, SetInformationRequest request, FileSystemShare share, SMB1ConnectionState state)
{ {
string userName = state.GetConnectedUserName(header.UID); SMB1Session session = state.GetSession(header.UID);
if (!share.HasWriteAccess(userName)) if (!share.HasWriteAccess(session.UserName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2); return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
@ -251,15 +251,15 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetSetInformation2Response(SMB1Header header, SetInformation2Request request, FileSystemShare share, SMB1ConnectionState state) internal static SMB1Command GetSetInformation2Response(SMB1Header header, SetInformation2Request request, FileSystemShare share, SMB1ConnectionState state)
{ {
OpenFileObject openFile = state.GetOpenFileObject(request.FID); SMB1Session session = state.GetSession(header.UID);
OpenFileObject openFile = session.GetOpenFileObject(request.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_SMB_BAD_FID; header.Status = NTStatus.STATUS_SMB_BAD_FID;
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2); return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
} }
string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(session.UserName))
if (!share.HasWriteAccess(userName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2); return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);

View file

@ -18,6 +18,7 @@ namespace SMBLibrary.Server.SMB1
{ {
internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state) internal static SMB1Command GetNTCreateResponse(SMB1Header header, NTCreateAndXRequest request, ISMBShare share, SMB1ConnectionState state)
{ {
SMB1Session session = state.GetSession(header.UID);
bool isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0; bool isExtended = (request.Flags & NTCreateFlags.NT_CREATE_REQUEST_EXTENDED_RESPONSE) > 0;
string path = request.FileName; string path = request.FileName;
if (share is NamedPipeShare) if (share is NamedPipeShare)
@ -25,7 +26,7 @@ namespace SMBLibrary.Server.SMB1
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path); Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
if (pipeStream != null) if (pipeStream != null)
{ {
ushort? fileID = state.AddOpenFile(path, pipeStream); ushort? fileID = session.AddOpenFile(path, pipeStream);
if (!fileID.HasValue) if (!fileID.HasValue)
{ {
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
@ -47,7 +48,7 @@ namespace SMBLibrary.Server.SMB1
else // FileSystemShare else // FileSystemShare
{ {
FileSystemShare fileSystemShare = (FileSystemShare)share; FileSystemShare fileSystemShare = (FileSystemShare)share;
string userName = state.GetConnectedUserName(header.UID); string userName = session.UserName;
FileSystemEntry entry; FileSystemEntry entry;
NTStatus createStatus = CreateFile(out entry, fileSystemShare, userName, path, request.CreateDisposition, request.CreateOptions, request.DesiredAccess, state); NTStatus createStatus = CreateFile(out entry, fileSystemShare, userName, path, request.CreateDisposition, request.CreateOptions, request.DesiredAccess, state);
if (createStatus != NTStatus.STATUS_SUCCESS) if (createStatus != NTStatus.STATUS_SUCCESS)
@ -109,7 +110,7 @@ namespace SMBLibrary.Server.SMB1
} }
} }
ushort? fileID = state.AddOpenFile(path, stream, deleteOnClose); ushort? fileID = session.AddOpenFile(path, stream, deleteOnClose);
if (!fileID.HasValue) if (!fileID.HasValue)
{ {
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;

View file

@ -18,6 +18,7 @@ namespace SMBLibrary.Server.SMB1
{ {
internal static SMB1Command GetOpenAndXResponse(SMB1Header header, OpenAndXRequest request, ISMBShare share, SMB1ConnectionState state) internal static SMB1Command GetOpenAndXResponse(SMB1Header header, OpenAndXRequest request, ISMBShare share, SMB1ConnectionState state)
{ {
SMB1Session session = state.GetSession(header.UID);
bool isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0; bool isExtended = (request.Flags & OpenFlags.SMB_OPEN_EXTENDED_RESPONSE) > 0;
string path = request.FileName; string path = request.FileName;
if (share is NamedPipeShare) if (share is NamedPipeShare)
@ -25,7 +26,7 @@ namespace SMBLibrary.Server.SMB1
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path); Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
if (pipeStream != null) if (pipeStream != null)
{ {
ushort? fileID = state.AddOpenFile(path, pipeStream); ushort? fileID = session.AddOpenFile(path, pipeStream);
if (!fileID.HasValue) if (!fileID.HasValue)
{ {
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
@ -47,7 +48,7 @@ namespace SMBLibrary.Server.SMB1
else // FileSystemShare else // FileSystemShare
{ {
FileSystemShare fileSystemShare = (FileSystemShare)share; FileSystemShare fileSystemShare = (FileSystemShare)share;
string userName = state.GetConnectedUserName(header.UID); string userName = session.UserName;
bool hasWriteAccess = fileSystemShare.HasWriteAccess(userName); bool hasWriteAccess = fileSystemShare.HasWriteAccess(userName);
IFileSystem fileSystem = fileSystemShare.FileSystem; IFileSystem fileSystem = fileSystemShare.FileSystem;
@ -133,7 +134,7 @@ namespace SMBLibrary.Server.SMB1
stream = new PrefetchedStream(stream); stream = new PrefetchedStream(stream);
} }
} }
ushort? fileID = state.AddOpenFile(path, stream); ushort? fileID = session.AddOpenFile(path, stream);
if (!fileID.HasValue) if (!fileID.HasValue)
{ {
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES; header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;

View file

@ -19,7 +19,8 @@ namespace SMBLibrary.Server.SMB1
{ {
internal static SMB1Command GetReadResponse(SMB1Header header, ReadRequest request, ISMBShare share, SMB1ConnectionState state) internal static SMB1Command GetReadResponse(SMB1Header header, ReadRequest request, ISMBShare share, SMB1ConnectionState state)
{ {
OpenFileObject openFile = state.GetOpenFileObject(request.FID); SMB1Session session = state.GetSession(header.UID);
OpenFileObject openFile = session.GetOpenFileObject(request.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_INVALID_HANDLE; header.Status = NTStatus.STATUS_INVALID_HANDLE;
@ -40,7 +41,8 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetReadResponse(SMB1Header header, ReadAndXRequest request, ISMBShare share, SMB1ConnectionState state) internal static SMB1Command GetReadResponse(SMB1Header header, ReadAndXRequest request, ISMBShare share, SMB1ConnectionState state)
{ {
OpenFileObject openFile = state.GetOpenFileObject(request.FID); SMB1Session session = state.GetSession(header.UID);
OpenFileObject openFile = session.GetOpenFileObject(request.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_INVALID_HANDLE; header.Status = NTStatus.STATUS_INVALID_HANDLE;
@ -136,7 +138,8 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetWriteResponse(SMB1Header header, WriteRequest request, ISMBShare share, SMB1ConnectionState state) internal static SMB1Command GetWriteResponse(SMB1Header header, WriteRequest request, ISMBShare share, SMB1ConnectionState state)
{ {
OpenFileObject openFile = state.GetOpenFileObject(request.FID); SMB1Session session = state.GetSession(header.UID);
OpenFileObject openFile = session.GetOpenFileObject(request.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_INVALID_HANDLE; header.Status = NTStatus.STATUS_INVALID_HANDLE;
@ -155,7 +158,8 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetWriteResponse(SMB1Header header, WriteAndXRequest request, ISMBShare share, SMB1ConnectionState state) internal static SMB1Command GetWriteResponse(SMB1Header header, WriteAndXRequest request, ISMBShare share, SMB1ConnectionState state)
{ {
OpenFileObject openFile = state.GetOpenFileObject(request.FID); SMB1Session session = state.GetSession(header.UID);
OpenFileObject openFile = session.GetOpenFileObject(request.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_INVALID_HANDLE; header.Status = NTStatus.STATUS_INVALID_HANDLE;

View file

@ -17,14 +17,16 @@ namespace SMBLibrary.Server.SMB1
{ {
internal static SMB1Command GetCloseResponse(SMB1Header header, CloseRequest request, ISMBShare share, SMB1ConnectionState state) internal static SMB1Command GetCloseResponse(SMB1Header header, CloseRequest request, ISMBShare share, SMB1ConnectionState state)
{ {
OpenFileObject openFile = state.GetOpenFileObject(request.FID); SMB1Session session = state.GetSession(header.UID);
OpenFileObject openFile = session.GetOpenFileObject(request.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_SMB_BAD_FID; header.Status = NTStatus.STATUS_SMB_BAD_FID;
return new ErrorResponse(CommandName.SMB_COM_CLOSE); return new ErrorResponse(CommandName.SMB_COM_CLOSE);
} }
state.RemoveOpenFile(request.FID); state.LogToServer(Severity.Verbose, "Close: Closing file '{0}'", openFile.Path);
session.RemoveOpenFile(request.FID);
if (openFile.DeleteOnClose && share is FileSystemShare) if (openFile.DeleteOnClose && share is FileSystemShare)
{ {
try try
@ -42,7 +44,8 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetFindClose2Request(SMB1Header header, FindClose2Request request, SMB1ConnectionState state) internal static SMB1Command GetFindClose2Request(SMB1Header header, FindClose2Request request, SMB1ConnectionState state)
{ {
state.ReleaseSearchHandle(request.SearchHandle); SMB1Session session = state.GetSession(header.UID);
session.ReleaseSearchHandle(request.SearchHandle);
return new FindClose2Response(); return new FindClose2Response();
} }

View file

@ -40,25 +40,25 @@ namespace SMBLibrary.Server.SMB1
if (loginSuccess) if (loginSuccess)
{ {
state.LogToServer(Severity.Information, "User '{0}' authenticated successfully", message.UserName); state.LogToServer(Severity.Information, "User '{0}' authenticated successfully", message.UserName);
ushort? userID = state.AddConnectedUser(message.UserName); SMB1Session session = state.CreateSession(message.UserName);
if (!userID.HasValue) if (session == null)
{ {
header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS; header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX); return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
} }
header.UID = userID.Value; header.UID = session.UserID;
response.PrimaryDomain = request.PrimaryDomain; response.PrimaryDomain = request.PrimaryDomain;
} }
else if (users.FallbackToGuest(message.UserName)) else if (users.FallbackToGuest(message.UserName))
{ {
state.LogToServer(Severity.Information, "User '{0}' failed authentication. logged in as guest", message.UserName); state.LogToServer(Severity.Information, "User '{0}' failed authentication. logged in as guest", message.UserName);
ushort? userID = state.AddConnectedUser("Guest"); SMB1Session session = state.CreateSession("Guest");
if (!userID.HasValue) if (session == null)
{ {
header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS; header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX); return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
} }
header.UID = userID.Value; header.UID = session.UserID;
response.Action = SessionSetupAction.SetupGuest; response.Action = SessionSetupAction.SetupGuest;
response.PrimaryDomain = request.PrimaryDomain; response.PrimaryDomain = request.PrimaryDomain;
} }
@ -100,6 +100,18 @@ namespace SMBLibrary.Server.SMB1
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX); return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
} }
// According to [MS-SMB] 3.3.5.3, a UID MUST be allocated if the server returns STATUS_MORE_PROCESSING_REQUIRED
if (header.UID == 0)
{
ushort? userID = state.AllocateUserID();
if (!userID.HasValue)
{
header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
return new ErrorResponse(request.CommandName);
}
header.UID = userID.Value;
}
MessageTypeName messageType = AuthenticationMessageUtils.GetMessageType(messageBytes); MessageTypeName messageType = AuthenticationMessageUtils.GetMessageType(messageBytes);
if (messageType == MessageTypeName.Negotiate) if (messageType == MessageTypeName.Negotiate)
{ {
@ -133,24 +145,12 @@ namespace SMBLibrary.Server.SMB1
if (loginSuccess) if (loginSuccess)
{ {
state.LogToServer(Severity.Information, "User '{0}' authenticated successfully", authenticateMessage.UserName); state.LogToServer(Severity.Information, "User '{0}' authenticated successfully", authenticateMessage.UserName);
ushort? userID = state.AddConnectedUser(authenticateMessage.UserName); state.CreateSession(header.UID, authenticateMessage.UserName);
if (!userID.HasValue)
{
header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
}
header.UID = userID.Value;
} }
else if (users.FallbackToGuest(authenticateMessage.UserName)) else if (users.FallbackToGuest(authenticateMessage.UserName))
{ {
state.LogToServer(Severity.Information, "User '{0}' failed authentication. logged in as guest", authenticateMessage.UserName); state.LogToServer(Severity.Information, "User '{0}' failed authentication. logged in as guest", authenticateMessage.UserName);
ushort? userID = state.AddConnectedUser("Guest"); state.CreateSession(header.UID, "Guest");
if (!userID.HasValue)
{
header.Status = NTStatus.STATUS_TOO_MANY_SESSIONS;
return new ErrorResponse(CommandName.SMB_COM_SESSION_SETUP_ANDX);
}
header.UID = userID.Value;
response.Action = SessionSetupAction.SetupGuest; response.Action = SessionSetupAction.SetupGuest;
} }
else else

View file

@ -22,6 +22,7 @@ namespace SMBLibrary.Server.SMB1
internal static Transaction2FindFirst2Response GetSubcommandResponse(SMB1Header header, Transaction2FindFirst2Request subcommand, FileSystemShare share, SMB1ConnectionState state) internal static Transaction2FindFirst2Response GetSubcommandResponse(SMB1Header header, Transaction2FindFirst2Request subcommand, FileSystemShare share, SMB1ConnectionState state)
{ {
SMB1Session session = state.GetSession(header.UID);
IFileSystem fileSystem = share.FileSystem; IFileSystem fileSystem = share.FileSystem;
string path = subcommand.FileName; string path = subcommand.FileName;
// '\Directory' - Get the directory info // '\Directory' - Get the directory info
@ -122,7 +123,7 @@ namespace SMBLibrary.Server.SMB1
} }
else else
{ {
ushort? searchHandle = state.AllocateSearchHandle(); ushort? searchHandle = session.AllocateSearchHandle();
if (!searchHandle.HasValue) if (!searchHandle.HasValue)
{ {
header.Status = NTStatus.STATUS_OS2_NO_MORE_SIDS; header.Status = NTStatus.STATUS_OS2_NO_MORE_SIDS;
@ -130,7 +131,7 @@ namespace SMBLibrary.Server.SMB1
} }
response.SID = searchHandle.Value; response.SID = searchHandle.Value;
entries.RemoveRange(0, returnCount); entries.RemoveRange(0, returnCount);
state.OpenSearches.Add(response.SID, entries); session.OpenSearches.Add(response.SID, entries);
} }
return response; return response;
} }
@ -195,14 +196,15 @@ namespace SMBLibrary.Server.SMB1
internal static Transaction2FindNext2Response GetSubcommandResponse(SMB1Header header, Transaction2FindNext2Request subcommand, FileSystemShare share, SMB1ConnectionState state) internal static Transaction2FindNext2Response GetSubcommandResponse(SMB1Header header, Transaction2FindNext2Request subcommand, FileSystemShare share, SMB1ConnectionState state)
{ {
if (!state.OpenSearches.ContainsKey(subcommand.SID)) SMB1Session session = state.GetSession(header.UID);
if (!session.OpenSearches.ContainsKey(subcommand.SID))
{ {
header.Status = NTStatus.STATUS_INVALID_HANDLE; header.Status = NTStatus.STATUS_INVALID_HANDLE;
return null; return null;
} }
bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0; bool returnResumeKeys = (subcommand.Flags & FindFlags.SMB_FIND_RETURN_RESUME_KEYS) > 0;
List<FileSystemEntry> entries = state.OpenSearches[subcommand.SID]; List<FileSystemEntry> entries = session.OpenSearches[subcommand.SID];
FindInformationList findInformationList = new FindInformationList(); FindInformationList findInformationList = new FindInformationList();
for (int index = 0; index < entries.Count; index++) for (int index = 0; index < entries.Count; index++)
{ {
@ -218,11 +220,11 @@ namespace SMBLibrary.Server.SMB1
Transaction2FindNext2Response response = new Transaction2FindNext2Response(); Transaction2FindNext2Response response = new Transaction2FindNext2Response();
response.SetFindInformationList(findInformationList, header.UnicodeFlag); response.SetFindInformationList(findInformationList, header.UnicodeFlag);
entries.RemoveRange(0, returnCount); entries.RemoveRange(0, returnCount);
state.OpenSearches[subcommand.SID] = entries; session.OpenSearches[subcommand.SID] = entries;
response.EndOfSearch = (returnCount == entries.Count) && (entries.Count <= subcommand.SearchCount); response.EndOfSearch = (returnCount == entries.Count) && (entries.Count <= subcommand.SearchCount);
if (response.EndOfSearch) if (response.EndOfSearch)
{ {
state.ReleaseSearchHandle(subcommand.SID); session.ReleaseSearchHandle(subcommand.SID);
} }
return response; return response;
} }
@ -257,8 +259,9 @@ namespace SMBLibrary.Server.SMB1
internal static Transaction2QueryFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFileInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state) internal static Transaction2QueryFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2QueryFileInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state)
{ {
SMB1Session session = state.GetSession(header.UID);
IFileSystem fileSystem = share.FileSystem; IFileSystem fileSystem = share.FileSystem;
OpenFileObject openFile = state.GetOpenFileObject(subcommand.FID); OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_INVALID_HANDLE; header.Status = NTStatus.STATUS_INVALID_HANDLE;
@ -280,7 +283,8 @@ namespace SMBLibrary.Server.SMB1
internal static Transaction2SetFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2SetFileInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state) internal static Transaction2SetFileInformationResponse GetSubcommandResponse(SMB1Header header, Transaction2SetFileInformationRequest subcommand, FileSystemShare share, SMB1ConnectionState state)
{ {
OpenFileObject openFile = state.GetOpenFileObject(subcommand.FID); SMB1Session session = state.GetSession(header.UID);
OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_INVALID_HANDLE; header.Status = NTStatus.STATUS_INVALID_HANDLE;
@ -300,8 +304,7 @@ namespace SMBLibrary.Server.SMB1
} }
case SetInformationLevel.SMB_SET_FILE_BASIC_INFO: case SetInformationLevel.SMB_SET_FILE_BASIC_INFO:
{ {
string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(session.UserName))
if (!share.HasWriteAccess(userName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return null; return null;
@ -353,8 +356,7 @@ namespace SMBLibrary.Server.SMB1
if (((SetFileDispositionInfo)subcommand.SetInfo).DeletePending) if (((SetFileDispositionInfo)subcommand.SetInfo).DeletePending)
{ {
// We're supposed to delete the file on close, but it's too late to report errors at this late stage // We're supposed to delete the file on close, but it's too late to report errors at this late stage
string userName = state.GetConnectedUserName(header.UID); if (!share.HasWriteAccess(session.UserName))
if (!share.HasWriteAccess(userName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return null; return null;

View file

@ -18,7 +18,8 @@ namespace SMBLibrary.Server.SMB1
{ {
internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, TransactionTransactNamedPipeRequest subcommand, NamedPipeShare share, SMB1ConnectionState state) internal static TransactionTransactNamedPipeResponse GetSubcommandResponse(SMB1Header header, TransactionTransactNamedPipeRequest subcommand, NamedPipeShare share, SMB1ConnectionState state)
{ {
OpenFileObject openFile = state.GetOpenFileObject(subcommand.FID); SMB1Session session = state.GetSession(header.UID);
OpenFileObject openFile = session.GetOpenFileObject(subcommand.FID);
if (openFile == null) if (openFile == null)
{ {
header.Status = NTStatus.STATUS_INVALID_HANDLE; header.Status = NTStatus.STATUS_INVALID_HANDLE;

View file

@ -16,6 +16,7 @@ namespace SMBLibrary.Server.SMB1
{ {
internal static SMB1Command GetTreeConnectResponse(SMB1Header header, TreeConnectAndXRequest request, SMB1ConnectionState state, NamedPipeShare services, ShareCollection shares) internal static SMB1Command GetTreeConnectResponse(SMB1Header header, TreeConnectAndXRequest request, SMB1ConnectionState state, NamedPipeShare services, ShareCollection shares)
{ {
SMB1Session session = state.GetSession(header.UID);
bool isExtended = (request.Flags & TreeConnectFlags.ExtendedResponse) > 0; bool isExtended = (request.Flags & TreeConnectFlags.ExtendedResponse) > 0;
string shareName = ServerPathUtils.GetShareName(request.Path); string shareName = ServerPathUtils.GetShareName(request.Path);
ISMBShare share; ISMBShare share;
@ -35,14 +36,13 @@ namespace SMBLibrary.Server.SMB1
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX); return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
} }
string userName = state.GetConnectedUserName(header.UID); if (!((FileSystemShare)share).HasReadAccess(session.UserName))
if (!((FileSystemShare)share).HasReadAccess(userName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX); return new ErrorResponse(CommandName.SMB_COM_TREE_CONNECT_ANDX);
} }
} }
ushort? treeID = state.AddConnectedTree(share); ushort? treeID = session.AddConnectedTree(share);
if (!treeID.HasValue) if (!treeID.HasValue)
{ {
header.Status = NTStatus.STATUS_INSUFF_SERVER_RESOURCES; header.Status = NTStatus.STATUS_INSUFF_SERVER_RESOURCES;
@ -88,13 +88,14 @@ namespace SMBLibrary.Server.SMB1
internal static SMB1Command GetTreeDisconnectResponse(SMB1Header header, TreeDisconnectRequest request, SMB1ConnectionState state) internal static SMB1Command GetTreeDisconnectResponse(SMB1Header header, TreeDisconnectRequest request, SMB1ConnectionState state)
{ {
if (!state.IsTreeConnected(header.TID)) SMB1Session session = state.GetSession(header.UID);
if (!session.IsTreeConnected(header.TID))
{ {
header.Status = NTStatus.STATUS_SMB_BAD_TID; header.Status = NTStatus.STATUS_SMB_BAD_TID;
return new ErrorResponse(CommandName.SMB_COM_TREE_DISCONNECT); return new ErrorResponse(CommandName.SMB_COM_TREE_DISCONNECT);
} }
state.RemoveConnectedTree(header.TID); session.RemoveConnectedTree(header.TID);
return new TreeDisconnectResponse(); return new TreeDisconnectResponse();
} }
} }

View file

@ -88,8 +88,15 @@ namespace SMBLibrary.Server
{ {
return ServerResponseHelper.GetEchoResponse((EchoRequest)command, sendQueue); return ServerResponseHelper.GetEchoResponse((EchoRequest)command, sendQueue);
} }
else if (state.IsAuthenticated(header.UID)) else
{ {
SMB1Session session = state.GetSession(header.UID);
if (session == null)
{
header.Status = NTStatus.STATUS_USER_SESSION_DELETED;
return new ErrorResponse(command.CommandName);
}
if (command is TreeConnectAndXRequest) if (command is TreeConnectAndXRequest)
{ {
TreeConnectAndXRequest request = (TreeConnectAndXRequest)command; TreeConnectAndXRequest request = (TreeConnectAndXRequest)command;
@ -97,13 +104,18 @@ namespace SMBLibrary.Server
} }
else if (command is LogoffAndXRequest) else if (command is LogoffAndXRequest)
{ {
// FIXME: Remove connected trees that the user has connected to state.RemoveSession(header.UID);
state.RemoveConnectedUser(header.UID);
return new LogoffAndXResponse(); return new LogoffAndXResponse();
} }
else if (state.IsTreeConnected(header.TID)) else
{ {
ISMBShare share = state.GetConnectedTree(header.TID); ISMBShare share = session.GetConnectedTree(header.TID);
if (share == null)
{
header.Status = NTStatus.STATUS_SMB_BAD_TID;
return new ErrorResponse(command.CommandName);
}
if (command is CreateDirectoryRequest) if (command is CreateDirectoryRequest)
{ {
if (!(share is FileSystemShare)) if (!(share is FileSystemShare))
@ -180,7 +192,7 @@ namespace SMBLibrary.Server
} }
else if (command is WriteRequest) else if (command is WriteRequest)
{ {
string userName = state.GetConnectedUserName(header.UID); string userName = session.UserName;
if (share is FileSystemShare && !((FileSystemShare)share).HasWriteAccess(userName)) if (share is FileSystemShare && !((FileSystemShare)share).HasWriteAccess(userName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
@ -234,7 +246,7 @@ namespace SMBLibrary.Server
} }
else if (command is WriteAndXRequest) else if (command is WriteAndXRequest)
{ {
string userName = state.GetConnectedUserName(header.UID); string userName = session.UserName;
if (share is FileSystemShare && !((FileSystemShare)share).HasWriteAccess(userName)) if (share is FileSystemShare && !((FileSystemShare)share).HasWriteAccess(userName))
{ {
header.Status = NTStatus.STATUS_ACCESS_DENIED; header.Status = NTStatus.STATUS_ACCESS_DENIED;
@ -294,11 +306,6 @@ namespace SMBLibrary.Server
return NTCreateHelper.GetNTCreateResponse(header, request, share, state); return NTCreateHelper.GetNTCreateResponse(header, request, share, state);
} }
} }
else
{
header.Status = NTStatus.STATUS_SMB_BAD_TID;
return new ErrorResponse(command.CommandName);
}
} }
header.Status = NTStatus.STATUS_SMB_BAD_COMMAND; header.Status = NTStatus.STATUS_SMB_BAD_COMMAND;