ruby_smb 2.0.1 → 2.0.6

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 (143) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -1
  4. data/examples/anonymous_auth.rb +3 -3
  5. data/examples/append_file.rb +10 -8
  6. data/examples/authenticate.rb +9 -5
  7. data/examples/delete_file.rb +8 -6
  8. data/examples/enum_registry_key.rb +5 -4
  9. data/examples/enum_registry_values.rb +5 -4
  10. data/examples/list_directory.rb +8 -6
  11. data/examples/negotiate_with_netbios_service.rb +9 -5
  12. data/examples/net_share_enum_all.rb +6 -4
  13. data/examples/pipes.rb +11 -12
  14. data/examples/query_service_status.rb +64 -0
  15. data/examples/read_file.rb +8 -6
  16. data/examples/read_registry_key_value.rb +6 -5
  17. data/examples/rename_file.rb +9 -7
  18. data/examples/tree_connect.rb +7 -5
  19. data/examples/write_file.rb +9 -7
  20. data/lib/ruby_smb/client.rb +81 -48
  21. data/lib/ruby_smb/client/authentication.rb +5 -10
  22. data/lib/ruby_smb/client/echo.rb +2 -4
  23. data/lib/ruby_smb/client/negotiation.rb +21 -14
  24. data/lib/ruby_smb/client/tree_connect.rb +2 -4
  25. data/lib/ruby_smb/client/utils.rb +16 -10
  26. data/lib/ruby_smb/client/winreg.rb +1 -1
  27. data/lib/ruby_smb/dcerpc.rb +4 -0
  28. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  29. data/lib/ruby_smb/dcerpc/ndr.rb +306 -44
  30. data/lib/ruby_smb/dcerpc/netlogon.rb +101 -0
  31. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +28 -0
  32. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
  33. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +27 -0
  34. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
  35. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +25 -0
  36. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
  37. data/lib/ruby_smb/dcerpc/request.rb +19 -0
  38. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  39. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  40. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  41. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  46. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  59. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  60. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  61. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  62. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  63. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  64. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  65. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  66. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  67. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  68. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  69. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  70. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  71. data/lib/ruby_smb/dispatcher/socket.rb +1 -1
  72. data/lib/ruby_smb/error.rb +21 -5
  73. data/lib/ruby_smb/field/stringz16.rb +17 -1
  74. data/lib/ruby_smb/generic_packet.rb +11 -1
  75. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  76. data/lib/ruby_smb/smb1/file.rb +10 -25
  77. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
  78. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
  79. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
  80. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
  81. data/lib/ruby_smb/smb1/pipe.rb +8 -6
  82. data/lib/ruby_smb/smb1/tree.rb +13 -9
  83. data/lib/ruby_smb/smb2/file.rb +33 -33
  84. data/lib/ruby_smb/smb2/pipe.rb +9 -6
  85. data/lib/ruby_smb/smb2/tree.rb +21 -11
  86. data/lib/ruby_smb/version.rb +1 -1
  87. data/spec/lib/ruby_smb/client_spec.rb +195 -101
  88. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  89. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
  90. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
  91. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
  92. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
  93. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
  94. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
  95. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  96. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  97. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  98. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  99. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  100. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  101. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  102. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  103. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  104. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  105. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  106. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  107. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  108. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  109. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  110. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  111. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  112. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  113. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  114. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  115. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  116. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  117. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  118. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  119. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  120. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  121. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  122. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  123. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  124. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  125. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  126. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
  127. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
  128. data/spec/lib/ruby_smb/error_spec.rb +34 -5
  129. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  130. data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
  131. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  132. data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
  133. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
  134. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
  135. data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
  136. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
  137. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
  138. data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
  139. data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
  140. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
  141. data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
  142. metadata +91 -2
  143. metadata.gz.sig +0 -0
@@ -1,4 +1,4 @@
1
- RSpec.describe RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer do
1
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrPointer do
2
2
  subject(:packet) do
3
3
  Class.new(described_class) do
4
4
  endian :little
@@ -6,48 +6,190 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer do
6
6
  end.new
7
7
  end
8
8
 
9
- it { is_expected.to respond_to :referent_identifier }
9
+ it { is_expected.to respond_to :referent_id }
10
10
 
11
11
  it 'is little endian' do
12
12
  expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
13
13
  end
14
14
 
15
- describe '#referent_identifier' do
15
+ describe '#referent_id' do
16
16
  it 'is a 32-bit unsigned integer' do
