mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-07-03 16:23:19 +02:00
273 lines
12 KiB
C#
273 lines
12 KiB
C#
/* Copyright (C) 2014 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 System.Text;
|
|
using SMBLibrary.SMB1;
|
|
using Utilities;
|
|
|
|
namespace SMBLibrary.Server
|
|
{
|
|
public class FileSystemResponseHelper
|
|
{
|
|
internal static SMB1Command GetCreateDirectoryResponse(SMB1Header header, CreateDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
|
|
{
|
|
string userName = state.GetConnectedUserName(header.UID);
|
|
if (!share.HasWriteAccess(userName))
|
|
{
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
|
|
}
|
|
IFileSystem fileSystem = share.FileSystem;
|
|
|
|
try
|
|
{
|
|
fileSystem.CreateDirectory(request.DirectoryName);
|
|
}
|
|
catch (IOException)
|
|
{
|
|
System.Diagnostics.Debug.Print("[{0}] CreateDirectory: Cannot create '{1}'", DateTime.Now.ToString("HH:mm:ss:ffff"), request.DirectoryName);
|
|
header.Status = NTStatus.STATUS_OBJECT_NAME_INVALID;
|
|
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
System.Diagnostics.Debug.Print("[{0}] CreateDirectory: Cannot create '{1}', Access Denied", DateTime.Now.ToString("HH:mm:ss:ffff"), request.DirectoryName);
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_CREATE_DIRECTORY);
|
|
}
|
|
|
|
return new CreateDirectoryResponse();
|
|
}
|
|
|
|
internal static SMB1Command GetDeleteDirectoryResponse(SMB1Header header, DeleteDirectoryRequest request, FileSystemShare share, SMB1ConnectionState state)
|
|
{
|
|
string userName = state.GetConnectedUserName(header.UID);
|
|
if (!share.HasWriteAccess(userName))
|
|
{
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
|
}
|
|
IFileSystem fileSystem = share.FileSystem;
|
|
|
|
FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName);
|
|
if (entry == null)
|
|
{
|
|
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
|
}
|
|
|
|
if (!entry.IsDirectory)
|
|
{
|
|
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
|
}
|
|
|
|
try
|
|
{
|
|
fileSystem.Delete(request.DirectoryName);
|
|
return new DeleteDirectoryResponse();
|
|
}
|
|
catch (IOException)
|
|
{
|
|
System.Diagnostics.Debug.Print("[{0}] DeleteDirectory: Cannot delete '{1}'", DateTime.Now.ToString("HH:mm:ss:ffff"), request.DirectoryName);
|
|
header.Status = NTStatus.STATUS_CANNOT_DELETE;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
System.Diagnostics.Debug.Print("[{0}] DeleteDirectory: Cannot delete '{1}', Access Denied", DateTime.Now.ToString("HH:mm:ss:ffff"), request.DirectoryName);
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE_DIRECTORY);
|
|
}
|
|
}
|
|
|
|
internal static SMB1Command GetCheckDirectoryResponse(SMB1Header header, CheckDirectoryRequest request, FileSystemShare share)
|
|
{
|
|
IFileSystem fileSystem = share.FileSystem;
|
|
FileSystemEntry entry = fileSystem.GetEntry(request.DirectoryName);
|
|
if (entry == null || !entry.IsDirectory)
|
|
{
|
|
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
return new ErrorResponse(CommandName.SMB_COM_CHECK_DIRECTORY);
|
|
}
|
|
|
|
return new CheckDirectoryResponse();
|
|
}
|
|
|
|
internal static SMB1Command GetDeleteResponse(SMB1Header header, DeleteRequest request, FileSystemShare share, SMB1ConnectionState state)
|
|
{
|
|
string userName = state.GetConnectedUserName(header.UID);
|
|
if (!share.HasWriteAccess(userName))
|
|
{
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
|
}
|
|
IFileSystem fileSystem = share.FileSystem;
|
|
|
|
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
|
if (entry == null)
|
|
{
|
|
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
|
}
|
|
|
|
if (!entry.IsDirectory && (request.SearchAttributes & SMBFileAttributes.Directory) > 0
|
|
|| entry.IsDirectory && (request.SearchAttributes & SMBFileAttributes.Directory) == 0)
|
|
{
|
|
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
|
}
|
|
|
|
try
|
|
{
|
|
fileSystem.Delete(request.FileName);
|
|
return new DeleteResponse();
|
|
}
|
|
catch (IOException)
|
|
{
|
|
System.Diagnostics.Debug.Print("[{0}] Delete: Cannot delete '{1}'", DateTime.Now.ToString("HH:mm:ss:ffff"), request.FileName);
|
|
header.Status = NTStatus.STATUS_CANNOT_DELETE;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
System.Diagnostics.Debug.Print("[{0}] DeleteDirectory: Cannot delete '{1}', Access Denied", DateTime.Now.ToString("HH:mm:ss:ffff"), request.FileName);
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_DELETE);
|
|
}
|
|
}
|
|
|
|
internal static SMB1Command GetRenameResponse(SMB1Header header, RenameRequest request, FileSystemShare share, SMB1ConnectionState state)
|
|
{
|
|
string userName = state.GetConnectedUserName(header.UID);
|
|
if (!share.HasWriteAccess(userName))
|
|
{
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
|
}
|
|
IFileSystem fileSystem = share.FileSystem;
|
|
|
|
FileSystemEntry sourceEntry = fileSystem.GetEntry(request.OldFileName);
|
|
if (sourceEntry == null)
|
|
{
|
|
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
|
}
|
|
|
|
// The file must not already exist unless we just want to upcase / downcase a filename letter
|
|
FileSystemEntry destinationEntry = fileSystem.GetEntry(request.NewFileName);
|
|
if (destinationEntry != null &&
|
|
!String.Equals(request.OldFileName, request.NewFileName, StringComparison.InvariantCultureIgnoreCase))
|
|
{
|
|
// The new file already exists.
|
|
header.Status = NTStatus.STATUS_OBJECT_NAME_COLLISION;
|
|
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
|
}
|
|
|
|
try
|
|
{
|
|
fileSystem.Move(request.OldFileName, request.NewFileName);
|
|
return new RenameResponse();
|
|
}
|
|
catch (IOException)
|
|
{
|
|
System.Diagnostics.Debug.Print("[{0}] Rename: Sharing violation renaming '{1}'", DateTime.Now.ToString("HH:mm:ss:ffff"), request.OldFileName);
|
|
header.Status = NTStatus.STATUS_SHARING_VIOLATION;
|
|
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
|
}
|
|
catch (UnauthorizedAccessException)
|
|
{
|
|
System.Diagnostics.Debug.Print("[{0}] Rename: Cannot rename '{1}', Access Denied", DateTime.Now.ToString("HH:mm:ss:ffff"), request.OldFileName);
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_RENAME);
|
|
}
|
|
}
|
|
|
|
internal static SMB1Command GetQueryInformationResponse(SMB1Header header, QueryInformationRequest request, FileSystemShare share)
|
|
{
|
|
IFileSystem fileSystem = share.FileSystem;
|
|
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
|
if (entry == null)
|
|
{
|
|
header.Status = NTStatus.STATUS_OBJECT_PATH_INVALID;
|
|
return new ErrorResponse(CommandName.SMB_COM_QUERY_INFORMATION);
|
|
}
|
|
|
|
QueryInformationResponse response = new QueryInformationResponse();
|
|
response.FileAttributes = InfoHelper.GetFileAttributes(entry);
|
|
response.LastWriteTime = entry.LastWriteTime;
|
|
response.FileSize = (uint)Math.Min(UInt32.MaxValue, entry.Size);
|
|
|
|
return response;
|
|
}
|
|
|
|
internal static SMB1Command GetSetInformationResponse(SMB1Header header, SetInformationRequest request, FileSystemShare share, SMB1ConnectionState state)
|
|
{
|
|
string userName = state.GetConnectedUserName(header.UID);
|
|
if (!share.HasWriteAccess(userName))
|
|
{
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
|
}
|
|
IFileSystem fileSystem = share.FileSystem;
|
|
|
|
FileSystemEntry entry = fileSystem.GetEntry(request.FileName);
|
|
if (entry == null)
|
|
{
|
|
header.Status = NTStatus.STATUS_NO_SUCH_FILE;
|
|
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION);
|
|
}
|
|
|
|
bool? isHidden = null;
|
|
bool? isReadOnly = null;
|
|
bool? isArchived = null;
|
|
if ((request.FileAttributes & SMBFileAttributes.Hidden) > 0)
|
|
{
|
|
isHidden = true;
|
|
}
|
|
if ((request.FileAttributes & SMBFileAttributes.ReadOnly) > 0)
|
|
{
|
|
isReadOnly = true;
|
|
}
|
|
if ((request.FileAttributes & SMBFileAttributes.Archive) > 0)
|
|
{
|
|
isArchived = true;
|
|
}
|
|
fileSystem.SetAttributes(request.FileName, isHidden, isReadOnly, isArchived);
|
|
|
|
if (request.LastWriteTime != SMB1Helper.UTimeNotSpecified)
|
|
{
|
|
fileSystem.SetDates(request.FileName, null, request.LastWriteTime, null);
|
|
}
|
|
|
|
return new SetInformationResponse();
|
|
}
|
|
|
|
internal static SMB1Command GetSetInformation2Response(SMB1Header header, SetInformation2Request request, FileSystemShare share, SMB1ConnectionState state)
|
|
{
|
|
string openedFilePath = state.GetOpenedFilePath(request.FID);
|
|
if (openedFilePath == null)
|
|
{
|
|
header.Status = NTStatus.STATUS_SMB_BAD_FID;
|
|
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
|
}
|
|
|
|
string userName = state.GetConnectedUserName(header.UID);
|
|
if (!share.HasWriteAccess(userName))
|
|
{
|
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
|
return new ErrorResponse(CommandName.SMB_COM_SET_INFORMATION2);
|
|
}
|
|
IFileSystem fileSystem = share.FileSystem;
|
|
|
|
fileSystem.SetDates(openedFilePath, request.CreationDateTime, request.LastWriteDateTime, request.LastAccessDateTime);
|
|
return new SetInformation2Response();
|
|
}
|
|
}
|
|
}
|