ruby_smb 2.0.2 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  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 +72 -43
  21. data/lib/ruby_smb/client/negotiation.rb +1 -0
  22. data/lib/ruby_smb/dcerpc.rb +2 -0
  23. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  24. data/lib/ruby_smb/dcerpc/ndr.rb +209 -44
  25. data/lib/ruby_smb/dcerpc/request.rb +13 -0
  26. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  27. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  28. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  29. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  30. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  31. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  32. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  33. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  34. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  35. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  36. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  37. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  38. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  39. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  40. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  41. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  46. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  47. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  48. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  49. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  50. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  51. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  52. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  53. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  54. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  55. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  56. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  57. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  58. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  59. data/lib/ruby_smb/dispatcher/socket.rb +1 -1
  60. data/lib/ruby_smb/field/stringz16.rb +17 -1
  61. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  62. data/lib/ruby_smb/smb1/file.rb +2 -10
  63. data/lib/ruby_smb/smb1/pipe.rb +2 -0
  64. data/lib/ruby_smb/smb2/file.rb +25 -17
  65. data/lib/ruby_smb/smb2/pipe.rb +3 -0
  66. data/lib/ruby_smb/smb2/tree.rb +9 -3
  67. data/lib/ruby_smb/version.rb +1 -1
  68. data/spec/lib/ruby_smb/client_spec.rb +161 -60
  69. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  70. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  71. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  72. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  73. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  74. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  75. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  76. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  77. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  78. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  79. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  80. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  81. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  82. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  83. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  84. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  85. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  86. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  87. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  88. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  89. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  90. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  91. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  92. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  93. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  94. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  95. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  96. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  97. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  98. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  99. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  100. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  101. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +215 -41
  102. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
  103. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  104. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  105. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +7 -0
  106. data/spec/lib/ruby_smb/smb2/file_spec.rb +60 -6
  107. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +7 -0
  108. data/spec/lib/ruby_smb/smb2/tree_spec.rb +35 -1
  109. metadata +72 -2
  110. 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