17
- expect(packet.referent_identifier).to be_a BinData::Uint32le
17
+ expect(packet.referent_id).to be_a BinData::Uint32le
18
18
  end
19
19
 
20
- it 'has an initial value of 0x00020000' do
21
- expect(packet.referent_identifier).to eq(0x00020000)
20
+ it 'has an initial value of 0' do
21
+ expect(packet.referent_id).to eq(0)
22
22
  end
23
23
  end
24
24
 
25
25
  describe '#get' do
26
- it 'returns 0 when #referent_identifier is 0' do
27
- packet.referent_identifier = 0
28
- expect(packet.get).to eq(0)
26
+ it 'returns :null when #referent_id is 0' do
27
+ packet.referent_id = 0
28
+ expect(packet.get).to eq(:null)
29
29
  end
30
30
 
31
- it 'returns #referent when #referent_identifier is greater than 0' do
31
+ it 'returns #referent when #referent_id is not 0' do
32
32
  packet.set('spec_test')
33
33
  expect(packet.get).to eq(packet.referent)
34
34
  end
35
35
  end
36
36
 
37
37
  describe '#set' do
38
- context 'when the value is 0' do
39
- it 'sets #referent_identifier to 0' do
40
- packet.set(0)
41
- expect(packet.referent_identifier).to eq(0)
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)
42
47
  end
43
48
  end
44
49
 
45
50
  context 'when the value is a string' do
51
+ let(:str) { 'spec_test' }
52
+
46
53
  it 'sets #referent to the value' do
47
- str = 'spec_test'
48
54
  packet.set(str)
49
55
  expect(packet.referent).to eq(str)
50
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
51
193
  end
52
194
  end
53
195
  end
@@ -120,6 +262,24 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrString do
120
262
  packet.set(0)
121
263
  expect(packet.actual_count).to eq(0)
122
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
123
283
  end
124
284
 
125
285
  context 'when the value is a string' do
@@ -136,13 +296,123 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrString do
136
296
  expect(packet.max_count).to eq(str.length + 1)
137
297
  expect(packet.actual_count).to eq(str.length + 1)
138
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
139
409
  end
140
410
  end
141
411
  end
142
412
 
143
413
  RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStr do
144
- it 'is NdrTopLevelFullPointer subclass' do
145
- expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer
414
+ it 'is NdrPointer subclass' do
415
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
146
416
  end
147
417
 
148
418
  subject(:packet) { described_class.new }
@@ -158,25 +428,33 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStr do
158
428
  expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrString
159
429
  end
160
430
 
161
- it 'exists if superclass #referent_identifier is not zero' do
431
+ it 'exists if superclass #referent_id is not zero' do
432
+ packet.referent_id = 0xCCCC
162
433
  expect(packet.referent?).to be true
163
434
  end
164
435
 
165
- it 'does not exist if superclass #referent_identifier is zero' do
166
- packet.referent_identifier = 0
436
+ it 'does not exist if superclass #referent_id is zero' do
437
+ packet.referent_id = 0
167
438
  expect(packet.referent?).to be false
168
439
  end
169
440
  end
170
441
 
171
- describe '#to_s' do
172
- it 'returns "\0" when #referent_identifier is 0' do
173
- packet.referent_identifier = 0
174
- expect(packet.to_s).to eq("\0")
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
175
449
  end
176
450
 
177
- it 'returns #referent when #referent_identifier is greater than 0' do
178
- packet.set('spec_test')
179
- expect(packet.to_s).to eq(packet.referent)
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
180
458
  end
181
459
  end
182
460
  end
@@ -242,11 +520,42 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrContextHandle do
242
520
  end
243
521
  end
244
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
245
554
  end
246
555
 
247
556
  RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpDword do
248
- it 'is NdrTopLevelFullPointer subclass' do
249
- expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer
557
+ it 'is NdrPointer subclass' do
558
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
250
559
  end
251
560
 
252
561
  subject(:packet) { described_class.new }
@@ -262,40 +571,251 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpDword do
262
571
  expect(packet.referent).to be_a BinData::Uint32le
263
572
  end
264
573
 
265
- it 'exists if superclass #referent_identifier is not zero' do
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
266
625
  expect(packet.referent?).to be true
267
626
  end
268
627
 
269
- it 'does not exist if superclass #referent_identifier is zero' do
270
- packet.referent_identifier = 0
628
+ it 'does not exist if superclass #referent_id is zero' do
629
+ packet.referent_id = 0
271
630
  expect(packet.referent?).to be false
