RPCPipeStream.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. /* Copyright (C) 2017-2018 Tal Aloni <tal.aloni.il@gmail.com>. All rights reserved.
  2. *
  3. * You can redistribute this program and/or modify it under the terms of
  4. * the GNU Lesser Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.IO;
  10. using SMBLibrary.RPC;
  11. namespace SMBLibrary.Services
  12. {
  13. public class RPCPipeStream : Stream
  14. {
  15. private RemoteService m_service;
  16. private List<MemoryStream> m_outputStreams; // A stream for each message in order to support message mode named pipe
  17. private int? m_maxTransmitFragmentSize;
  18. public RPCPipeStream(RemoteService service)
  19. {
  20. m_service = service;
  21. m_outputStreams = new List<MemoryStream>();
  22. }
  23. public override int Read(byte[] buffer, int offset, int count)
  24. {
  25. if (m_outputStreams.Count > 0)
  26. {
  27. int result = m_outputStreams[0].Read(buffer, offset, count);
  28. if (m_outputStreams[0].Position == m_outputStreams[0].Length)
  29. {
  30. m_outputStreams.RemoveAt(0);
  31. }
  32. return result;
  33. }
  34. else
  35. {
  36. return 0;
  37. }
  38. }
  39. public override void Write(byte[] buffer, int offset, int count)
  40. {
  41. // [MC-CIFS] In message mode, the system treats the bytes read or written in each I/O operation to the pipe as a message unit.
  42. RPCPDU rpcRequest = RPCPDU.GetPDU(buffer, offset);
  43. ProcessRPCRequest(rpcRequest);
  44. }
  45. private void ProcessRPCRequest(RPCPDU rpcRequest)
  46. {
  47. if (rpcRequest is BindPDU)
  48. {
  49. BindAckPDU bindAckPDU = RemoteServiceHelper.GetRPCBindResponse((BindPDU)rpcRequest, m_service);
  50. m_maxTransmitFragmentSize = bindAckPDU.MaxTransmitFragmentSize;
  51. Append(bindAckPDU.GetBytes());
  52. }
  53. else if (m_maxTransmitFragmentSize.HasValue && rpcRequest is RequestPDU) // if BindPDU was not received, we treat as protocol error
  54. {
  55. List<RPCPDU> responsePDUs = RemoteServiceHelper.GetRPCResponse((RequestPDU)rpcRequest, m_service, m_maxTransmitFragmentSize.Value);
  56. foreach (RPCPDU responsePDU in responsePDUs)
  57. {
  58. Append(responsePDU.GetBytes());
  59. }
  60. }
  61. else
  62. {
  63. FaultPDU faultPDU = new FaultPDU();
  64. faultPDU.Flags = PacketFlags.FirstFragment | PacketFlags.LastFragment;
  65. faultPDU.DataRepresentation = new DataRepresentationFormat(CharacterFormat.ASCII, ByteOrder.LittleEndian, FloatingPointRepresentation.IEEE);
  66. faultPDU.CallID = 0;
  67. faultPDU.AllocationHint = RPCPDU.CommonFieldsLength + FaultPDU.FaultFieldsLength;
  68. faultPDU.Status = FaultStatus.ProtocolError;
  69. Append(faultPDU.GetBytes());
  70. }
  71. }
  72. private void Append(byte[] buffer)
  73. {
  74. MemoryStream stream = new MemoryStream(buffer);
  75. m_outputStreams.Add(stream);
  76. }
  77. public override void Flush()
  78. {
  79. }
  80. public override void Close()
  81. {
  82. }
  83. public override long Seek(long offset, SeekOrigin origin)
  84. {
  85. throw new NotSupportedException();
  86. }
  87. public override void SetLength(long value)
  88. {
  89. throw new NotSupportedException();
  90. }
  91. public override bool CanSeek
  92. {
  93. get
  94. {
  95. return false;
  96. }
  97. }
  98. public override bool CanRead
  99. {
  100. get
  101. {
  102. return true;
  103. }
  104. }
  105. public override bool CanWrite
  106. {
  107. get
  108. {
  109. return true;
  110. }
  111. }
  112. public override long Length
  113. {
  114. get
  115. {
  116. // Stream.Length only works on Stream implementations where seeking is available.
  117. throw new NotSupportedException();
  118. }
  119. }
  120. public override long Position
  121. {
  122. get
  123. {
  124. throw new NotSupportedException();
  125. }
  126. set
  127. {
  128. throw new NotSupportedException();
  129. }
  130. }
  131. /// <summary>
  132. /// The length of the first message available in the pipe
  133. /// </summary>
  134. public int MessageLength
  135. {
  136. get
  137. {
  138. if (m_outputStreams.Count > 0)
  139. {
  140. return (int)m_outputStreams[0].Length;
  141. }
  142. else
  143. {
  144. return 0;
  145. }
  146. }
  147. }
  148. }
  149. }