Server: SMB1: Added support for pass-through Information Levels

This commit is contained in:
Tal Aloni 2017-10-01 16:55:30 +03:00
parent 2b14375876
commit c1210d57bc
3 changed files with 154 additions and 47 deletions

View file

@ -35,6 +35,7 @@ namespace SMBLibrary.Server.SMB1
Capabilities.RpcRemoteApi | Capabilities.RpcRemoteApi |
Capabilities.NTStatusCode | Capabilities.NTStatusCode |
Capabilities.NTFind | Capabilities.NTFind |
Capabilities.InfoLevelPassthrough |
Capabilities.LargeRead | Capabilities.LargeRead |
Capabilities.LargeWrite; Capabilities.LargeWrite;
response.SystemTime = DateTime.UtcNow; response.SystemTime = DateTime.UtcNow;
@ -67,6 +68,7 @@ namespace SMBLibrary.Server.SMB1
Capabilities.RpcRemoteApi | Capabilities.RpcRemoteApi |
Capabilities.NTStatusCode | Capabilities.NTStatusCode |
Capabilities.NTFind | Capabilities.NTFind |
Capabilities.InfoLevelPassthrough |
Capabilities.LargeRead | Capabilities.LargeRead |
Capabilities.LargeWrite | Capabilities.LargeWrite |
Capabilities.ExtendedSecurity; Capabilities.ExtendedSecurity;

View file

