mirror of
https://github.com/TalAloni/SMBLibrary.git
synced 2025-07-25 10:28:15 +02:00
Added RPCPipeStream to improve read / write abstraction
This commit is contained in:
parent
3f36591e14
commit
211adcc78a
8 changed files with 157 additions and 64 deletions
|
@ -139,6 +139,7 @@
|
||||||
<Compile Include="Services\Enums\PlatformName.cs" />
|
<Compile Include="Services\Enums\PlatformName.cs" />
|
||||||
<Compile Include="Services\RemoteService.cs" />
|
<Compile Include="Services\RemoteService.cs" />
|
||||||
<Compile Include="Services\RemoteServiceHelper.cs" />
|
<Compile Include="Services\RemoteServiceHelper.cs" />
|
||||||
|
<Compile Include="Services\RPCPipeStream.cs" />
|
||||||
<Compile Include="Services\ServerService\Enums\Permissions.cs" />
|
<Compile Include="Services\ServerService\Enums\Permissions.cs" />
|
||||||
<Compile Include="Services\ServerService\Enums\ServerType.cs" />
|
<Compile Include="Services\ServerService\Enums\ServerType.cs" />
|
||||||
<Compile Include="Services\ServerService\EnumStructures\ShareTypeExtended.cs" />
|
<Compile Include="Services\ServerService\EnumStructures\ShareTypeExtended.cs" />
|
||||||
|
|
|
@ -28,8 +28,6 @@ namespace SMBLibrary.Server
|
||||||
// Key is FID
|
// Key is FID
|
||||||
private Dictionary<ushort, OpenedFileObject> m_openedFiles = new Dictionary<ushort, OpenedFileObject>();
|
private Dictionary<ushort, OpenedFileObject> m_openedFiles = new Dictionary<ushort, OpenedFileObject>();
|
||||||
private ushort m_nextFID = 1;
|
private ushort m_nextFID = 1;
|
||||||
// Key is FID
|
|
||||||
private Dictionary<ushort, byte[]> m_namedPipeResponse = new Dictionary<ushort, byte[]>();
|
|
||||||
|
|
||||||
// Key is PID
|
// Key is PID
|
||||||
public Dictionary<uint, ProcessStateObject> ProcessStateList = new Dictionary<uint, ProcessStateObject>();
|
public Dictionary<uint, ProcessStateObject> ProcessStateList = new Dictionary<uint, ProcessStateObject>();
|
||||||
|
@ -262,25 +260,6 @@ namespace SMBLibrary.Server
|
||||||
m_openedFiles.Remove(fileID);
|
m_openedFiles.Remove(fileID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void StoreNamedPipeReply(ushort fileID, byte[] response)
|
|
||||||
{
|
|
||||||
m_namedPipeResponse.Add(fileID, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] RetrieveNamedPipeReply(ushort fileID)
|
|
||||||
{
|
|
||||||
if (m_namedPipeResponse.ContainsKey(fileID))
|
|
||||||
{
|
|
||||||
byte[] result = m_namedPipeResponse[fileID];
|
|
||||||
m_namedPipeResponse.Remove(fileID);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return new byte[0];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public uint? GetMaxDataCount(uint processID)
|
public uint? GetMaxDataCount(uint processID)
|
||||||
{
|
{
|
||||||
ProcessStateObject processState = GetProcessState(processID);
|
ProcessStateObject processState = GetProcessState(processID);
|
||||||
|
|
|
@ -22,10 +22,10 @@ namespace SMBLibrary.Server.SMB1
|
||||||
string path = request.FileName;
|
string path = request.FileName;
|
||||||
if (share is NamedPipeShare)
|
if (share is NamedPipeShare)
|
||||||
{
|
{
|
||||||
RemoteService service = ((NamedPipeShare)share).GetService(path);
|
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
|
||||||
if (service != null)
|
if (pipeStream != null)
|
||||||
{
|
{
|
||||||
ushort? fileID = state.AddOpenedFile(path);
|
ushort? fileID = state.AddOpenedFile(path, pipeStream);
|
||||||
if (!fileID.HasValue)
|
if (!fileID.HasValue)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||||
|
|
|
@ -22,10 +22,10 @@ namespace SMBLibrary.Server.SMB1
|
||||||
string path = request.FileName;
|
string path = request.FileName;
|
||||||
if (share is NamedPipeShare)
|
if (share is NamedPipeShare)
|
||||||
{
|
{
|
||||||
RemoteService service = ((NamedPipeShare)share).GetService(path);
|
Stream pipeStream = ((NamedPipeShare)share).OpenPipe(path);
|
||||||
if (service != null)
|
if (pipeStream != null)
|
||||||
{
|
{
|
||||||
ushort? fileID = state.AddOpenedFile(path);
|
ushort? fileID = state.AddOpenedFile(path, pipeStream);
|
||||||
if (!fileID.HasValue)
|
if (!fileID.HasValue)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
header.Status = NTStatus.STATUS_TOO_MANY_OPENED_FILES;
|
||||||
|
|
|
@ -72,16 +72,20 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
string openedFilePath = openedFile.Path;
|
string openedFilePath = openedFile.Path;
|
||||||
|
Stream stream = openedFile.Stream;
|
||||||
if (share is NamedPipeShare)
|
if (share is NamedPipeShare)
|
||||||
{
|
{
|
||||||
return state.RetrieveNamedPipeReply(FID);
|
byte[] 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 data;
|
||||||
}
|
}
|
||||||
else // FileSystemShare
|
else // FileSystemShare
|
||||||
{
|
{
|
||||||
FileSystemShare fileSystemShare = (FileSystemShare)share;
|
|
||||||
IFileSystem fileSystem = fileSystemShare.FileSystem;
|
|
||||||
Stream stream = openedFile.Stream;
|
|
||||||
|
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
{
|
{
|
||||||
|
@ -176,26 +180,14 @@ namespace SMBLibrary.Server.SMB1
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
string openedFilePath = openedFile.Path;
|
string openedFilePath = openedFile.Path;
|
||||||
|
Stream stream = openedFile.Stream;
|
||||||
if (share is NamedPipeShare)
|
if (share is NamedPipeShare)
|
||||||
{
|
{
|
||||||
RemoteService service = ((NamedPipeShare)share).GetService(openedFilePath);
|
stream.Write(data, 0, data.Length);
|
||||||
if (service != null)
|
return (uint)data.Length;
|
||||||
{
|
|
||||||
RPCPDU rpcRequest = RPCPDU.GetPDU(data, 0);
|
|
||||||
RPCPDU rpcReply = RemoteServiceHelper.GetRPCReply(rpcRequest, service);
|
|
||||||
byte[] replyData = rpcReply.GetBytes();
|
|
||||||
state.StoreNamedPipeReply(FID, replyData);
|
|
||||||
return (uint)data.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This code should not execute unless the SMB request (sequence) is invalid
|
|
||||||
header.Status = NTStatus.STATUS_INVALID_SMB;
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else // FileSystemShare
|
else // FileSystemShare
|
||||||
{
|
{
|
||||||
Stream stream = openedFile.Stream;
|
|
||||||
if (stream == null)
|
if (stream == null)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
header.Status = NTStatus.STATUS_ACCESS_DENIED;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* Copyright (C) 2014-2017 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
|
/* 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
|
* 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,
|
* the GNU Lesser Public License as published by the Free Software Foundation,
|
||||||
|
@ -18,26 +18,17 @@ 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)
|
||||||
{
|
{
|
||||||
string openedFilePath = state.GetOpenedFilePath(subcommand.FID);
|
OpenedFileObject openedFile = state.GetOpenedFileObject(subcommand.FID);
|
||||||
if (openedFilePath == null)
|
if (openedFile == null)
|
||||||
{
|
{
|
||||||
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
header.Status = NTStatus.STATUS_INVALID_HANDLE;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransactionTransactNamedPipeResponse response = new TransactionTransactNamedPipeResponse();
|
TransactionTransactNamedPipeResponse response = new TransactionTransactNamedPipeResponse();
|
||||||
RemoteService service = share.GetService(openedFilePath);
|
openedFile.Stream.Write(subcommand.WriteData, 0, subcommand.WriteData.Length);
|
||||||
if (service != null)
|
response.ReadData = ByteReader.ReadAllBytes(openedFile.Stream);
|
||||||
{
|
return response;
|
||||||
RPCPDU rpcRequest = RPCPDU.GetPDU(subcommand.WriteData, 0);
|
|
||||||
RPCPDU rpcReply = RemoteServiceHelper.GetRPCReply(rpcRequest, service);
|
|
||||||
response.ReadData = rpcReply.GetBytes();
|
|
||||||
return response;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This code should not execute unless the request sequence is invalid
|
|
||||||
header.Status = NTStatus.STATUS_INVALID_SMB;
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.IO;
|
||||||
using SMBLibrary.RPC;
|
using SMBLibrary.RPC;
|
||||||
using SMBLibrary.Services;
|
using SMBLibrary.Services;
|
||||||
|
|
||||||
|
@ -23,7 +23,21 @@ namespace SMBLibrary.Server
|
||||||
this.Add(new WorkstationService(Environment.MachineName, Environment.MachineName));
|
this.Add(new WorkstationService(Environment.MachineName, Environment.MachineName));
|
||||||
}
|
}
|
||||||
|
|
||||||
public RemoteService GetService(string path)
|
public Stream OpenPipe(string path)
|
||||||
|
{
|
||||||
|
// 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.
|
||||||
|
return new RPCPipeStream(service);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private RemoteService GetService(string path)
|
||||||
{
|
{
|
||||||
foreach (RemoteService service in this)
|
foreach (RemoteService service in this)
|
||||||
{
|
{
|
||||||
|
|
116
SMBLibrary/Services/RPCPipeStream.cs
Normal file
116
SMBLibrary/Services/RPCPipeStream.cs
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
namespace SMBLibrary.Services
|
||||||
|
{
|
||||||
|
public class RPCPipeStream : Stream
|
||||||
|
{
|
||||||
|
private RemoteService m_service;
|
||||||
|
private MemoryStream m_outputStream;
|
||||||
|
|
||||||
|
public RPCPipeStream(RemoteService service)
|
||||||
|
{
|
||||||
|
m_service = service;
|
||||||
|
m_outputStream = new MemoryStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
return m_outputStream.Read(buffer, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
int lengthOfPDUs = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
RPCPDU rpcRequest = RPCPDU.GetPDU(buffer, offset);
|
||||||
|
lengthOfPDUs += rpcRequest.FragmentLength;
|
||||||
|
RPCPDU rpcReply = RemoteServiceHelper.GetRPCReply(rpcRequest, m_service);
|
||||||
|
byte[] replyData = rpcReply.GetBytes();
|
||||||
|
Append(replyData);
|
||||||
|
}
|
||||||
|
while (lengthOfPDUs < count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Append(byte[] buffer)
|
||||||
|
{
|
||||||
|
long position = m_outputStream.Position;
|
||||||
|
m_outputStream.Position = m_outputStream.Length;
|
||||||
|
m_outputStream.Write(buffer, 0, buffer.Length);
|
||||||
|
m_outputStream.Seek(position, SeekOrigin.Begin);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Close()
|
||||||
|
{
|
||||||
|
m_outputStream.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanSeek
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanRead
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_outputStream.CanRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_outputStream.CanWrite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Length
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
// Stream.Length only works on Stream implementations where seeking is available.
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue