RemoteServiceHelper.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. /* Copyright (C) 2014-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.Text;
  10. using SMBLibrary.RPC;
  11. using Utilities;
  12. namespace SMBLibrary.Services
  13. {
  14. public class RemoteServiceHelper
  15. {
  16. // v1 - DCE 1.1: Remote Procedure Call
  17. // v2 - [MS-RPCE] 2.2.4.12 NDR Transfer Syntax Identifier
  18. public static readonly Guid NDRTransferSyntaxIdentifier = new Guid("8A885D04-1CEB-11C9-9FE8-08002B104860");
  19. public const int NDRTransferSyntaxVersion = 2;
  20. // v1 - [MS-RPCE] 3.3.1.5.3 - Bind Time Feature Negotiation
  21. // Windows will reject this:
  22. //private static readonly Guid BindTimeFeatureIdentifier1 = new Guid("6CB71C2C-9812-4540-0100-000000000000");
  23. // Windows will return NegotiationResult.NegotiateAck:
  24. public static readonly Guid BindTimeFeatureIdentifier3 = new Guid("6CB71C2C-9812-4540-0300-000000000000");
  25. public const int BindTimeFeatureIdentifierVersion = 1;
  26. private static uint m_associationGroupID = 1;
  27. public static BindAckPDU GetRPCBindResponse(BindPDU bindPDU, RemoteService service)
  28. {
  29. BindAckPDU bindAckPDU = new BindAckPDU();
  30. bindAckPDU.Flags = PacketFlags.FirstFragment | PacketFlags.LastFragment;
  31. bindAckPDU.DataRepresentation = bindPDU.DataRepresentation;
  32. bindAckPDU.CallID = bindPDU.CallID;
  33. // See DCE 1.1: Remote Procedure Call - 12.6.3.6
  34. // The client should set the assoc_group_id field either to 0 (zero), to indicate a new association group,
  35. // or to the known value. When the server receives a value of 0, this indicates that the client
  36. // has requested a new association group, and it assigns a server unique value to the group.
  37. if (bindPDU.AssociationGroupID == 0)
  38. {
  39. bindAckPDU.AssociationGroupID = m_associationGroupID;
  40. m_associationGroupID++;
  41. if (m_associationGroupID == 0)
  42. {
  43. m_associationGroupID++;
  44. }
  45. }
  46. else
  47. {
  48. bindAckPDU.AssociationGroupID = bindPDU.AssociationGroupID;
  49. }
  50. bindAckPDU.SecondaryAddress = @"\PIPE\" + service.PipeName;
  51. bindAckPDU.MaxTransmitFragmentSize = bindPDU.MaxReceiveFragmentSize;
  52. bindAckPDU.MaxReceiveFragmentSize = bindPDU.MaxTransmitFragmentSize;
  53. foreach (ContextElement element in bindPDU.ContextList)
  54. {
  55. ResultElement resultElement = new ResultElement();
  56. if (element.AbstractSyntax.InterfaceUUID.Equals(service.InterfaceGuid))
  57. {
  58. int index = IndexOfSupportedTransferSyntax(element.TransferSyntaxList);
  59. if (index >= 0)
  60. {
  61. resultElement.Result = NegotiationResult.Acceptance;
  62. resultElement.TransferSyntax = element.TransferSyntaxList[index];
  63. }
  64. else if (element.TransferSyntaxList.Contains(new SyntaxID(BindTimeFeatureIdentifier3, 1)))
  65. {
  66. // [MS-RPCE] 3.3.1.5.3
  67. // If the server supports bind time feature negotiation, it MUST reply with the result
  68. // field in the p_result_t structure of the bind_ack PDU equal to negotiate_ack.
  69. resultElement.Result = NegotiationResult.NegotiateAck;
  70. resultElement.Reason = RejectionReason.AbstractSyntaxNotSupported;
  71. }
  72. else
  73. {
  74. resultElement.Result = NegotiationResult.ProviderRejection;
  75. resultElement.Reason = RejectionReason.ProposedTransferSyntaxesNotSupported;
  76. }
  77. }
  78. else
  79. {
  80. resultElement.Result = NegotiationResult.ProviderRejection;
  81. resultElement.Reason = RejectionReason.AbstractSyntaxNotSupported;
  82. }
  83. bindAckPDU.ResultList.Add(resultElement);
  84. }
  85. return bindAckPDU;
  86. }
  87. private static int IndexOfSupportedTransferSyntax(List<SyntaxID> syntaxList)
  88. {
  89. List<SyntaxID> supportedTransferSyntaxes = new List<SyntaxID>();
  90. supportedTransferSyntaxes.Add(new SyntaxID(NDRTransferSyntaxIdentifier, 1));
  91. // [MS-RPCE] Version 2.0 data representation protocol:
  92. supportedTransferSyntaxes.Add(new SyntaxID(NDRTransferSyntaxIdentifier, 2));
  93. for(int index = 0; index < syntaxList.Count; index++)
  94. {
  95. if (supportedTransferSyntaxes.Contains(syntaxList[index]))
  96. {
  97. return index;
  98. }
  99. }
  100. return -1;
  101. }
  102. public static List<ResponsePDU> GetRPCResponse(RequestPDU requestPDU, RemoteService service, int maxTransmitFragmentSize)
  103. {
  104. byte[] responseBytes = service.GetResponseBytes(requestPDU.OpNum, requestPDU.Data);
  105. int offset = 0;
  106. List<ResponsePDU> result = new List<ResponsePDU>();
  107. int maxPDUDataLength = maxTransmitFragmentSize - RPCPDU.CommonFieldsLength - ResponsePDU.ResponseFieldsLength;
  108. do
  109. {
  110. ResponsePDU responsePDU = new ResponsePDU();
  111. int pduDataLength = Math.Min(responseBytes.Length - offset, maxPDUDataLength);
  112. responsePDU.DataRepresentation = requestPDU.DataRepresentation;
  113. responsePDU.CallID = requestPDU.CallID;
  114. responsePDU.AllocationHint = (uint)(responseBytes.Length - offset);
  115. responsePDU.Data = ByteReader.ReadBytes(responseBytes, offset, pduDataLength);
  116. if (offset == 0)
  117. {
  118. responsePDU.Flags |= PacketFlags.FirstFragment;
  119. }
  120. if (offset + pduDataLength == responseBytes.Length)
  121. {
  122. responsePDU.Flags |= PacketFlags.LastFragment;
  123. }
  124. result.Add(responsePDU);
  125. offset += pduDataLength;
  126. }
  127. while (offset < responseBytes.Length);
  128. return result;
  129. }
  130. }
  131. }