RemoteServiceHelper.cs 6.0 KB

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