RPCPipeStream.cs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. /* Copyright (C) 2017 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 (rpcRequest is RequestPDU)
  54. {
  55. // if BindPDU was not received, we ignore any subsequent RPC packets
  56. if (m_maxTransmitFragmentSize.HasValue)
  57. {
  58. List<ResponsePDU> responsePDUs = RemoteServiceHelper.GetRPCResponse((RequestPDU)rpcRequest, m_service, m_maxTransmitFragmentSize.Value);
  59. foreach (ResponsePDU responsePDU in responsePDUs)
  60. {
  61. Append(responsePDU.GetBytes());
  62. }
  63. }
  64. }
  65. else
  66. {
  67. throw new NotImplementedException("Unsupported RPC Packet Type");
  68. }
  69. }
  70. private void Append(byte[] buffer)
  71. {
  72. MemoryStream stream = new MemoryStream(buffer);
  73. m_outputStreams.Add(stream);
  74. }
  75. public override void Flush()
  76. {
  77. }
  78. public override void Close()
  79. {
  80. }
  81. public override long Seek(long offset, SeekOrigin origin)
  82. {
  83. throw new NotSupportedException();
  84. }
  85. public override void SetLength(long value)
  86. {
  87. throw new NotSupportedException();
  88. }
  89. public override bool CanSeek
  90. {
  91. get
  92. {
  93. return false;
  94. }
  95. }
  96. public override bool CanRead
  97. {
  98. get
  99. {
  100. return true;
  101. }
  102. }
  103. public override bool CanWrite
  104. {
  105. get
  106. {
  107. return true;
  108. }
  109. }
  110. public override long Length
  111. {
  112. get
  113. {
  114. // Stream.Length only works on Stream implementations where seeking is available.
  115. throw new NotSupportedException();
  116. }
  117. }
  118. public override long Position
  119. {
  120. get
  121. {
  122. throw new NotSupportedException();
  123. }
  124. set
  125. {
  126. throw new NotSupportedException();
  127. }
  128. }
  129. /// <summary>
  130. /// The length of the first message available in the pipe
  131. /// </summary>
  132. public int MessageLength
  133. {
  134. get
  135. {
  136. if (m_outputStreams.Count > 0)
  137. {
  138. return (int)m_outputStreams[0].Length;
  139. }
  140. else
  141. {
  142. return 0;
  143. }
  144. }
  145. }
  146. }
  147. }