@ -29,6 +29,21 @@ namespace SMBLibrary.Server.SMB1
return returnStatus; return returnStatus;
} }
public static NTStatus GetFileInformation(out FileInformation result, INTFileStore fileStore, string path, FileInformationClass informationClass, SecurityContext securityContext)
{
object handle;
FileStatus fileStatus;
NTStatus openStatus = fileStore.CreateFile(out handle, out fileStatus, path, (AccessMask)FileAccessMask.FILE_READ_ATTRIBUTES, 0, ShareAccess.FILE_SHARE_READ | ShareAccess.FILE_SHARE_WRITE, CreateDisposition.FILE_OPEN, 0, securityContext);
if (openStatus != NTStatus.STATUS_SUCCESS)
{
result = null;
return openStatus;
}
NTStatus returnStatus = fileStore.GetFileInformation(out result, handle, informationClass);
fileStore.CloseFile(handle);
return returnStatus;
}
public static NTStatus GetFileInformation(out QueryInformation result, INTFileStore fileStore, object handle, QueryInformationLevel informationLevel) public static NTStatus GetFileInformation(out QueryInformation result, INTFileStore fileStore, object handle, QueryInformationLevel informationLevel)
{ {
result = null; result = null;

View file

@ -145,16 +145,32 @@ namespace SMBLibrary.Server.SMB1
} }
Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse(); Transaction2QueryFSInformationResponse response = new Transaction2QueryFSInformationResponse();
QueryFSInformation queryFSInformation; if (subcommand.IsPassthroughInformationLevel)
NTStatus queryStatus = SMB1FileStoreHelper.GetFileSystemInformation(out queryFSInformation, share.FileStore, subcommand.QueryFSInformationLevel);
if (queryStatus != NTStatus.STATUS_SUCCESS)
{ {
state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", share.Name, subcommand.QueryFSInformationLevel, queryStatus); FileSystemInformation fileSystemInfo;
header.Status = queryStatus; NTStatus status = share.FileStore.GetFileSystemInformation(out fileSystemInfo, subcommand.FileSystemInformationClass);
return null; if (status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. Information class: {1}, NTStatus: {2}", share.Name, subcommand.FileSystemInformationClass, status);
header.Status = status;
return null;
}
state.LogToServer(Severity.Information, "GetFileSystemInformation on '{0}' succeeded. Information class: {1}", share.Name, subcommand.FileSystemInformationClass);
response.SetFileSystemInformation(fileSystemInfo);
}
else
{
QueryFSInformation queryFSInformation;
NTStatus status = SMB1FileStoreHelper.GetFileSystemInformation(out queryFSInformation, share.FileStore, subcommand.QueryFSInformationLevel);
if (status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Verbose, "GetFileSystemInformation on '{0}' failed. Information level: {1}, NTStatus: {2}", share.Name, subcommand.QueryFSInformationLevel, status);
header.Status = status;
return null;
}
state.LogToServer(Severity.Information, "GetFileSystemInformation on '{0}' succeeded. Information level: {1}", share.Name, subcommand.QueryFSInformationLevel);
response.SetQueryFSInformation(queryFSInformation, header.UnicodeFlag);
} }
state.LogToServer(Severity.Information, "GetFileSystemInformation on '{0}' succeeded. Information level: {1}", share.Name, subcommand.QueryFSInformationLevel);
response.SetQueryFSInformation(queryFSInformation, header.UnicodeFlag);
return response; return response;
} }
@ -178,16 +194,37 @@ namespace SMBLibrary.Server.SMB1
} }
Transaction2QueryPathInformationResponse response = new Transaction2QueryPathInformationResponse(); Transaction2QueryPathInformationResponse response = new Transaction2QueryPathInformationResponse();
QueryInformation queryInformation; if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass != FileInformationClass.FileAllInformation)
NTStatus queryStatus = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, path, subcommand.QueryInformationLevel, session.SecurityContext);
if (queryStatus != NTStatus.STATUS_SUCCESS)
{ {
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}", share.Name, path, subcommand.QueryInformationLevel, queryStatus); FileInformation fileInfo;
header.Status = queryStatus; NTStatus status = SMB1FileStoreHelper.GetFileInformation(out fileInfo, share.FileStore, path, subcommand.FileInformationClass, session.SecurityContext);
return null; if (status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}", share.Name, path, subcommand.FileInformationClass, status);
header.Status = status;
return null;
}
state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information class: {2}", share.Name, path, subcommand.FileInformationClass);
response.SetFileInformation(fileInfo);
}
else
{
// The FILE_ALL_INFORMATION structure described in [MS-FSCC], is NOT used by [MS-SMB]
if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass == FileInformationClass.FileAllInformation)
{
subcommand.QueryInformationLevel = QueryInformationLevel.SMB_QUERY_FILE_ALL_INFO;
}
QueryInformation queryInformation;
NTStatus status = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, path, subcommand.QueryInformationLevel, session.SecurityContext);
if (status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}", share.Name, path, subcommand.QueryInformationLevel, status);
header.Status = status;
return null;
}
state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information level: {2}", share.Name, path, subcommand.QueryInformationLevel);
response.SetQueryInformation(queryInformation);
} }
state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information level: {2}", share.Name, path, subcommand.QueryInformationLevel);
response.SetQueryInformation(queryInformation);
return response; return response;
} }
@ -213,16 +250,37 @@ namespace SMBLibrary.Server.SMB1
} }
Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse(); Transaction2QueryFileInformationResponse response = new Transaction2QueryFileInformationResponse();
QueryInformation queryInformation; if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass != FileInformationClass.FileAllInformation)
NTStatus queryStatus = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, openFile.Handle, subcommand.QueryInformationLevel);
if (queryStatus != NTStatus.STATUS_SUCCESS)
{ {
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.QueryInformationLevel, queryStatus, subcommand.FID); FileInformation fileInfo;
header.Status = queryStatus; NTStatus status = share.FileStore.GetFileInformation(out fileInfo, openFile.Handle, subcommand.FileInformationClass);
return null; if (status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.FileInformationClass, status, subcommand.FID);
header.Status = status;
return null;
}
state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.FileInformationClass, subcommand.FID);
response.SetFileInformation(fileInfo);
}
else
{
// The FILE_ALL_INFORMATION structure described in [MS-FSCC], is NOT used by [MS-SMB]
if (subcommand.IsPassthroughInformationLevel && subcommand.FileInformationClass == FileInformationClass.FileAllInformation)
{
subcommand.QueryInformationLevel = QueryInformationLevel.SMB_QUERY_FILE_ALL_INFO;
}
QueryInformation queryInformation;
NTStatus status = SMB1FileStoreHelper.GetFileInformation(out queryInformation, share.FileStore, openFile.Handle, subcommand.QueryInformationLevel);
if (status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Verbose, "GetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.QueryInformationLevel, status, subcommand.FID);
header.Status = status;
return null;
}
state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information level: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.QueryInformationLevel, subcommand.FID);
response.SetQueryInformation(queryInformation);
} }
state.LogToServer(Severity.Information, "GetFileInformation on '{0}{1}' succeeded. Information level: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.QueryInformationLevel, subcommand.FID);
response.SetQueryInformation(queryInformation);
return response; return response;
} }
@ -247,32 +305,64 @@ namespace SMBLibrary.Server.SMB1
} }
} }
SetInformation information; if (subcommand.IsPassthroughInformationLevel)
try
{ {
information = SetInformation.GetSetInformation(subcommand.InformationBytes, subcommand.SetInformationLevel); FileInformation fileInfo;
} try
catch(UnsupportedInformationLevelException) {
{ fileInfo = FileInformation.GetFileInformation(subcommand.InformationBytes, 0, subcommand.FileInformationClass);
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_OS2_INVALID_LEVEL.", share.Name, openFile.Path, subcommand.SetInformationLevel); }
header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL; catch (UnsupportedInformationLevelException)
return null; {
} state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_OS2_INVALID_LEVEL.", share.Name, openFile.Path, subcommand.FileInformationClass);
catch(Exception) header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
{ return null;
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path, subcommand.SetInformationLevel); }
header.Status = NTStatus.STATUS_INVALID_PARAMETER; catch (Exception)
return null; {
} state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path, subcommand.FileInformationClass);
header.Status = NTStatus.STATUS_INVALID_PARAMETER;
return null;
}
NTStatus status = SMB1FileStoreHelper.SetFileInformation(share.FileStore, openFile.Handle, information); NTStatus status = share.FileStore.SetFileInformation(openFile.Handle, fileInfo);
if (status != NTStatus.STATUS_SUCCESS) if (status != NTStatus.STATUS_SUCCESS)
{ {
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SetInformationLevel, status, subcommand.FID); state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information class: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.FileInformationClass, status, subcommand.FID);
header.Status = status; header.Status = status;
return null; return null;
}
state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information class: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.FileInformationClass, subcommand.FID);
}
else
{
SetInformation information;
try
{
information = SetInformation.GetSetInformation(subcommand.InformationBytes, subcommand.SetInformationLevel);
}
catch (UnsupportedInformationLevelException)
{
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_OS2_INVALID_LEVEL.", share.Name, openFile.Path, subcommand.SetInformationLevel);
header.Status = NTStatus.STATUS_OS2_INVALID_LEVEL;
return null;
}
catch (Exception)
{
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: STATUS_INVALID_PARAMETER.", share.Name, openFile.Path, subcommand.SetInformationLevel);
header.Status = NTStatus.STATUS_INVALID_PARAMETER;
return null;
}
NTStatus status = SMB1FileStoreHelper.SetFileInformation(share.FileStore, openFile.Handle, information);
if (status != NTStatus.STATUS_SUCCESS)
{
state.LogToServer(Severity.Verbose, "SetFileInformation on '{0}{1}' failed. Information level: {2}, NTStatus: {3}. (FID: {4})", share.Name, openFile.Path, subcommand.SetInformationLevel, status, subcommand.FID);
header.Status = status;
return null;
}
state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information level: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.SetInformationLevel, subcommand.FID);
} }
state.LogToServer(Severity.Information, "SetFileInformation on '{0}{1}' succeeded. Information level: {2}. (FID: {3})", share.Name, openFile.Path, subcommand.SetInformationLevel, subcommand.FID);
Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse(); Transaction2SetFileInformationResponse response = new Transaction2SetFileInformationResponse();
return response; return response;
} }