ruby_smb 1.0.5 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +3 -2
  5. data/Gemfile +6 -2
  6. data/README.md +35 -47
  7. data/examples/anonymous_auth.rb +3 -3
  8. data/examples/append_file.rb +10 -8
  9. data/examples/authenticate.rb +9 -5
  10. data/examples/delete_file.rb +8 -6
  11. data/examples/enum_registry_key.rb +29 -0
  12. data/examples/enum_registry_values.rb +31 -0
  13. data/examples/list_directory.rb +8 -6
  14. data/examples/negotiate.rb +51 -8
  15. data/examples/negotiate_with_netbios_service.rb +9 -5
  16. data/examples/net_share_enum_all.rb +6 -4
  17. data/examples/pipes.rb +13 -13
  18. data/examples/query_service_status.rb +64 -0
  19. data/examples/read_file.rb +8 -6
  20. data/examples/read_file_encryption.rb +56 -0
  21. data/examples/read_registry_key_value.rb +33 -0
  22. data/examples/rename_file.rb +9 -7
  23. data/examples/tree_connect.rb +7 -5
  24. data/examples/write_file.rb +9 -7
  25. data/lib/ruby_smb.rb +4 -1
  26. data/lib/ruby_smb/client.rb +239 -21
  27. data/lib/ruby_smb/client/authentication.rb +27 -8
  28. data/lib/ruby_smb/client/encryption.rb +62 -0
  29. data/lib/ruby_smb/client/negotiation.rb +154 -12
  30. data/lib/ruby_smb/client/signing.rb +19 -0
  31. data/lib/ruby_smb/client/tree_connect.rb +4 -4
  32. data/lib/ruby_smb/client/utils.rb +8 -7
  33. data/lib/ruby_smb/client/winreg.rb +46 -0
  34. data/lib/ruby_smb/crypto.rb +30 -0
  35. data/lib/ruby_smb/dcerpc.rb +40 -0
  36. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  37. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  38. data/lib/ruby_smb/dcerpc/error.rb +6 -0
  39. data/lib/ruby_smb/dcerpc/ndr.rb +260 -16
  40. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  41. data/lib/ruby_smb/dcerpc/request.rb +41 -9
  42. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  43. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +38 -0
  44. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  45. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  46. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  59. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  60. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  61. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  62. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  63. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  64. data/lib/ruby_smb/dcerpc/winreg.rb +421 -0
  65. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  66. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  67. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  68. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  69. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  70. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  71. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  72. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  73. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  74. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  75. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  76. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  77. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  78. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  79. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +40 -0
  80. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  81. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  82. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  83. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  84. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  85. data/lib/ruby_smb/dispatcher/socket.rb +5 -4
  86. data/lib/ruby_smb/error.rb +28 -1
  87. data/lib/ruby_smb/field/stringz16.rb +17 -1
  88. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  89. data/lib/ruby_smb/smb1/commands.rb +1 -1
  90. data/lib/ruby_smb/smb1/file.rb +8 -14
  91. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
  92. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
  93. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  94. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
  95. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
  96. data/lib/ruby_smb/smb1/pipe.rb +81 -3
  97. data/lib/ruby_smb/smb1/tree.rb +12 -3
  98. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  99. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  100. data/lib/ruby_smb/smb2/file.rb +51 -61
  101. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  102. data/lib/ruby_smb/smb2/packet.rb +2 -0
  103. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  104. data/lib/ruby_smb/smb2/packet/error_packet.rb +2 -4
  105. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
  106. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
  107. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  108. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
  109. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
  110. data/lib/ruby_smb/smb2/pipe.rb +80 -3
  111. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  112. data/lib/ruby_smb/smb2/tree.rb +32 -20
  113. data/lib/ruby_smb/version.rb +1 -1
  114. data/ruby_smb.gemspec +5 -3
  115. data/spec/lib/ruby_smb/client_spec.rb +1583 -102
  116. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  117. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  118. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  119. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1729 -0
  120. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  121. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  122. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +135 -0
  123. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  124. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  125. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  126. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  127. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  128. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  129. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  130. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  131. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  132. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  133. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  134. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  135. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  136. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  137. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  138. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  139. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  140. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  141. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  142. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  143. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  144. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  145. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  146. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  147. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +104 -0
  148. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  149. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  150. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  151. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  152. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  153. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +95 -0
  154. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  155. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +35 -0
  156. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  157. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  158. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +138 -0
  159. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  160. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  161. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  162. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +884 -0
  163. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  164. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
  165. data/spec/lib/ruby_smb/error_spec.rb +59 -0
  166. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  167. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  168. data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
  169. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  170. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  171. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  172. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  173. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +216 -147
  174. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  175. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  176. data/spec/lib/ruby_smb/smb2/file_spec.rb +146 -68
  177. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  178. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  179. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +3 -24
  180. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  181. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  182. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  183. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  184. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
  185. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +226 -148
  186. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  187. data/spec/lib/ruby_smb/smb2/tree_spec.rb +88 -9
  188. metadata +257 -81
  189. metadata.gz.sig +0 -0
  190. data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
  191. data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -0,0 +1,25 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RubySMB::Crypto::KDF do
4
+ describe '.counter_mode' do
5
+ it 'generates the expected 128-bit key' do
6
+ expected_key = "\x3c\x5e\x0a\x1b\x0a\xce\xa5\xb2\x64\x3f\xab\x78\xdc\x82\x31\x3b".b
7
+ expect(described_class.counter_mode('ki', 'label', 'context')).to eq(expected_key)
8
+ end
9
+
10
+ it 'generates the expected 256-bit key' do
11
+ expected_key =
12
+ "\x33\x4d\xa9\x6d\x24\x7e\xcb\x14\xf6\x24\x00\x97\x26\x51\xd5\xb4"\
13
+ "\x54\x5f\xda\x95\xf0\x5a\xcb\x25\x92\x57\xae\x71\x1c\x37\x20\x5b".b
14
+ expect(described_class.counter_mode('ki', 'label', 'context', length: 256)).to eq(expected_key)
15
+ end
16
+
17
+ it 'raises the expected exception when an error occurs' do
18
+ allow(OpenSSL::Digest).to receive(:new).and_raise(OpenSSL::OpenSSLError)
19
+ expect { described_class.counter_mode('ki', 'label', 'context') }.to raise_error(
20
+ RubySMB::Error::EncryptionError,
21
+ "Crypto::KDF.counter_mode OpenSSL error: OpenSSL::OpenSSLError"
22
+ )
23
+ end
24
+ end
25
+ end
@@ -31,7 +31,7 @@ RSpec.describe RubySMB::Dcerpc::BindAck do
31
31
  end
32
32
 
33
33
  it 'should have a default value of 0xFFFF' do
34
- expect(packet.max_xmit_frag).to eq 0xFFFF
34
+ expect(packet.max_xmit_frag).to eq RubySMB::Dcerpc::MAX_XMIT_FRAG
35
35
  end
36
36
  end
37
37
 
@@ -41,7 +41,7 @@ RSpec.describe RubySMB::Dcerpc::BindAck do
41
41
  end
42
42
 
43
43
  it 'should have a default value of 0xFFFF' do
44
- expect(packet.max_recv_frag).to eq 0xFFFF
44
+ expect(packet.max_recv_frag).to eq RubySMB::Dcerpc::MAX_RECV_FRAG
45
45
  end
46
46
  end
47
47
 
@@ -41,7 +41,7 @@ RSpec.describe RubySMB::Dcerpc::Bind do
41
41
  end
42
42
 
43
43
  it 'should have a default value of 0xFFFF' do
44
- expect(packet.max_xmit_frag).to eq 0xFFFF
44
+ expect(packet.max_xmit_frag).to eq RubySMB::Dcerpc::MAX_XMIT_FRAG
45
45
  end
46
46
  end
47
47
 
@@ -51,7 +51,7 @@ RSpec.describe RubySMB::Dcerpc::Bind do
51
51
  end
52
52
 
53
53
  it 'should have a default value of 0xFFFF' do
54
- expect(packet.max_recv_frag).to eq 0xFFFF
54
+ expect(packet.max_recv_frag).to eq RubySMB::Dcerpc::MAX_RECV_FRAG
55
55
  end
56
56
  end
57
57
 