272
631
  end
273
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
274
678
  end
275
679
 
276
680
  RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
277
681
  subject(:packet) { described_class.new }
278
682
 
279
- it { is_expected.to respond_to :referent_identifier }
280
683
  it { is_expected.to respond_to :max_count }
281
- it { is_expected.to respond_to :offset }
282
- it { is_expected.to respond_to :actual_count }
283
- it { is_expected.to respond_to :bytes }
684
+ it { is_expected.to respond_to :elements }
284
685
 
285
686
  it 'is little endian' do
286
687
  expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
287
688
  end
288
689
 
289
- describe '#referent_identifier' do
690
+ describe '#max_count' do
290
691
  it 'is a 32-bit unsigned integer' do
291
- expect(packet.referent_identifier).to be_a BinData::Uint32le
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)
292
744
  end
293
745
 
294
- it 'has an initial value of 0x00020000' do
295
- expect(packet.referent_identifier).to eq(0x00020000)
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)
296
772
  end
297
773
  end
298
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
+
299
819
  describe '#max_count' do
300
820
  it 'is a 32-bit unsigned integer' do
301
821
  expect(packet.max_count).to be_a BinData::Uint32le
@@ -305,15 +825,6 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
305
825
  packet.actual_count = 345
306
826
  expect(packet.max_count).to eq(345)
307
827
  end
308
-
309
- it 'exists if #referent_identifier is not zero' do
310
- expect(packet.max_count?).to be true
311
- end
312
-
313
- it 'does not exist if #referent_identifier is zero' do
314
- packet.referent_identifier = 0
315
- expect(packet.max_count?).to be false
316
- end
317
828
  end
318
829
 
319
830
  describe '#offset' do
@@ -324,15 +835,6 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
324
835
  it 'has an initial value of 0' do
325
836
  expect(packet.offset).to eq(0)
326
837
  end
327
-
328
- it 'exists if #referent_identifier is not zero' do
329
- expect(packet.offset?).to be true
330
- end
331
-
332
- it 'does not exist if #referent_identifier is zero' do
333
- packet.referent_identifier = 0
334
- expect(packet.offset?).to be false
335
- end
336
838
  end
337
839
 
338
840
  describe '#actual_count' do
@@ -344,15 +846,6 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
344
846
  packet.bytes << 2 << 3 << 4 << 5
345
847
  expect(packet.actual_count).to eq(4)
346
848
  end
347
-
348
- it 'exists if #referent_identifier is not zero' do
349
- expect(packet.actual_count?).to be true
350
- end
351
-
352
- it 'does not exist if #referent_identifier is zero' do
353
- packet.referent_identifier = 0
354
- expect(packet.actual_count?).to be false
355
- end
356
849
  end
357
850
 
358
851
  describe '#bytes' do
@@ -368,21 +861,98 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
368
861
  it 'is 8-bit unsigned integer elements' do
369
862
  expect(packet.bytes[0]).to be_a BinData::Uint8
370
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
371
926
 
372
- it 'exists if #referent_identifier is not zero' do
373
- expect(packet.bytes?).to be true
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
374
934
  end
375
935
 
376
- it 'does not exist if #referent_identifier is zero' do
377
- packet.referent_identifier = 0
378
- expect(packet.bytes?).to be false
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
379
949
  end
380
950
  end
381
951
  end
382
952
 
383
953
  RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpFileTime do
384
- it 'is NdrTopLevelFullPointer subclass' do
385
- expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer
954
+ it 'is NdrPointer subclass' do
955
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
386
956
  end
387
957
 
388
958
  subject(:packet) { described_class.new }
@@ -398,13 +968,762 @@ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpFileTime do
398
968
  expect(packet.referent).to be_a RubySMB::Field::FileTime
399
969
  end
400
970
 
401
- it 'exists if superclass #referent_identifier is not zero' do
971
+ it 'exists if superclass #referent_id is not zero' do
972
+ packet.referent_id = 0xCCCC
402
973
  expect(packet.referent?).to be true
403
974
  end
404
975
 
405
- it 'does not exist if superclass #referent_identifier is zero' do
406
- packet.referent_identifier = 0
976
+ it 'does not exist if superclass #referent_id is zero' do
977
+ packet.referent_id = 0
407
978
  expect(packet.referent?).to be false
408
979
  end
409
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
410
1729
  end