SMBLibrary/SMBLibrary/NTFileStore/NamedPipeStore.cs

181 lines
7 KiB
C#

/* Copyright (C) 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 SMBLibrary.RPC;
using SMBLibrary.Services;
using Utilities;
namespace SMBLibrary
{
public class NamedPipeStore : INTFileStore
{
private List<RemoteService> m_services;
public NamedPipeStore(List<RemoteService> services)
{
m_services = services;
}
public NTStatus CreateFile(out object handle, out FileStatus fileStatus, string path, AccessMask desiredAccess, FileAttributes fileAttributes, ShareAccess shareAccess, CreateDisposition createDisposition, CreateOptions createOptions, SecurityContext securityContext)
{
fileStatus = FileStatus.FILE_DOES_NOT_EXIST;
// It is possible to have a named pipe that does not use RPC (e.g. MS-WSP),
// However this is not currently needed by our implementation.
RemoteService service = GetService(path);
if (service != null)
{
// All instances of a named pipe share the same pipe name, but each instance has its own buffers and handles,
// and provides a separate conduit for client/server communication.
RPCPipeStream stream = new RPCPipeStream(service);
handle = new FileHandle(path, false, stream, false);
fileStatus = FileStatus.FILE_OPENED;
return NTStatus.STATUS_SUCCESS;
}
handle = null;
return NTStatus.STATUS_OBJECT_PATH_NOT_FOUND;
}
public NTStatus CloseFile(object handle)
{
FileHandle fileHandle = (FileHandle)handle;
if (fileHandle.Stream != null)
{
fileHandle.Stream.Close();
}
return NTStatus.STATUS_SUCCESS;
}
private RemoteService GetService(string path)
{
if (path.StartsWith(@"\"))
{
path = path.Substring(1);
}
foreach (RemoteService service in m_services)
{
if (String.Equals(path, service.PipeName, StringComparison.InvariantCultureIgnoreCase))
{
return service;
}
}
return null;
}
public NTStatus ReadFile(out byte[] data, object handle, long offset, int maxCount)
{
Stream stream = ((FileHandle)handle).Stream;
data = new byte[maxCount];
int bytesRead = stream.Read(data, 0, maxCount);
if (bytesRead < maxCount)
{
// EOF, we must trim the response data array
data = ByteReader.ReadBytes(data, 0, bytesRead);
}
return NTStatus.STATUS_SUCCESS;
}
public NTStatus WriteFile(out int numberOfBytesWritten, object handle, long offset, byte[] data)
{
Stream stream = ((FileHandle)handle).Stream;
stream.Write(data, 0, data.Length);
numberOfBytesWritten = data.Length;
return NTStatus.STATUS_SUCCESS;
}
public NTStatus FlushFileBuffers(object handle)
{
FileHandle fileHandle = (FileHandle)handle;
if (fileHandle.Stream != null)
{
fileHandle.Stream.Flush();
}
return NTStatus.STATUS_SUCCESS;
}
public NTStatus DeviceIOControl(object handle, uint ctlCode, byte[] input, out byte[] output, int maxOutputLength)
{
output = null;
if (ctlCode == (uint)IoControlCode.FSCTL_PIPE_TRANSCEIVE)
{
int numberOfBytesWritten;
NTStatus writeStatus = WriteFile(out numberOfBytesWritten, handle, 0, input);
if (writeStatus != NTStatus.STATUS_SUCCESS)
{
return writeStatus;
}
int messageLength = ((RPCPipeStream)((FileHandle)handle).Stream).MessageLength;
NTStatus readStatus = ReadFile(out output, handle, 0, maxOutputLength);
if (readStatus != NTStatus.STATUS_SUCCESS)
{
return readStatus;
}
if (output.Length < messageLength)
{
return NTStatus.STATUS_BUFFER_OVERFLOW;
}
else
{
return NTStatus.STATUS_SUCCESS;
}
}
return NTStatus.STATUS_NOT_SUPPORTED;
}
public NTStatus QueryDirectory(out List<QueryDirectoryFileInformation> result, object directoryHandle, string fileName, FileInformationClass informationClass)
{
result = null;
return NTStatus.STATUS_NOT_SUPPORTED;
}
public NTStatus GetFileInformation(out FileInformation result, object handle, FileInformationClass informationClass)
{
switch (informationClass)
{
case FileInformationClass.FileBasicInformation:
{
FileBasicInformation information = new FileBasicInformation();
information.FileAttributes = FileAttributes.Temporary;
result = information;
return NTStatus.STATUS_SUCCESS;
}
case FileInformationClass.FileStandardInformation:
{
FileStandardInformation information = new FileStandardInformation();
information.DeletePending = false;
result = information;
return NTStatus.STATUS_SUCCESS;
}
case FileInformationClass.FileNetworkOpenInformation:
{
FileNetworkOpenInformation information = new FileNetworkOpenInformation();
information.FileAttributes = FileAttributes.Temporary;
result = information;
return NTStatus.STATUS_SUCCESS;
}
default:
result = null;
return NTStatus.STATUS_INVALID_INFO_CLASS;
}
}
public NTStatus SetFileInformation(object handle, FileInformation information)
{
return NTStatus.STATUS_NOT_SUPPORTED;
}
public NTStatus GetFileSystemInformation(out FileSystemInformation result, FileSystemInformationClass informationClass)
{
result = null;
return NTStatus.STATUS_NOT_SUPPORTED;
}
}
}