@@ -0,0 +1,1729 @@
1
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrPointer do
2
+ subject(:packet) do
3
+ Class.new(described_class) do
4
+ endian :little
5
+ string :referent
6
+ end.new
7
+ end
8
+
9
+ it { is_expected.to respond_to :referent_id }
10
+
11
+ it 'is little endian' do
12
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
13
+ end
14
+
15
+ describe '#referent_id' do
16
+ it 'is a 32-bit unsigned integer' do
17
+ expect(packet.referent_id).to be_a BinData::Uint32le
18
+ end
19
+
20
+ it 'has an initial value of 0' do
21
+ expect(packet.referent_id).to eq(0)
22
+ end
23
+ end
24
+
25
+ describe '#get' do
26
+ it 'returns :null when #referent_id is 0' do
27
+ packet.referent_id = 0
28
+ expect(packet.get).to eq(:null)
29
+ end
30
+
31
+ it 'returns #referent when #referent_id is not 0' do
32
+ packet.set('spec_test')
33
+ expect(packet.get).to eq(packet.referent)
34
+ end
35
+ end
36
+
37
+ describe '#set' do
38
+ context 'when the value is :null' do
39
+ it 'clears #referent' do
40
+ expect(packet.referent).to receive(:clear)
41
+ packet.set(:null)
42
+ end
43
+
44
+ it 'sets #referent_id to 0' do
45
+ packet.set(:null)
46
+ expect(packet.referent_id).to eq(0)
47
+ end
48
+ end
49
+
50
+ context 'when the value is a string' do
51
+ let(:str) { 'spec_test' }
52
+
53
+ it 'sets #referent to the value' do
54
+ packet.set(str)
55
+ expect(packet.referent).to eq(str)
56
+ end
57
+
58
+ it 'calls #set when #referent support it' do
59
+ module TestSet; def set(v); end; end
60
+ packet.referent.extend(TestSet)
61
+ expect(packet.referent).to receive(:set).with(str)
62
+ packet.set(str)
63
+ end
64
+
65
+ it 'assigns directly to #referent when it does not support #set' do
66
+ expect(packet).to receive(:referent=).with(str)
67
+ packet.set(str)
68
+ end
69
+
70
+ it 'sets #referent_id to a random value' do
71
+ rnd = double('Random Value')
72
+ allow(packet).to receive(:rand).and_return(rnd)
73
+ expect(packet).to receive(:referent_id=).with(rnd)
74
+ packet.set(str)
75
+ end
76
+
77
+ it 'does not change #referent_id if it is already set' do
78
+ packet.referent_id = 0xCCCCCC
79
+ packet.set(str)
80
+ expect(packet.referent_id).to eq(0xCCCCCC)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#do_read' do
86
+ let(:io) { StringIO.new }
87
+
88
+ it 'asks referent_id to read the io stream' do
89
+ expect(packet.referent_id).to receive(:do_read).with(io)
90
+ packet.do_read(io)
91
+ end
92
+
93
+ context 'when it can process #referent' do
94
+ before :example do
95
+ allow(packet).to receive(:process_referent?).and_return(true)
96
+ allow(packet.referent_id).to receive(:do_read)
97
+ end
98
+
99
+ it 'asks referent to read the io stream if referent_id is not 0' do
100
+ packet.referent_id = 0xCCCC
101
+ expect(packet.referent).to receive(:do_read).with(io)
102
+ packet.do_read(io)
103
+ end
104
+
105
+ it 'does not ask referent to read the io stream if referent_id is 0' do
106
+ packet.referent_id = 0
107
+ expect(packet.referent).to_not receive(:do_read).with(io)
108
+ packet.do_read(io)
109
+ end
110
+ end
111
+ end
112
+
113
+ describe '#do_write' do
114
+ let(:io) { StringIO.new }
115
+
116
+ it 'asks referent_id to write the io stream' do
117
+ expect(packet.referent_id).to receive(:do_write).with(io)
118
+ packet.do_write(io)
119
+ end
120
+
121
+ context 'when it can process #referent' do
122
+ before :example do
123
+ allow(packet).to receive(:process_referent?).and_return(true)
124
+ allow(packet.referent_id).to receive(:do_write)
125
+ end
126
+
127
+ it 'asks referent to write the io stream if referent_id is not 0' do
128
+ packet.referent_id = 0xCCCC
129
+ expect(packet.referent).to receive(:do_write).with(io)
130
+ packet.do_write(io)
131
+ end
132
+
133
+ it 'does not ask referent to write the io stream if referent_id is 0' do
134
+ packet.referent_id = 0
135
+ expect(packet.referent).to_not receive(:do_write).with(io)
136
+ packet.do_write(io)
137
+ end
138
+ end
139
+ end
140
+
141
+ describe '#process_referent?' do
142
+ let(:ndr_struct) { RubySMB::Dcerpc::Ndr::NdrStruct.new }
143
+ it 'returns false if the parent is a NdrStruct' do
144
+ obj = described_class.new(nil, {}, ndr_struct)
145
+ expect(obj.process_referent?).to be false
146
+ end
147
+
148
+ it 'returns false if one of the parents is a NdrStruct' do
149
+ obj1 = described_class.new(nil, {}, ndr_struct)
150
+ obj2 = described_class.new(nil, {}, obj1)
151
+ obj3 = described_class.new(nil, {}, obj2)
152
+ obj4 = described_class.new(nil, {}, obj3)
153
+ obj5 = described_class.new(nil, {}, obj4)
154
+ expect(obj5.process_referent?).to be false
155
+ end
156
+
157
+ it 'returns true if none of the parents is a NdrStruct' do
158
+ obj1 = described_class.new
159
+ obj2 = described_class.new(nil, {}, obj1)
160
+ obj3 = described_class.new(nil, {}, obj2)
161
+ obj4 = described_class.new(nil, {}, obj3)
162
+ obj5 = described_class.new(nil, {}, obj4)
163
+ expect(obj5.process_referent?).to be true
164
+ end
165
+ end
166
+
167
+ describe '#read' do
168
+ let(:struct) do
169
+ Class.new(described_class) do
170
+ attr_accessor :str_length
171
+ endian :little
172
+ string :referent, read_length: -> { self.str_length }
173
+ end
174
+ end
175
+
176
+ context 'with a null string' do
177
+ it 'reads its own binary representation' do
178
+ raw = packet.to_binary_s
179
+ expect(struct.read(raw)).to eq(packet)
180
+ expect(struct.read(raw).to_binary_s).to eq(raw)
181
+ end
182
+ end
183
+
184
+ context 'with a normal string' do
185
+ it 'reads its own binary representation' do
186
+ packet.set('testing')
187
+ raw = packet.to_binary_s
188
+ struct_obj = struct.new
189
+ struct_obj.str_length = 'testing'.size
190
+ expect(struct_obj.read(raw)).to eq(packet)
191
+ expect(struct_obj.read(raw).to_binary_s).to eq(raw)
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrString do
198
+ subject(:packet) { described_class.new }
199
+
200
+ it { is_expected.to respond_to :max_count }
201
+ it { is_expected.to respond_to :offset }
202
+ it { is_expected.to respond_to :actual_count }
203
+ it { is_expected.to respond_to :str }
204
+
205
+ it 'is little endian' do
206
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
207
+ end
208
+
209
+ describe '#max_count' do
210
+ it 'is a 32-bit unsigned integer' do
211
+ expect(packet.max_count).to be_a BinData::Uint32le
212
+ end
213
+ end
214
+
215
+ describe '#offset' do
216
+ it 'is a 32-bit unsigned integer' do
217
+ expect(packet.offset).to be_a BinData::Uint32le
218
+ end
219
+
220
+ it 'has an initial valu of 0' do
221
+ expect(packet.offset).to eq(0)
222
+ end
223
+ end
224
+
225
+ describe '#actual_count' do
226
+ it 'is a 32-bit unsigned integer' do
227
+ expect(packet.actual_count).to be_a BinData::Uint32le
228
+ end
229
+ end
230
+
231
+ describe '#str' do
232
+ it 'is a RubySMB::Field::Stringz16' do
233
+ expect(packet.str).to be_a RubySMB::Field::Stringz16
234
+ end
235
+
236
+ it 'exists if #actual_count is greater than 0' do
237
+ packet.actual_count = 4
238
+ expect(packet.str?).to be true
239
+ end
240
+
241
+ it 'does not exist if #actual_count is 0' do
242
+ expect(packet.str?).to be false
243
+ end
244
+ end
245
+
246
+ describe '#get' do
247
+ it 'returns 0 when #actual_count is 0' do
248
+ expect(packet.get).to eq(0)
249
+ end
250
+
251
+ it 'returns #str when #actual_count is greater than 0' do
252
+ str = 'spec_test'
253
+ strz16 = RubySMB::Field::Stringz16.new(str)
254
+ packet.set(str)
255
+ expect(packet.get).to eq(strz16)
256
+ end
257
+ end
258
+
259
+ describe '#set' do
260
+ context 'when the value is 0' do
261
+ it 'sets #actual_count to 0' do
262
+ packet.set(0)
263
+ expect(packet.actual_count).to eq(0)
264
+ end
265
+
266
+ it 'clears #str' do
267
+ expect(packet.str).to receive(:clear)
268
+ packet.set(0)
269
+ end
270
+
271
+ it 'keeps #actual_count set to 0 when called from #to_binary_s' do
272
+ packet.set(0)
273
+ packet.to_binary_s
274
+ expect(packet.actual_count).to eq(0)
275
+ end
276
+
277
+ it 'keeps #actual_count set to 0 when called from #do_num_bytes' do
278
+ packet.set(0)
279
+ packet.to_binary_s
280
+ packet.do_num_bytes
281
+ expect(packet.actual_count).to eq(0)
282
+ end
283
+ end
284
+
285
+ context 'when the value is a string' do
286
+ let(:str) { 'spec_test' }
287
+
288
+ it 'sets #str to the value' do
289
+ packet.set(str)
290
+ strz16 = RubySMB::Field::Stringz16.new(str)
291
+ expect(packet.str).to eq(strz16)
292
+ end
293
+
294
+ it 'sets #max_count and #actual_count to the expected value' do
295
+ packet.set(str)
296
+ expect(packet.max_count).to eq(str.length + 1)
297
+ expect(packet.actual_count).to eq(str.length + 1)
298
+ end
299
+
300
+ it 'sets #actual_count to 0 when the value is an empty string' do
301
+ packet.actual_count = 10
302
+ packet.set('')
303
+ expect(packet.actual_count).to eq(0)
304
+ end
305
+
306
+ it 'keeps custom #max_count and #offset values when called from #to_binary_s' do
307
+ packet.set(str)
308
+ packet.max_count = 3
309
+ packet.offset = 10
310
+ packet.to_binary_s
311
+ expect(packet.max_count).to eq(3)
312
+ expect(packet.offset).to eq(10)
313
+ end
314
+
315
+ it 'keeps custom #max_count value when called from #do_num_bytes' do
316
+ packet.set(str)
317
+ packet.max_count = 3
318
+ packet.offset = 10
319
+ packet.do_num_bytes
320
+ expect(packet.max_count).to eq(3)
321
+ expect(packet.offset).to eq(10)
322
+ end
323
+
324
+ it 'sets #max_count to the number of elements set after setting custom #max_count value' do
325
+ packet.set(str)
326
+ packet.max_count = 3
327
+ packet.set(str * 2)
328
+ expect(packet.max_count).to eq(str.size * 2 + 1)
329
+ end
330
+ end
331
+ end
332
+
333
+ describe '#clear' do
334
+ it 'clears #str' do
335
+ expect(packet.str).to receive(:clear)
336
+ packet.clear
337
+ end
338
+
339
+ it 'clears #actual_count' do
340
+ expect(packet.actual_count).to receive(:clear)
341
+ packet.clear
342
+ end
343
+
344
+ it 'does to clear out #max_count and #offset' do
345
+ expect(packet.max_count).to_not receive(:clear)
346
+ expect(packet.offset).to_not receive(:clear)
347
+ packet.clear
348
+ end
349
+ end
350
+
351
+ describe '#to_s' do
352
+ it 'calls str#to_s' do
353
+ expect(packet.str).to receive(:to_s)
354
+ packet.to_s
355
+ end
356
+
357
+ it 'outputs the expected string with the correct encoding' do
358
+ str = 'testing'
359
+ packet.assign(str)
360
+ expect(packet.to_s.encoding).to eq(Encoding::UTF_16LE)
361
+ expect(packet.to_s).to eq(str.encode(Encoding::UTF_16LE))
362
+ end
363
+ end
364
+
365
+ describe '#read' do
366
+ context 'with a null string' do
367
+ it 'reads its own binary representation' do
368
+ packet.set(0)
369
+ raw = packet.to_binary_s
370
+ expect(described_class.read(raw)).to eq(packet)
371
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
372
+ end
373
+ end
374
+
375
+ context 'with a normal string' do
376
+ it 'reads its own binary representation' do
377
+ packet.set('testing')
378
+ raw = packet.to_binary_s
379
+ expect(described_class.read(raw)).to eq(packet)
380
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
381
+ end
382
+ end
383
+
384
+ context 'with different #offset and #max_count values' do
385
+ it 'reads its own binary representation' do
386
+ packet.set('testing')
387
+ packet.max_count = 256
388
+ packet.offset = 40
389
+ raw = packet.to_binary_s
390
+ expect(described_class.read(raw)).to eq(packet)
391
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
392
+ end
393
+ end
394
+
395
+ context 'with #actual_count less than elements size' do
396
+ it 'reads its own binary representation reduced to #actual_count elements' do
397
+ str = '12345'
398
+ packet.set(str)
399
+ packet.actual_count = 4
400
+ max_count = packet.max_count.to_i
401
+ raw = packet.to_binary_s
402
+ packet2 = described_class.read(raw)
403
+ expect(packet2.max_count).to eq(max_count)
404
+ expect(packet2.offset).to eq(0)
405
+ expect(packet2.actual_count).to eq(4)
406
+ expect(packet2.str).to eq(str[0,3].encode(Encoding::UTF_16LE))
407
+ expect(packet2.to_binary_s).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x001\x002\x003\x00\x00\x00".b)
408
+ end
409
+ end
410
+ end
411
+ end
412
+
413
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStr do
414
+ it 'is NdrPointer subclass' do
415
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
416
+ end
417
+
418
+ subject(:packet) { described_class.new }
419
+
420
+ it { is_expected.to respond_to :referent }
421
+
422
+ it 'is little endian' do
423
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
424
+ end
425
+
426
+ describe '#referent' do
427
+ it 'is a NdrString' do
428
+ expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrString
429
+ end
430
+
431
+ it 'exists if superclass #referent_id is not zero' do
432
+ packet.referent_id = 0xCCCC
433
+ expect(packet.referent?).to be true
434
+ end
435
+
436
+ it 'does not exist if superclass #referent_id is zero' do
437
+ packet.referent_id = 0
438
+ expect(packet.referent?).to be false
439
+ end
440
+ end
441
+
442
+ describe '#read' do
443
+ context 'with a null pointer' do
444
+ it 'reads its own binary representation' do
445
+ raw = packet.to_binary_s
446
+ expect(described_class.read(raw)).to eq(packet)
447
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
448
+ end
449
+ end
450
+
451
+ context 'with a normal string' do
452
+ it 'reads its own binary representation' do
453
+ packet.set('testing')
454
+ raw = packet.to_binary_s
455
+ expect(described_class.read(raw)).to eq(packet)
456
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
457
+ end
458
+ end
459
+ end
460
+ end
461
+
462
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrContextHandle do
463
+ let(:uuid) { 'c3bce70d-5155-472b-9f2f-b824e5fc9b60' }
464
+ let(:attr) { 123 }
465
+ subject(:packet) { described_class.new }
466
+
467
+ it { is_expected.to respond_to :context_handle_attributes }
468
+ it { is_expected.to respond_to :context_handle_uuid }
469
+
470
+ it 'is little endian' do
471
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
472
+ end
473
+
474
+ describe '#context_handle_attributes' do
475
+ it 'is a 32-bit unsigned integer' do
476
+ expect(packet.context_handle_attributes).to be_a BinData::Uint32le
477
+ end
478
+ end
479
+
480
+ describe '#context_handle_uuid' do
481
+ it 'is a UUID' do
482
+ expect(packet.context_handle_uuid).to be_a RubySMB::Dcerpc::Uuid
483
+ end
484
+ end
485
+
486
+ describe '#get' do
487
+ it 'returns the expeted hash' do
488
+ packet.context_handle_attributes = attr
489
+ packet.context_handle_uuid = uuid
490
+ expect(packet.get).to eq({context_handle_attributes: attr, context_handle_uuid: uuid})
491
+ end
492
+ end
493
+
494
+ describe '#set' do
495
+ let(:handle) { {context_handle_attributes: attr, context_handle_uuid: uuid} }
496
+
497
+ context 'when the value is a hash' do
498
+ it 'sets #context_handle_attributes and #context_handle_uuid to the expected values' do
499
+ packet.set(handle)
500
+ expect(packet.context_handle_attributes).to eq(attr)
501
+ expect(packet.context_handle_uuid).to eq(uuid)
502
+ end
503
+ end
504
+
505
+ context 'when the value is a NdrContextHandle'do
506
+ it 'reads the value binary representaion ' do
507
+ ndr_context_handle = described_class.new(handle)
508
+ allow(ndr_context_handle).to receive(:to_binary_s).and_call_original
509
+ packet.set(ndr_context_handle)
510
+ expect(ndr_context_handle).to have_received(:to_binary_s)
511
+ expect(packet.get).to eq(ndr_context_handle)
512
+ end
513
+ end
514
+
515
+ context 'when the value is a binary string'do
516
+ it 'reads the value' do
517
+ ndr_context_handle = described_class.new(handle)
518
+ packet.set(ndr_context_handle.to_binary_s)
519
+ expect(packet.get).to eq(ndr_context_handle)
520
+ end
521
+ end
522
+ end
523
+
524
+ describe '#read' do
525
+ context 'with a hash' do
526
+ it 'reads its own binary representation' do
527
+ packet.set({context_handle_attributes: attr, context_handle_uuid: uuid})
528
+ raw = packet.to_binary_s
529
+ expect(described_class.read(raw)).to eq(packet)
530
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
531
+ end
532
+ end
533
+
534
+ context 'with a NdrContextHandle' do
535
+ it 'reads its own binary representation' do
536
+ nch = described_class.new
537
+ nch.set({context_handle_attributes: attr, context_handle_uuid: uuid})
538
+ packet.set(nch)
539
+ raw = packet.to_binary_s
540
+ expect(described_class.read(raw)).to eq(packet)
541
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
542
+ end
543
+ end
544
+
545
+ context 'with a binary string' do
546
+ it 'reads its own binary representation' do
547
+ packet.set("{\x00\x00\x00\r\xE7\xBC\xC3UQ+G\x9F/\xB8$\xE5\xFC\x9B`".b)
548
+ raw = packet.to_binary_s
549
+ expect(described_class.read(raw)).to eq(packet)
550
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
551
+ end
552
+ end
553
+ end
554
+ end
555
+
556
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpDword do
557
+ it 'is NdrPointer subclass' do
558
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
559
+ end
560
+
561
+ subject(:packet) { described_class.new }
562
+
563
+ it { is_expected.to respond_to :referent }
564
+
565
+ it 'is little endian' do
566
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
567
+ end
568
+
569
+ describe '#referent' do
570
+ it 'is a 32-bit unsigned integer' do
571
+ expect(packet.referent).to be_a BinData::Uint32le
572
+ end
573
+
574
+ it 'exists if superclass #referent_id is not zero' do
575
+ packet.referent_id = 0xCCCC
576
+ expect(packet.referent?).to be true
577
+ end
578
+
579
+ it 'does not exist if superclass #referent_id is zero' do
580
+ packet.referent_id = 0
581
+ expect(packet.referent?).to be false
582
+ end
583
+ end
584
+
585
+ describe '#read' do
586
+ context 'with a null pointer' do
587
+ it 'reads its own binary representation' do
588
+ raw = packet.to_binary_s
589
+ expect(described_class.read(raw)).to eq(packet)
590
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
591
+ end
592
+ end
593
+
594
+ context 'with a normal integer' do
595
+ it 'reads its own binary representation' do
596
+ packet.set(123)
597
+ raw = packet.to_binary_s
598
+ expect(described_class.read(raw)).to eq(packet)
599
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
600
+ end
601
+ end
602
+ end
603
+ end
604
+
605
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByteArray do
606
+ it 'is NdrPointer subclass' do
607
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
608
+ end
609
+
610
+ subject(:packet) { described_class.new }
611
+
612
+ it { is_expected.to respond_to :referent }
613
+
614
+ it 'is little endian' do
615
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
616
+ end
617
+
618
+ describe '#referent' do
619
+ it 'is a NdrByteArray structure' do
620
+ expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrByteArray
621
+ end
622
+
623
+ it 'exists if superclass #referent_id is not zero' do
624
+ packet.referent_id = 0xCCCC
625
+ expect(packet.referent?).to be true
626
+ end
627
+
628
+ it 'does not exist if superclass #referent_id is zero' do
629
+ packet.referent_id = 0
630
+ expect(packet.referent?).to be false
631
+ end
632
+ end
633
+
634
+ describe '#set' do
635
+ it 'accepts a NdrLpByteArray structure' do
636
+ struct = described_class.new([1, 2, 3])
637
+ packet.set(struct)
638
+ expect(packet).to eq(struct)
639
+ end
640
+
641
+ it 'accepts a NdrLpByteArray null pointer' do
642
+ struct = described_class.new
643
+ packet.set(struct)
644
+ expect(packet).to eq(:null)
645
+ end
646
+
647
+ it 'accepts a BinData::Array' do
648
+ struct = BinData::Array.new([1, 2, 3], type: :uint8)
649
+ packet.set(struct)
650
+ expect(packet).to eq(struct)
651
+ end
652
+
653
+ it 'accepts an Array' do
654
+ struct = Array.new([1, 2, 3])
655
+ packet.set(struct)
656
+ expect(packet).to eq(struct)
657
+ end
658
+ end
659
+
660
+ describe '#read' do
661
+ context 'with a null pointer' do
662
+ it 'reads its own binary representation' do
663
+ raw = packet.to_binary_s
664
+ expect(described_class.read(raw)).to eq(packet)
665
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
666
+ end
667
+ end
668
+
669
+ context 'with a normal array of bytes' do
670
+ it 'reads its own binary representation' do
671
+ packet.set([1, 2, 3])
672
+ raw = packet.to_binary_s
673
+ expect(described_class.read(raw)).to eq(packet)
674
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
675
+ end
676
+ end
677
+ end
678
+ end
679
+
680
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
681
+ subject(:packet) { described_class.new }
682
+
683
+ it { is_expected.to respond_to :max_count }
684
+ it { is_expected.to respond_to :elements }
685
+
686
+ it 'is little endian' do
687
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
688
+ end
689
+
690
+ describe '#max_count' do
691
+ it 'is a 32-bit unsigned integer' do
692
+ expect(packet.max_count).to be_a BinData::Uint32le
693
+ end
694
+
695
+ it 'has an initial value equal to #elements size' do
696
+ packet.elements = [1, 2, 3]
697
+ expect(packet.max_count).to eq(3)
698
+ end
699
+ end
700
+
701
+ describe '#elements' do
702
+ it 'is a Bindata::Array' do
703
+ expect(packet.elements).to be_a BinData::Array
704
+ end
705
+
706
+ it 'is 8-bit unsigned integer elements' do
707
+ expect(packet.elements[0]).to be_a BinData::Uint8
708
+ end
709
+
710
+ it 'exists if #max_count is greater than 0' do
711
+ packet.max_count = 2
712
+ expect(packet.elements?).to be true
713
+ end
714
+
715
+ it 'does not exist if #max_count is 0' do
716
+ packet.max_count = 0
717
+ expect(packet.elements?).to be false
718
+ end
719
+
720
+ it 'reads at most #max_counts elements' do
721
+ bin = "ABCDEFG".b
722
+ packet.max_count = 3
723
+ packet.elements.read(bin)
724
+ expect(packet.elements).to eq(bin.bytes[0,3])
725
+ end
726
+ end
727
+
728
+ describe '#get' do
729
+ it 'returns the elements' do
730
+ packet.elements = [1, 2, 3]
731
+ expect(packet.get).to eq([1, 2, 3])
732
+ end
733
+ end
734
+
735
+ describe '#set' do
736
+ it 'sets #elements as expected' do
737
+ packet.set([1, 2, 3])
738
+ expect(packet.elements).to eq([1, 2, 3])
739
+ end
740
+
741
+ it 'sets #max_count to the number of elements set' do
742
+ packet.set([1, 2, 3])
743
+ expect(packet.max_count).to eq(3)
744
+ end
745
+
746
+ it 'calls #to_ary before setting the elements' do
747
+ ary = BinData::Array.new([1, 2, 3], type: :uint8)
748
+ expect(ary).to receive(:to_ary).and_call_original
749
+ packet.set(ary)
750
+ expect(packet.elements).to eq([1, 2, 3])
751
+ end
752
+
753
+ it 'keeps custom #max_count value when called from #to_binary_s' do
754
+ packet.set([1, 2, 3, 4, 5])
755
+ packet.max_count = 3
756
+ packet.to_binary_s
757
+ expect(packet.max_count).to eq(3)
758
+ end
759
+
760
+ it 'keeps custom #max_count value when called from #do_num_bytes' do
761
+ packet.set([1, 2, 3, 4, 5])
762
+ packet.max_count = 3
763
+ packet.do_num_bytes
764
+ expect(packet.max_count).to eq(3)
765
+ end
766
+
767
+ it 'sets #max_count to the number of elements set after setting custom #max_count value' do
768
+ packet.set([1, 2, 3, 4, 5])
769
+ packet.max_count = 3
770
+ packet.set([1, 2, 3, 4, 5])
771
+ expect(packet.max_count).to eq(5)
772
+ end
773
+ end
774
+
775
+ describe '#read' do
776
+ context 'with a no elements' do
777
+ it 'reads its own binary representation' do
778
+ raw = packet.to_binary_s
779
+ expect(described_class.read(raw)).to eq(packet)
780
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
781
+ end
782
+ end
783
+
784
+ context 'with some elements' do
785
+ it 'reads its own binary representation' do
786
+ packet.set([1, 2, 3])
787
+ raw = packet.to_binary_s
788
+ expect(described_class.read(raw)).to eq(packet)
789
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
790
+ end
791
+ end
792
+
793
+ context 'with #max_count less than elements size' do
794
+ it 'reads its own binary representation reduced to #max_count elements' do
795
+ packet.set([1, 2, 3, 4, 5])
796
+ packet.max_count = 3
797
+ raw = packet.to_binary_s
798
+ packet2 = described_class.new([1, 2, 3])
799
+ raw2 = packet2.to_binary_s
800
+ expect(described_class.read(raw)).to eq(packet2)
801
+ expect(described_class.read(raw).to_binary_s).to eq(raw2)
802
+ end
803
+ end
804
+ end
805
+ end
806
+
807
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrByteArray do
808
+ subject(:packet) { described_class.new }
809
+
810
+ it { is_expected.to respond_to :max_count }
811
+ it { is_expected.to respond_to :offset }
812
+ it { is_expected.to respond_to :actual_count }
813
+ it { is_expected.to respond_to :bytes }
814
+
815
+ it 'is little endian' do
816
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
817
+ end
818
+
819
+ describe '#max_count' do
820
+ it 'is a 32-bit unsigned integer' do
821
+ expect(packet.max_count).to be_a BinData::Uint32le
822
+ end
823
+
824
+ it 'has an initial value equal to #actual_count' do
825
+ packet.actual_count = 345
826
+ expect(packet.max_count).to eq(345)
827
+ end
828
+ end
829
+
830
+ describe '#offset' do
831
+ it 'is a 32-bit unsigned integer' do
832
+ expect(packet.offset).to be_a BinData::Uint32le
833
+ end
834
+
835
+ it 'has an initial value of 0' do
836
+ expect(packet.offset).to eq(0)
837
+ end
838
+ end
839
+
840
+ describe '#actual_count' do
841
+ it 'is a 32-bit unsigned integer' do
842
+ expect(packet.actual_count).to be_a BinData::Uint32le
843
+ end
844
+
845
+ it 'has an initial value equal to #bytes size' do
846
+ packet.bytes << 2 << 3 << 4 << 5
847
+ expect(packet.actual_count).to eq(4)
848
+ end
849
+ end
850
+
851
+ describe '#bytes' do
852
+ it 'is a Bindata::Array' do
853
+ expect(packet.bytes).to be_a BinData::Array
854
+ end
855
+
856
+ it 'has an initial length equal to #actual_count' do
857
+ packet.actual_count = 3
858
+ expect(packet.bytes.size).to eq(3)
859
+ end
860
+
861
+ it 'is 8-bit unsigned integer elements' do
862
+ expect(packet.bytes[0]).to be_a BinData::Uint8
863
+ end
864
+ end
865
+
866
+ describe '#get' do
867
+ it 'returns bytes' do
868
+ packet.bytes = [1, 2, 3]
869
+ expect(packet.get).to eq([1, 2, 3])
870
+ end
871
+ end
872
+
873
+ describe '#set' do
874
+ it 'sets #bytes as expected' do
875
+ packet.set([1, 2, 3])
876
+ expect(packet.bytes).to eq([1, 2, 3])
877
+ end
878
+
879
+ it 'sets #actual_count and #max_count to the number of bytes set' do
880
+ packet.set([1, 2, 3])
881
+ expect(packet.max_count).to eq(3)
882
+ expect(packet.actual_count).to eq(3)
883
+ end
884
+
885
+ it 'calls #to_ary before setting the elements' do
886
+ ary = BinData::Array.new([1, 2, 3], type: :uint8)
887
+ expect(ary).to receive(:to_ary).and_call_original
888
+ packet.set(ary)
889
+ expect(packet.bytes).to eq([1, 2, 3])
890
+ end
891
+
892
+ it 'keeps custom #max_count and #offset values when called from #to_binary_s' do
893
+ packet.set([1, 2, 3, 4, 5])
894
+ packet.max_count = 3
895
+ packet.offset = 40
896
+ packet.to_binary_s
897
+ expect(packet.max_count).to eq(3)
898
+ expect(packet.offset).to eq(40)
899
+ end
900
+
901
+ it 'keeps custom #max_count and #offset values when called from #do_num_bytes' do
902
+ packet.set([1, 2, 3, 4, 5])
903
+ packet.max_count = 3
904
+ packet.offset = 40
905
+ packet.do_num_bytes
906
+ expect(packet.max_count).to eq(3)
907
+ expect(packet.offset).to eq(40)
908
+ end
909
+
910
+ it 'sets #max_count to the number of bytes set after setting custom #max_count value' do
911
+ packet.set([1, 2, 3, 4, 5])
912
+ packet.max_count = 3
913
+ packet.set([1, 2, 3, 4, 5])
914
+ expect(packet.max_count).to eq(5)
915
+ end
916
+ end
917
+
918
+ describe '#read' do
919
+ context 'with a no elements' do
920
+ it 'reads its own binary representation' do
921
+ raw = packet.to_binary_s
922
+ expect(described_class.read(raw)).to eq(packet)
923
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
924
+ end
925
+ end
926
+
927
+ context 'with some elements' do
928
+ it 'reads its own binary representation' do
929
+ packet.set([1, 2, 3])
930
+ raw = packet.to_binary_s
931
+ expect(described_class.read(raw)).to eq(packet)
932
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
933
+ end
934
+ end
935
+
936
+ context 'with #max_count less than elements size' do
937
+ it 'reads its own binary representation reduced to #max_count elements' do
938
+ packet.set([1, 2, 3, 4, 5])
939
+ packet.actual_count = 3
940
+ max_count = packet.max_count.to_i
941
+ raw = packet.to_binary_s
942
+ packet2 = described_class.read(raw)
943
+ expect(packet2.max_count).to eq(max_count)
944
+ expect(packet2.offset).to eq(0)
945
+ expect(packet2.actual_count).to eq(3)
946
+ expect(packet2.bytes).to eq([1, 2, 3])
947
+ expect(packet2.to_binary_s).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x01\x02\x03".b)
948
+ end
949
+ end
950
+ end
951
+ end
952
+
953
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpFileTime do
954
+ it 'is NdrPointer subclass' do
955
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
956
+ end
957
+
958
+ subject(:packet) { described_class.new }
959
+
960
+ it { is_expected.to respond_to :referent }
961
+
962
+ it 'is little endian' do
963
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
964
+ end
965
+
966
+ describe '#referent' do
967
+ it 'is a FileTime' do
968
+ expect(packet.referent).to be_a RubySMB::Field::FileTime
969
+ end
970
+
971
+ it 'exists if superclass #referent_id is not zero' do
972
+ packet.referent_id = 0xCCCC
973
+ expect(packet.referent?).to be true
974
+ end
975
+
976
+ it 'does not exist if superclass #referent_id is zero' do
977
+ packet.referent_id = 0
978
+ expect(packet.referent?).to be false
979
+ end
980
+ end
981
+
982
+ describe '#read' do
983
+ context 'with a null pointer' do
984
+ it 'reads its own binary representation' do
985
+ raw = packet.to_binary_s
986
+ expect(described_class.read(raw)).to eq(packet)
987
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
988
+ end
989
+ end
990
+
991
+ context 'with a normal FileTime' do
992
+ it 'reads its own binary representation' do
993
+ time = RubySMB::Field::FileTime.new(Time.now)
994
+ packet.set(time)
995
+ raw = packet.to_binary_s
996
+ expect(described_class.read(raw)).to eq(packet)
997
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
998
+ end
999
+ end
1000
+ end
1001
+ end
1002
+
1003
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrStruct do
1004
+ describe '#do_read' do
1005
+ let(:io) { BinData::IO::Read.new(bin_str) }
1006
+ context 'with a structure containg an array of pointers to integer' do
1007
+ subject(:struct) do
1008
+ Class.new(described_class) do
1009
+ endian :little
1010
+ uint32 :a
1011
+ array :b, type: :ndr_lp_dword, read_until: -> { index == a - 1 }
1012
+ uint32 :c
1013
+ end.new
1014
+ end
1015
+
1016
+ context 'without null pointers' do
1017
+ let(:bin_str) do
1018
+ "\x03\x00\x00\x00" + # a
1019
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1020
+ "&_>=" + # b[1] referent_id
1021
+ "T\r%\x18" + # b[2] referent_id
1022
+ "7\x00\x00\x00" + # c
1023
+ "\x01\x00\x00\x00" + # b[0]
1024
+ "\x02\x00\x00\x00" + # b[1]
1025
+ "\x03\x00\x00\x00" # b[2]
1026
+ end
1027
+
1028
+ it 'reads as expected' do
1029
+ struct.do_read(io)
1030
+ expect(struct.a).to eq(3)
1031
+ expect(struct.b).to eq([1, 2, 3])
1032
+ expect(struct.b[0].referent_id).to eq(2635975080)
1033
+ expect(struct.b[0].referent).to eq(1)
1034
+ expect(struct.b[1].referent_id).to eq(1027497766)
1035
+ expect(struct.b[1].referent).to eq(2)
1036
+ expect(struct.b[2].referent_id).to eq(405081428)
1037
+ expect(struct.b[2].referent).to eq(3)
1038
+ expect(struct.c).to eq(55)
1039
+ end
1040
+ end
1041
+
1042
+ context 'with null pointers' do
1043
+ let(:bin_str) do
1044
+ "\x03\x00\x00\x00" + # a
1045
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1046
+ "\x00\x00\x00\x00" + # b[1] referent_id (null)
1047
+ "T\r%\x18" + # b[2] referent_id
1048
+ "7\x00\x00\x00" + # c
1049
+ "\x01\x00\x00\x00" + # b[0]
1050
+ "\x03\x00\x00\x00" # b[2]
1051
+ end
1052
+
1053
+ it 'reads as expected' do
1054
+ struct.do_read(io)
1055
+ expect(struct.a).to eq(3)
1056
+ expect(struct.b).to eq([1, :null, 3])
1057
+ expect(struct.b[0].referent_id).to eq(2635975080)
1058
+ expect(struct.b[0].referent).to eq(1)
1059
+ expect(struct.b[1].referent_id).to eq(0)
1060
+ expect(struct.b[2].referent_id).to eq(405081428)
1061
+ expect(struct.b[2].referent).to eq(3)
1062
+ expect(struct.c).to eq(55)
1063
+ end
1064
+ end
1065
+ end
1066
+
1067
+ context 'with a structure containg an array of pointers to strings' do
1068
+ subject(:struct) do
1069
+ Class.new(described_class) do
1070
+ endian :little
1071
+ uint32 :a
1072
+ array :b, type: :ndr_lp_str, read_until: -> { index == a - 1 }
1073
+ uint32 :c
1074
+ end.new
1075
+ end
1076
+
1077
+ context 'without null pointers' do
1078
+ let(:bin_str) do
1079
+ "\x03\x00\x00\x00" + # a
1080
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1081
+ "&_>=" + # b[1] referent_id
1082
+ "T\r%\x18" + # b[2] referent_id
1083
+ "7\x00\x00\x00" + # c
1084
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
1085
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # b[1]
1086
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
1087
+ end
1088
+
1089
+ it 'reads as expected' do
1090
+ struct.do_read(io)
1091
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1092
+ str2 = 'test2'.encode(Encoding::UTF_16LE)
1093
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1094
+ expect(struct.a).to eq(3)
1095
+ expect(struct.b).to eq([str1, str2, str3])
1096
+ expect(struct.b[0].referent_id).to eq(2635975080)
1097
+ expect(struct.b[0].referent).to eq(str1)
1098
+ expect(struct.b[1].referent_id).to eq(1027497766)
1099
+ expect(struct.b[1].referent).to eq(str2)
1100
+ expect(struct.b[2].referent_id).to eq(405081428)
1101
+ expect(struct.b[2].referent).to eq(str3)
1102
+ expect(struct.c).to eq(55)
1103
+ end
1104
+ end
1105
+
1106
+ context 'with null pointers' do
1107
+ let(:bin_str) do
1108
+ "\x03\x00\x00\x00" + # a
1109
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1110
+ "\x00\x00\x00\x00" + # b[1] referent_id (null)
1111
+ "T\r%\x18" + # b[2] referent_id
1112
+ "7\x00\x00\x00" + # c
1113
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
1114
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
1115
+ end
1116
+
1117
+ it 'reads as expected' do
1118
+ struct.do_read(io)
1119
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1120
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1121
+ expect(struct.a).to eq(3)
1122
+ expect(struct.b).to eq([str1, :null, str3])
1123
+ expect(struct.b[0].referent_id).to eq(2635975080)
1124
+ expect(struct.b[0].referent).to eq(str1)
1125
+ expect(struct.b[1].referent_id).to eq(0)
1126
+ expect(struct.b[2].referent_id).to eq(405081428)
1127
+ expect(struct.b[2].referent).to eq(str3)
1128
+ expect(struct.c).to eq(55)
1129
+ end
1130
+ end
1131
+
1132
+ context 'with null strings' do
1133
+ let(:bin_str) do
1134
+ "\x03\x00\x00\x00" + # a
1135
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1136
+ "&_>=" + # b[1] referent_id
1137
+ "T\r%\x18" + # b[2] referent_id
1138
+ "7\x00\x00\x00" + # c
1139
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
1140
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # b[1] null string
1141
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
1142
+ end
1143
+
1144
+ it 'reads as expected' do
1145
+ struct.do_read(io)
1146
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1147
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1148
+ expect(struct.a).to eq(3)
1149
+ expect(struct.b).to eq([str1, 0, str3])
1150
+ expect(struct.b[0].referent_id).to eq(2635975080)
1151
+ expect(struct.b[0].referent).to eq(str1)
1152
+ expect(struct.b[1].referent_id).to eq(1027497766)
1153
+ expect(struct.b[1].referent).to eq(0)
1154
+ expect(struct.b[2].referent_id).to eq(405081428)
1155
+ expect(struct.b[2].referent).to eq(str3)
1156
+ expect(struct.c).to eq(55)
1157
+ end
1158
+ end
1159
+
1160
+ context 'with padding' do
1161
+ let(:bin_str) do
1162
+ "\x03\x00\x00\x00" + # a
1163
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1164
+ "&_>=" + # b[1] referent_id
1165
+ "T\r%\x18" + # b[2] referent_id
1166
+ "7\x00\x00\x00" + # c
1167
+ "\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00" + # b[0]
1168
+ "\x00\x00" + # pad
1169
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # b[1]
1170
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
1171
+ end
1172
+
1173
+ it 'reads as expected' do
1174
+ struct.do_read(io)
1175
+ str1 = 'test'.encode(Encoding::UTF_16LE)
1176
+ str2 = 'test2'.encode(Encoding::UTF_16LE)
1177
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1178
+ expect(struct.a).to eq(3)
1179
+ expect(struct.b).to eq([str1, str2, str3])
1180
+ expect(struct.b[0].referent_id).to eq(2635975080)
1181
+ expect(struct.b[0].referent).to eq(str1)
1182
+ expect(struct.b[1].referent_id).to eq(1027497766)
1183
+ expect(struct.b[1].referent).to eq(str2)
1184
+ expect(struct.b[2].referent_id).to eq(405081428)
1185
+ expect(struct.b[2].referent).to eq(str3)
1186
+ expect(struct.c).to eq(55)
1187
+ end
1188
+ end
1189
+ end
1190
+
1191
+ context 'with a structure containg an pointers to strings' do
1192
+ subject(:struct) do
1193
+ Class.new(described_class) do
1194
+ endian :little
1195
+ uint32 :a
1196
+ ndr_lp_str :b
1197
+ ndr_lp_str :c
1198
+ ndr_lp_str :d
1199
+ uint32 :e
1200
+ end.new
1201
+ end
1202
+
1203
+ context 'without null pointers' do
1204
+ let(:bin_str) do
1205
+ "\x03\x00\x00\x00" + # a
1206
+ "\xA8\xC9\x1D\x9D" + # b referent_id
1207
+ "&_>=" + # c referent_id
1208
+ "T\r%\x18" + # d referent_id
1209
+ "7\x00\x00\x00" + # c
1210
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
1211
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # c
1212
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
1213
+ end
1214
+
1215
+ it 'reads as expected' do
1216
+ struct.do_read(io)
1217
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1218
+ str2 = 'test2'.encode(Encoding::UTF_16LE)
1219
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1220
+ expect(struct.a).to eq(3)
1221
+ expect(struct.b).to eq(str1)
1222
+ expect(struct.c).to eq(str2)
1223
+ expect(struct.d).to eq(str3)
1224
+ expect(struct.b.referent_id).to eq(2635975080)
1225
+ expect(struct.b.referent).to eq(str1)
1226
+ expect(struct.c.referent_id).to eq(1027497766)
1227
+ expect(struct.c.referent).to eq(str2)
1228
+ expect(struct.d.referent_id).to eq(405081428)
1229
+ expect(struct.d.referent).to eq(str3)
1230
+ expect(struct.e).to eq(55)
1231
+ end
1232
+ end
1233
+
1234
+ context 'with null pointers' do
1235
+ let(:bin_str) do
1236
+ "\x03\x00\x00\x00" + # a
1237
+ "\xA8\xC9\x1D\x9D" + # b referent_id
1238
+ "\x00\x00\x00\x00" + # c referent_id (null)
1239
+ "T\r%\x18" + # d referent_id
1240
+ "7\x00\x00\x00" + # c
1241
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
1242
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
1243
+ end
1244
+
1245
+ it 'reads as expected' do
1246
+ struct.do_read(io)
1247
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1248
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1249
+ expect(struct.a).to eq(3)
1250
+ expect(struct.b).to eq(str1)
1251
+ expect(struct.c).to eq(:null)
1252
+ expect(struct.d).to eq(str3)
1253
+ expect(struct.b.referent_id).to eq(2635975080)
1254
+ expect(struct.b.referent).to eq(str1)
1255
+ expect(struct.c.referent_id).to eq(0)
1256
+ expect(struct.d.referent_id).to eq(405081428)
1257
+ expect(struct.d.referent).to eq(str3)
1258
+ expect(struct.e).to eq(55)
1259
+ end
1260
+ end
1261
+
1262
+ context 'with null strings' do
1263
+ let(:bin_str) do
1264
+ "\x03\x00\x00\x00" + # a
1265
+ "\xA8\xC9\x1D\x9D" + # b referent_id
1266
+ "&_>=" + # c referent_id
1267
+ "T\r%\x18" + # d referent_id
1268
+ "7\x00\x00\x00" + # c
1269
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
1270
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # c null string
1271
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
1272
+ end
1273
+
1274
+ it 'reads as expected' do
1275
+ struct.do_read(io)
1276
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1277
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1278
+ expect(struct.a).to eq(3)
1279
+ expect(struct.b).to eq(str1)
1280
+ expect(struct.c).to eq(0)
1281
+ expect(struct.d).to eq(str3)
1282
+ expect(struct.b.referent_id).to eq(2635975080)
1283
+ expect(struct.b.referent).to eq(str1)
1284
+ expect(struct.c.referent_id).to eq(1027497766)
1285
+ expect(struct.c.referent).to eq(0)
1286
+ expect(struct.d.referent_id).to eq(405081428)
1287
+ expect(struct.d.referent).to eq(str3)
1288
+ expect(struct.e).to eq(55)
1289
+ end
1290
+ end
1291
+
1292
+ context 'with padding' do
1293
+ let(:bin_str) do
1294
+ "\x03\x00\x00\x00" + # a
1295
+ "\xA8\xC9\x1D\x9D" + # b referent_id
1296
+ "&_>=" + # c referent_id
1297
+ "T\r%\x18" + # d referent_id
1298
+ "7\x00\x00\x00" + # c
1299
+ "\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00" + # b
1300
+ "\x00\x00" + # pad
1301
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # c
1302
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
1303
+ end
1304
+
1305
+ it 'reads as expected' do
1306
+ struct.do_read(io)
1307
+ str1 = 'test'.encode(Encoding::UTF_16LE)
1308
+ str2 = 'test2'.encode(Encoding::UTF_16LE)
1309
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1310
+ expect(struct.a).to eq(3)
1311
+ expect(struct.b).to eq(str1)
1312
+ expect(struct.c).to eq(str2)
1313
+ expect(struct.d).to eq(str3)
1314
+ expect(struct.b.referent_id).to eq(2635975080)
1315
+ expect(struct.b.referent).to eq(str1)
1316
+ expect(struct.c.referent_id).to eq(1027497766)
1317
+ expect(struct.c.referent).to eq(str2)
1318
+ expect(struct.d.referent_id).to eq(405081428)
1319
+ expect(struct.d.referent).to eq(str3)
1320
+ expect(struct.e).to eq(55)
1321
+ end
1322
+ end
1323
+ end
1324
+ end
1325
+
1326
+ describe '#do_write' do
1327
+ let(:raw_io) { BinData::IO.create_string_io }
1328
+ let(:io) { BinData::IO::Write.new(raw_io) }
1329
+ context 'with a structure containg an array of pointers to integer' do
1330
+ subject(:struct) do
1331
+ Class.new(described_class) do
1332
+ endian :little
1333
+ uint32 :a
1334
+ array :b, type: :ndr_lp_dword, read_until: -> { index == a - 1 }
1335
+ uint32 :c
1336
+ end.new
1337
+ end
1338
+
1339
+ context 'without null pointers' do
1340
+ let(:packet) do
1341
+ struct.new(a: 3, b: [1, 2, 3], c: 55)
1342
+ end
1343
+
1344
+ it 'writes as expected' do
1345
+ packet.do_write(io)
1346
+ raw_io.rewind
1347
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1348
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1349
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
1350
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1351
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1352
+ expect(raw_io.read(4)).to eq("\x01\x00\x00\x00".b) # b[0]
1353
+ expect(raw_io.read(4)).to eq("\x02\x00\x00\x00".b) # b[1]
1354
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # b[2]
1355
+ expect(raw_io.eof).to be true
1356
+ end
1357
+ end
1358
+
1359
+ context 'with null pointers' do
1360
+ let(:packet) do
1361
+ struct.new(a: 3, b: [1, :null, 3], c: 55)
1362
+ end
1363
+
1364
+ it 'writes as expected' do
1365
+ packet.do_write(io)
1366
+ raw_io.rewind
1367
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1368
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1369
+ expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # b[1] referent_id (null)
1370
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1371
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1372
+ expect(raw_io.read(4)).to eq("\x01\x00\x00\x00".b) # b[0]
1373
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # b[2]
1374
+ expect(raw_io.eof).to be true
1375
+ end
1376
+ end
1377
+ end
1378
+
1379
+ context 'with a structure containg an array of pointers to strings' do
1380
+ subject(:struct) do
1381
+ Class.new(described_class) do
1382
+ endian :little
1383
+ uint32 :a
1384
+ array :b, type: :ndr_lp_str, read_until: -> { index == a - 1 }
1385
+ uint32 :c
1386
+ end.new
1387
+ end
1388
+
1389
+ context 'without null pointers' do
1390
+ let(:packet) do
1391
+ struct.new(a: 3, b: ['test1', 'test2', 'test3'], c: 55)
1392
+ end
1393
+
1394
+ it 'writes as expected' do
1395
+ packet.do_write(io)
1396
+ raw_io.rewind
1397
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1398
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1399
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
1400
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1401
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1402
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
1403
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00".b) # b[1]
1404
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
1405
+ expect(raw_io.eof).to be true
1406
+ end
1407
+ end
1408
+
1409
+ context 'with null pointers' do
1410
+ let(:packet) do
1411
+ struct.new(a: 3, b: ['test1', :null, 'test3'], c: 55)
1412
+ end
1413
+
1414
+ it 'writes as expected' do
1415
+ packet.do_write(io)
1416
+ raw_io.rewind
1417
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1418
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1419
+ expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # b[1] referent_id (null)
1420
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1421
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1422
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
1423
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
1424
+ expect(raw_io.eof).to be true
1425
+ end
1426
+ end
1427
+
1428
+ context 'with null strings' do
1429
+ let(:packet) do
1430
+ struct.new(a: 3, b: ['test1', 0, 'test3'], c: 55)
1431
+ end
1432
+
1433
+ it 'writes as expected' do
1434
+ packet.do_write(io)
1435
+ raw_io.rewind
1436
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1437
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1438
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
1439
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1440
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1441
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
1442
+ expect(raw_io.read(12)).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".b) # b[1] null string
1443
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
1444
+ expect(raw_io.eof).to be true
1445
+ end
1446
+ end
1447
+
1448
+ context 'with padding' do
1449
+ let(:packet) do
1450
+ struct.new(a: 3, b: ['test1', 'test', 'test3'], c: 55)
1451
+ end
1452
+
1453
+ it 'writes as expected' do
1454
+ packet.do_write(io)
1455
+ raw_io.rewind
1456
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1457
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1458
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
1459
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1460
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1461
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
1462
+ expect(raw_io.read(22)).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00".b) # b[1]
1463
+ expect(raw_io.read(2)).to eq("\x00\x00".b) # pad
1464
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
1465
+ expect(raw_io.eof).to be true
1466
+ end
1467
+ end
1468
+ end
1469
+
1470
+ context 'with a structure containg pointers to strings' do
1471
+ subject(:struct) do
1472
+ Class.new(described_class) do
1473
+ endian :little
1474
+ uint32 :a
1475
+ ndr_lp_str :b
1476
+ ndr_lp_str :c
1477
+ ndr_lp_str :d
1478
+ uint32 :e
1479
+ end.new
1480
+ end
1481
+
1482
+ context 'without null pointers' do
1483
+ let(:packet) do
1484
+ struct.new(a: 3, b: 'test1', c: 'test2', d: 'test3', e: 55)
1485
+ end
1486
+
1487
+ it 'writes as expected' do
1488
+ packet.do_write(io)
1489
+ raw_io.rewind
1490
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1491
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
1492
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
1493
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
1494
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
1495
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
1496
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00".b) # c
1497
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
1498
+ expect(raw_io.eof).to be true
1499
+ end
1500
+ end
1501
+
1502
+ context 'with null pointers' do
1503
+ let(:packet) do
1504
+ struct.new(a: 3, b: 'test1', c: :null, d: 'test3', e: 55)
1505
+ end
1506
+
1507
+ it 'writes as expected' do
1508
+ packet.do_write(io)
1509
+ raw_io.rewind
1510
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1511
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
1512
+ expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # c referent_id (null)
1513
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
1514
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
1515
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
1516
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
1517
+ expect(raw_io.eof).to be true
1518
+ end
1519
+ end
1520
+
1521
+ context 'with null strings' do
1522
+ let(:packet) do
1523
+ struct.new(a: 3, b: 'test1', c: 0, d: 'test3', e: 55)
1524
+ end
1525
+
1526
+ it 'writes as expected' do
1527
+ packet.do_write(io)
1528
+ raw_io.rewind
1529
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1530
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
1531
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
1532
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
1533
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
1534
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
1535
+ expect(raw_io.read(12)).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".b) # c
1536
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
1537
+ expect(raw_io.eof).to be true
1538
+ end
1539
+ end
1540
+
1541
+ context 'with padding' do
1542
+ let(:packet) do
1543
+ struct.new(a: 3, b: 'test1', c: 'test', d: 'test3', e: 55)
1544
+ end
1545
+
1546
+ it 'writes as expected' do
1547
+ packet.do_write(io)
1548
+ raw_io.rewind
1549
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1550
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
1551
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
1552
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
1553
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
1554
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
1555
+ expect(raw_io.read(22)).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00".b) # c
1556
+ expect(raw_io.read(2)).to eq("\x00\x00".b) # pad
1557
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
1558
+ expect(raw_io.eof).to be true
1559
+ end
1560
+ end
1561
+ end
1562
+ end
1563
+ end
1564
+
1565
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrStringPtrsw do
1566
+ subject(:packet) { described_class.new }
1567
+
1568
+ it { is_expected.to respond_to :max_count }
1569
+ it { is_expected.to respond_to :elements }
1570
+
1571
+ it 'is little endian' do
1572
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
1573
+ end
1574
+
1575
+ describe '#max_count' do
1576
+ it 'is a 32-bit unsigned integer' do
1577
+ expect(packet.max_count).to be_a BinData::Uint32le
1578
+ end
1579
+
1580
+ it 'has an initial value equal to #elements size' do
1581
+ packet.elements = ['A', 'B', 'C']
1582
+ expect(packet.max_count).to eq(3)
1583
+ end
1584
+ end
1585
+
1586
+ describe '#elements' do
1587
+ it 'is a Bindata::Array' do
1588
+ expect(packet.elements).to be_a BinData::Array
1589
+ end
1590
+
1591
+ it 'is an array of NdrLpStr' do
1592
+ expect(packet.elements[0]).to be_a RubySMB::Dcerpc::Ndr::NdrLpStr
1593
+ end
1594
+
1595
+ it 'exists if #max_count is greater than 0' do
1596
+ packet.max_count = 2
1597
+ expect(packet.elements?).to be true
1598
+ end
1599
+
1600
+ it 'does not exist if #max_count is 0' do
1601
+ packet.max_count = 0
1602
+ expect(packet.elements?).to be false
1603
+ end
1604
+ end
1605
+
1606
+ describe '#get' do
1607
+ it 'returns elements' do
1608
+ packet.elements = ['1', '2', '3']
1609
+ expect(packet.get).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
1610
+ end
1611
+ end
1612
+
1613
+ describe '#set' do
1614
+ it 'sets #elements as expected' do
1615
+ packet.set(['1', '2', '3'])
1616
+ expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
1617
+ end
1618
+
1619
+ it 'sets #max_count to the number of elements set' do
1620
+ packet.set(['1', '2', '3'])
1621
+ expect(packet.max_count).to eq(3)
1622
+ end
1623
+
1624
+ it 'calls #to_ary before setting the elements' do
1625
+ ary = BinData::Array.new(['1','2', '3'], type: :ndr_lp_str)
1626
+ expect(ary).to receive(:to_ary).and_call_original
1627
+ packet.set(ary)
1628
+ expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
1629
+ end
1630
+
1631
+ it 'keeps custom #max_count value when called from #to_binary_s' do
1632
+ packet.set(['1', '2', '3', '4', '5'])
1633
+ packet.max_count = 3
1634
+ packet.to_binary_s
1635
+ expect(packet.max_count).to eq(3)
1636
+ end
1637
+
1638
+ it 'keeps custom #max_count and #offset values when called from #do_num_bytes' do
1639
+ packet.set(['1', '2', '3', '4', '5'])
1640
+ packet.max_count = 3
1641
+ packet.do_num_bytes
1642
+ expect(packet.max_count).to eq(3)
1643
+ end
1644
+
1645
+ it 'sets #max_count to the number of elements set after setting custom #max_count value' do
1646
+ packet.set(['1', '2', '3', '4', '5'])
1647
+ packet.max_count = 3
1648
+ packet.set(['1', '2', '3', '4', '5'])
1649
+ expect(packet.max_count).to eq(5)
1650
+ end
1651
+ end
1652
+
1653
+ describe '#read' do
1654
+ context 'with a no elements' do
1655
+ it 'reads its own binary representation' do
1656
+ raw = packet.to_binary_s
1657
+ expect(described_class.read(raw)).to eq(packet)
1658
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
1659
+ end
1660
+ end
1661
+
1662
+ context 'with some elements' do
1663
+ it 'reads its own binary representation' do
1664
+ packet.set(['1', '2', '3'])
1665
+ raw = packet.to_binary_s
1666
+ expect(described_class.read(raw)).to eq(packet)
1667
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
1668
+ end
1669
+ end
1670
+ end
1671
+ end
1672
+
1673
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStringPtrsw do
1674
+ it 'is NdrPointer subclass' do
1675
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
1676
+ end
1677
+
1678
+ subject(:packet) { described_class.new }
1679
+
1680
+ it { is_expected.to respond_to :referent }
1681
+
1682
+ it 'is little endian' do
1683
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
1684
+ end
1685
+
1686
+ describe '#referent' do
1687
+ it 'is a NdrStringPtrsw structure' do
1688
+ expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrStringPtrsw
1689
+ end
1690
+
1691
+ it 'exists if superclass #referent_id is not zero' do
1692
+ packet.referent_id = 0xCCCC
1693
+ expect(packet.referent?).to be true
1694
+ end
1695
+
1696
+ it 'does not exist if superclass #referent_id is zero' do
1697
+ packet.referent_id = 0
1698
+ expect(packet.referent?).to be false
1699
+ end
1700
+ end
1701
+
1702
+ describe '#set' do
1703
+ it 'calls #to_ary before setting the elements, if supported' do
1704
+ ary = BinData::Array.new(['1', '2', '3'], type: :ndr_lp_str)
1705
+ expect(ary).to receive(:to_ary).and_call_original
1706
+ packet.set(ary)
1707
+ expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
1708
+ end
1709
+ end
1710
+
1711
+ describe '#read' do
1712
+ context 'with a null pointer' do
1713
+ it 'reads its own binary representation' do
1714
+ raw = packet.to_binary_s
1715
+ expect(described_class.read(raw)).to eq(packet)
1716
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
1717
+ end
1718
+ end
1719
+
1720
+ context 'with a normal NdrStringPtrsw structure' do
1721
+ it 'reads its own binary representation' do
1722
+ packet.set(['1', '2', '3'])
1723
+ raw = packet.to_binary_s
1724
+ expect(described_class.read(raw)).to eq(packet)
1725
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
1726
+ end
1727
+ end
1728
+ end
1729
+ end