ruby_smb 2.0.2 → 2.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (143) 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 +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 +3 -4
  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 +37 -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 +37 -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 +32 -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 +174 -68
  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 +107 -18
  143. metadata.gz.sig +0 -0
@@ -0,0 +1,22 @@
1
+ RSpec.describe RubySMB::Dcerpc::Winreg::SaveKeyResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :error_status }
5
+
6
+ it 'is little endian' do
7
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
8
+ end
9
+
10
+ describe '#error_status' do
11
+ it 'is a 32-bit unsigned integer' do
12
+ expect(packet.error_status).to be_a BinData::Uint32le
13
+ end
14
+ end
15
+
16
+ describe '#initialize_instance' do
17
+ it 'sets #opnum to REG_CREATE_KEY constant' do
18
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_CREATE_KEY)
19
+ end
20
+ end
21
+ end
22
+
@@ -132,8 +132,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
132
132
  describe '#query_value' do
133
133
  let(:handle) { double('Handle') }
134
134
  let(:value_name) { double('Value Name') }
135
- let(:query_value_request_packet1) { double('Query Value Request Packet #1') }
136
- let(:query_value_request_packet2) { double('Query Value Request Packet #2') }
135
+ let(:query_value_request_packet) { double('Query Value Request Packet #1') }
137
136
  let(:lp_data1) { double('LpData #1') }
138
137
  let(:lp_data2) { double('LpData #2') }
139
138
  let(:response1) { double('Response #1') }
@@ -142,26 +141,28 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
142
141
  let(:query_value_response2) { double('Query Value Response #2') }
143
142
  let(:data) { double('Data') }
144
143
  let(:lpcb_data) { double('LpcbData') }
145
- let(:lpcb_data_referent) { double('Lpcb Data Referent') }
144
+ let(:lpcb_data_referent) { double('LpcbData Referent') }
145
+ let(:lp_data2_referent) { double('LpData Referent') }
146
146
  before :example do
147
+ allow(described_class::QueryValueRequest).to receive(:new).and_return(query_value_request_packet)
148
+ allow(query_value_request_packet).to receive_messages(
149
+ :lp_type= => nil,
150
+ :lpcb_data= => nil,
151
+ :lpcb_len= => nil,
152
+ :lp_data= => nil,
153
+ :lp_data => lp_data2,
154
+ )
155
+ allow(lp_data2).to receive(:referent).and_return(lp_data2_referent)
156
+ allow(lp_data2_referent).to receive(:max_count=)
147
157
  first_request = true
148
- allow(described_class::QueryValueRequest).to receive(:new) do
158
+ allow(winreg).to receive(:dcerpc_request) do |arg|
149
159
  if first_request
150
160
  first_request = false
151
- query_value_request_packet1
161
+ response1
152
162
  else
153
- query_value_request_packet2
163
+ response2
154
164
  end
155
165
  end
156
- allow(query_value_request_packet1).to receive(:lp_data).and_return(lp_data1)
157
- allow(query_value_request_packet2).to receive_messages(
158
- :lp_data => lp_data2,
159
- :lpcb_data= => nil
160
- )
161
- allow(lp_data1).to receive(:referent_identifier=)
162
- allow(lp_data2).to receive(:max_count=)
163
- allow(winreg).to receive(:dcerpc_request).with(query_value_request_packet1).and_return(response1)
164
- allow(winreg).to receive(:dcerpc_request).with(query_value_request_packet2).and_return(response2)
165
166
  allow(described_class::QueryValueResponse).to receive(:read).with(response1).and_return(query_value_response1)
166
167
  allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_return(query_value_response2)
167
168
  allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
@@ -175,24 +176,22 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
175
176
 
176
177
  it 'create the expected QueryValueRequest packets' do
177
178
  winreg.query_value(handle, value_name)
178
- expect(described_class::QueryValueRequest).to have_received(:new).with(hkey: handle, lp_value_name: value_name).twice
179
- end
180
-
181
- it 'sets the expected user rights on the first request packet' do
182
- winreg.query_value(handle, value_name)
183
- expect(lp_data1).to have_received(:referent_identifier=).with(0)
179
+ expect(described_class::QueryValueRequest).to have_received(:new).with(hkey: handle, lp_value_name: value_name)
184
180
  end
185
181
 
186
- it 'sets the expected user rights on the second request packet' do
182
+ it 'sets the expected fields on the request packet' do
187
183
  winreg.query_value(handle, value_name)
188
- expect(lp_data2).to have_received(:max_count=).with(lpcb_data_referent)
189
- expect(query_value_request_packet2).to have_received(:lpcb_data=).with(lpcb_data)
184
+ expect(query_value_request_packet).to have_received(:lp_type=).with(0)
185
+ expect(query_value_request_packet).to have_received(:lpcb_data=).with(0)
186
+ expect(query_value_request_packet).to have_received(:lpcb_len=).with(0)
187
+ expect(query_value_request_packet).to have_received(:lpcb_data=).with(lpcb_data)
188
+ expect(query_value_request_packet).to have_received(:lp_data=).with([])
189
+ expect(lp_data2_referent).to have_received(:max_count=).with(lpcb_data_referent)
190
190
  end
191
191
 
192
192
  it 'sends the expected dcerpc requests' do
193
193
  winreg.query_value(handle, value_name)
194
- expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet1).once.ordered
195
- expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet2).once.ordered
194
+ expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet).twice
196
195
  end
197
196
 
198
197
  context 'when receiving the first response' do
@@ -293,8 +292,20 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
293
292
  let(:query_info_key_request_packet) { double('CloseKey Request Packet') }
294
293
  let(:response) { double('Response') }
295
294
  let(:query_info_key_response) { double('CloseKey Response') }
295
+ let(:lp_class) { double('LpClass') }
296
+ let(:lp_class_referent) { double('LpClass referent') }
297
+ let(:lp_class_buf_ref) { double('LpClass buffer referent') }
296
298
  before :example do
297
299
  allow(described_class::QueryInfoKeyRequest).to receive(:new).and_return(query_info_key_request_packet)
300
+ allow(query_info_key_request_packet).to receive_messages(
301
+ :lp_class= => nil,
302
+ :lp_class => lp_class,
303
+ )
304
+ allow(lp_class).to receive(:referent).and_return(lp_class_referent)
305
+ allow(lp_class_referent).to receive(:actual_count=)
306
+ allow(lp_class).to receive(:maximum_length=)
307
+ allow(lp_class).to receive_message_chain(:buffer, :referent => lp_class_buf_ref)
308
+ allow(lp_class_buf_ref).to receive(:max_count=)
298
309
  allow(winreg).to receive(:dcerpc_request).and_return(response)
299
310
  allow(described_class::QueryInfoKeyResponse).to receive(:read).and_return(query_info_key_response)
300
311
  allow(query_info_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
@@ -310,6 +321,14 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
310
321
  expect(winreg).to have_received(:dcerpc_request).with(query_info_key_request_packet)
311
322
  end
312
323
 
324
+ it 'sets the expected fields on the request packet' do
325
+ winreg.query_info_key(handle)
326
+ expect(query_info_key_request_packet).to have_received(:lp_class=).with('')
327
+ expect(lp_class_referent).to have_received(:actual_count=).with(0)
328
+ expect(lp_class).to have_received(:maximum_length=).with(1024)
329
+ expect(lp_class_buf_ref).to have_received(:max_count=).with(1024 / 2)
330
+ end
331
+
313
332
  it 'creates a QueryInfoKeyResponse structure from the expected dcerpc response' do
314
333
  winreg.query_info_key(handle)
315
334
  expect(described_class::QueryInfoKeyResponse).to have_received(:read).with(response)
@@ -338,25 +357,27 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
338
357
  let(:handle) { double('Handle') }
339
358
  let(:index) { double('Index') }
340
359
  let(:enum_key_request_packet) { double('enum_key Request Packet') }
341
- let(:lp_class) { double('Lp Class') }
342
360
  let(:lp_name) { double('Lp Name') }
343
361
  let(:buffer) { double('Buffer') }
344
- let(:lp_class_buffer_referent) { double('Lp Class buffer referent') }
345
362
  let(:lp_name_buffer_referent) { double('Lp Name buffer referent') }
346
363
  let(:response) { double('Response') }
347
364
  let(:enum_key_response) { double('enum_key Response') }
348
365
  let(:result_str) { double('Result String') }
366
+ let(:lp_class) { double('Lp Class') }
367
+ let(:lp_class_buffer_referent) { double('Lp Class buffer referent') }
349
368
  before :example do
350
369
  allow(described_class::EnumKeyRequest).to receive(:new).and_return(enum_key_request_packet)
351
370
  allow(enum_key_request_packet).to receive_messages(
352
371
  :lpft_last_write_time= => nil,
353
- :lp_class => lp_class,
354
- :lp_name => lp_name
372
+ :lp_class= => nil,
373
+ :lp_name => lp_name,
374
+ :lp_class => lp_class
355
375
  )
356
376
  allow(lp_class).to receive(:referent).and_return(lp_class_buffer_referent)
377
+ allow(lp_class_buffer_referent).to receive(:buffer=)
357
378
  allow(lp_name).to receive(:buffer).and_return(buffer)
379
+ allow(lp_name).to receive(:buffer=)
358
380
  allow(buffer).to receive(:referent).and_return(lp_name_buffer_referent)
359
- allow(lp_class_buffer_referent).to receive(:buffer=)
360
381
  allow(lp_name_buffer_referent).to receive(:max_count=)
361
382
  allow(winreg).to receive(:dcerpc_request).and_return(response)
362
383
  allow(described_class::EnumKeyResponse).to receive(:read).and_return(enum_key_response)
@@ -369,10 +390,12 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
369
390
  expect(described_class::EnumKeyRequest).to have_received(:new).with(hkey: handle, dw_index: index)
370
391
  end
371
392
 
372
- it 'sets the expected user rights on the request packet' do
393
+ it 'sets the expected parameters on the request packet' do
373
394
  winreg.enum_key(handle, index)
374
395
  expect(enum_key_request_packet).to have_received(:lpft_last_write_time=).with(0)
375
- expect(lp_class_buffer_referent).to have_received(:buffer=).with(0)
396
+ expect(enum_key_request_packet).to have_received(:lp_class=).with('')
397
+ expect(lp_class_buffer_referent).to have_received(:buffer=).with(:null)
398
+ expect(lp_name).to have_received(:buffer=).with('')
376
399
  expect(lp_name_buffer_referent).to have_received(:max_count=).with(256)
377
400
  end
378
401
 
@@ -410,7 +433,6 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
410
433
  let(:index) { double('Index') }
411
434
  let(:enum_value_request_packet) { double('EnumValue Request Packet') }
412
435
  let(:lp_value_name) { double('Lp Value Name') }
413
- let(:lp_data) { double('Lp Data') }
414
436
  let(:buffer) { double('Buffer') }
415
437
  let(:referent) { double('Referent') }
416
438
  let(:response) { double('Response') }
@@ -418,14 +440,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
418
440
  let(:result_str) { double('Result String') }
419
441
  before :example do
420
442
  allow(described_class::EnumValueRequest).to receive(:new).and_return(enum_value_request_packet)
421
- allow(enum_value_request_packet).to receive_messages(
422
- :lp_value_name => lp_value_name,
423
- :lp_data => lp_data
424
- )
443
+ allow(enum_value_request_packet).to receive(:lp_value_name).and_return(lp_value_name)
425
444
  allow(lp_value_name).to receive(:buffer).and_return(buffer)
445
+ allow(lp_value_name).to receive(:buffer=)
426
446
  allow(buffer).to receive(:referent).and_return(referent)
427
447
  allow(referent).to receive(:max_count=)
428
- allow(lp_data).to receive(:referent_identifier=)
429
448
  allow(winreg).to receive(:dcerpc_request).and_return(response)
430
449
  allow(described_class::EnumValueResponse).to receive(:read).and_return(enum_value_response)
431
450
  allow(enum_value_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
@@ -437,10 +456,10 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
437
456
  expect(described_class::EnumValueRequest).to have_received(:new).with(hkey: handle, dw_index: index)
438
457
  end
439
458
 
440
- it 'sets the expected user rights on the request packet' do
459
+ it 'sets the expected buffer on the request packet' do
441
460
  winreg.enum_value(handle, index)
442
461
  expect(referent).to have_received(:max_count=).with(256)
443
- expect(lp_data).to have_received(:referent_identifier=).with(0)
462
+ expect(lp_value_name).to have_received(:buffer=).with('')
444
463
  end
445
464
 
446
465
  it 'sends the expected dcerpc request' do
@@ -492,6 +511,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
492
511
  expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
493
512
  end
494
513
 
514
+ it 'does not bind a DCERPC connection if #bind argument is false' do
515
+ winreg.has_registry_key?(key, bind: false)
516
+ expect(winreg).to_not have_received(:bind)
517
+ end
518
+
495
519
  it 'opens the expected root key' do
496
520
  winreg.has_registry_key?(key)
497
521
  expect(winreg).to have_received(:open_root_key).with(root_key)
@@ -519,6 +543,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
519
543
  it 'closes the key' do
520
544
  winreg.has_registry_key?(key)
521
545
  expect(winreg).to have_received(:close_key).with(subkey_handle)
546
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
522
547
  end
523
548
 
524
549
  it 'returns true when no error occurs' do
@@ -549,6 +574,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
549
574
  expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
550
575
  end
551
576
 
577
+ it 'does not bind a DCERPC connection if #bind argument is false' do
578
+ winreg.read_registry_key_value(key, value_name, bind: false)
579
+ expect(winreg).to_not have_received(:bind)
580
+ end
581
+
552
582
  it 'opens the expected root key' do
553
583
  winreg.read_registry_key_value(key, value_name)
554
584
  expect(winreg).to have_received(:open_root_key).with(root_key)
@@ -567,6 +597,7 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
567
597
  it 'closes the key' do
568
598
  winreg.read_registry_key_value(key, value_name)
569
599
  expect(winreg).to have_received(:close_key).with(subkey_handle)
600
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
570
601
  end
571
602
 
572
603
  it 'returns expect registry key value' do
@@ -600,6 +631,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
600
631
  expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
601
632
  end
602
633
 
634
+ it 'does not bind a DCERPC connection if #bind argument is false' do
635
+ winreg.enum_registry_key(key, bind: false)
636
+ expect(winreg).to_not have_received(:bind)
637
+ end
638
+
603
639
  it 'opens the expected root key' do
604
640
  winreg.enum_registry_key(key)
605
641
  expect(winreg).to have_received(:open_root_key).with(root_key)
@@ -630,6 +666,13 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
630
666
  it 'closes the key' do
631
667
  winreg.enum_registry_key(key)
632
668
  expect(winreg).to have_received(:close_key).with(subkey_handle)
669
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
670
+ end
671
+
672
+ it 'only closes the key once when there is no subkey' do
673
+ winreg.enum_registry_key(root_key)
674
+ expect(winreg).to have_received(:close_key).once
675
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
633
676
  end
634
677
 
635
678
  it 'returns the expected array of enumerated keys' do
@@ -667,6 +710,11 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
667
710
  expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
668
711
  end
669
712
 
713
+ it 'does not bind a DCERPC connection if #bind argument is false' do
714
+ winreg.enum_registry_values(key, bind: false)
715
+ expect(winreg).to_not have_received(:bind)
716
+ end
717
+
670
718
  it 'opens the expected root key' do
671
719
  winreg.enum_registry_values(key)
672
720
  expect(winreg).to have_received(:open_root_key).with(root_key)
@@ -697,6 +745,13 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
697
745
  it 'closes the key' do
698
746
  winreg.enum_registry_values(key)
699
747
  expect(winreg).to have_received(:close_key).with(subkey_handle)
748
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
749
+ end
750
+
751
+ it 'only closes the key once when there is no subkey' do
752
+ winreg.enum_registry_values(root_key)
753
+ expect(winreg).to have_received(:close_key).once
754
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
700
755
  end
701
756
 
702
757
  it 'returns the expected array of enumerated keys' do
@@ -707,4 +762,135 @@ RSpec.describe RubySMB::Dcerpc::Winreg do
707
762
  expect(winreg.enum_registry_values(key)).to eq([value1, value2])
708
763
  end
709
764
  end
765
+
766
+ describe '#create_key' do
767
+ let(:handle) { double('Handle') }
768
+ let(:sub_key) { double('Sub key') }
769
+ let(:create_key_request) { double('CreateKey Request') }
770
+ let(:response) { double('Response') }
771
+ let(:create_key_response) { double('CreateKey Response') }
772
+ let(:hkey) { double('hkey') }
773
+ before :example do
774
+ allow(described_class::CreateKeyRequest).to receive(:new).and_return(create_key_request)
775
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
776
+ allow(described_class::CreateKeyResponse).to receive(:read).and_return(create_key_response)
777
+ allow(create_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
778
+ allow(create_key_response).to receive(:hkey).and_return(hkey)
779
+ end
780
+
781
+ it 'create the expected CreateKeyRequest packet with the default options' do
782
+ opts = {
783
+ hkey: handle,
784
+ lp_sub_key: sub_key,
785
+ lp_class: :null,
786
+ dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
787
+ sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(maximum: 1),
788
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
789
+ lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY
790
+ }
791
+ winreg.create_key(handle, sub_key)
792
+ expect(described_class::CreateKeyRequest).to have_received(:new).with(opts)
793
+ end
794
+
795
+ it 'create the expected CreateKeyRequest packet with custom options' do
796
+ opts = {
797
+ hkey: handle,
798
+ lp_sub_key: sub_key,
799
+ lp_class: 'MyClass',
800
+ dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_SYMLINK,
801
+ sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(key_set_value: 1),
802
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new(n_length: 3),
803
+ lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_OPENED_EXISTING_KEY
804
+ }
805
+ winreg.create_key(handle, sub_key, opts)
806
+ expect(described_class::CreateKeyRequest).to have_received(:new).with(opts)
807
+ end
808
+
809
+ it 'sends the expected dcerpc request' do
810
+ winreg.create_key(handle, sub_key)
811
+ expect(winreg).to have_received(:dcerpc_request).with(create_key_request)
812
+ end
813
+
814
+ it 'creates a CreateKeyResponse structure from the expected dcerpc response' do
815
+ winreg.create_key(handle, sub_key)
816
+ expect(described_class::CreateKeyResponse).to have_received(:read).with(response)
817
+ end
818
+
819
+ context 'when an IOError occurs while parsing the response' do
820
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
821
+ allow(described_class::CreateKeyResponse).to receive(:read).and_raise(IOError)
822
+ expect { winreg.create_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
823
+ end
824
+ end
825
+
826
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
827
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
828
+ allow(create_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
829
+ expect { winreg.create_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
830
+ end
831
+ end
832
+
833
+ it 'returns the expected key name' do
834
+ expect(winreg.create_key(handle, sub_key)).to eq(hkey)
835
+ end
836
+ end
837
+
838
+ describe '#save_key' do
839
+ let(:handle) { double('Handle') }
840
+ let(:filename) { double('Filename') }
841
+ let(:save_key_request) { double('CreateKey Request') }
842
+ let(:response) { double('Response') }
843
+ let(:save_key_response) { double('CreateKey Response') }
844
+ let(:hkey) { double('hkey') }
845
+ before :example do
846
+ allow(described_class::SaveKeyRequest).to receive(:new).and_return(save_key_request)
847
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
848
+ allow(described_class::SaveKeyResponse).to receive(:read).and_return(save_key_response)
849
+ allow(save_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
850
+ end
851
+
852
+ it 'create the expected SaveKeyRequest packet with the default options' do
853
+ opts = {
854
+ hkey: handle,
855
+ lp_file: filename,
856
+ lp_security_attributes: :null,
857
+ }
858
+ winreg.save_key(handle, filename)
859
+ expect(described_class::SaveKeyRequest).to have_received(:new).with(opts)
860
+ end
861
+
862
+ it 'create the expected SaveKeyRequest packet with custom options' do
863
+ opts = {
864
+ hkey: handle,
865
+ lp_file: filename,
866
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
867
+ }
868
+ winreg.save_key(handle, filename, opts)
869
+ expect(described_class::SaveKeyRequest).to have_received(:new).with(opts)
870
+ end
871
+
872
+ it 'sends the expected dcerpc request' do
873
+ winreg.save_key(handle, filename)
874
+ expect(winreg).to have_received(:dcerpc_request).with(save_key_request)
875
+ end
876
+
877
+ it 'creates a SaveKeyResponse structure from the expected dcerpc response' do
878
+ winreg.save_key(handle, filename)
879
+ expect(described_class::SaveKeyResponse).to have_received(:read).with(response)
880
+ end
881
+
882
+ context 'when an IOError occurs while parsing the response' do
883
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
884
+ allow(described_class::SaveKeyResponse).to receive(:read).and_raise(IOError)
885
+ expect { winreg.save_key(handle, filename) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
886
+ end
887
+ end
888
+
889
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
890
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
891
+ allow(save_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
892
+ expect { winreg.save_key(handle, filename) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
893
+ end
894
+ end
895
+ end
710
896
  end
@@ -102,26 +102,26 @@ RSpec.describe RubySMB::Dispatcher::Socket do
102
102
  end
103
103
 
104
104
  it 'reads the number of bytes specified in the nbss header' do
105
- packet_length = 10
106
- session_header.packet_length = packet_length
105
+ stream_protocol_length = 10
106
+ session_header.stream_protocol_length = stream_protocol_length
107
107
  allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
108
108
  expect(response_socket).to receive(:read).with(4).and_return(session_header)
109
- expect(response_socket).to receive(:read).with(packet_length).and_return('A' * packet_length)
109
+ expect(response_socket).to receive(:read).with(stream_protocol_length).and_return('A' * stream_protocol_length)
110
110
  smb_socket.recv_packet
111
111
  end
112
112
 
113
113
  context 'when the socket does not return everything the first time' do
114
114
  it 'calls #read several times until everything is returned' do
115
- packet_length = 67
115
+ stream_protocol_length = 67
116
116
  returned_length = 10
117
- session_header.packet_length = packet_length
117
+ session_header.stream_protocol_length = stream_protocol_length
118
118
  allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
119
119
 
120
120
  expect(response_socket).to receive(:read).with(4).and_return(session_header)
121
121
  loop do
122
- expect(response_socket).to receive(:read).with(packet_length).and_return('A' * returned_length).once
123
- packet_length -= returned_length
124
- break if packet_length <= 0
122
+ expect(response_socket).to receive(:read).with(stream_protocol_length).and_return('A' * returned_length).once
123
+ stream_protocol_length -= returned_length
124
+ break if stream_protocol_length <= 0
125
125
  end
126
126
  smb_socket.recv_packet
127
127
  end
@@ -134,7 +134,7 @@ RSpec.describe RubySMB::Dispatcher::Socket do
134
134
 
135
135
  context 'when the SMB packet is empty' do
136
136
  it 'returns the nbss header only' do
137
- session_header.packet_length = 0
137
+ session_header.stream_protocol_length = 0
138
138
  allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
139
139
  expect(smb_socket.recv_packet(full_response: true)).to eq(session_header.to_binary_s)
140
140
  end
@@ -148,7 +148,7 @@ RSpec.describe RubySMB::Dispatcher::Socket do
148
148
 
149
149
  context 'when the SMB packet is empty' do
150
150
  it 'returns an empty string' do
151
- session_header.packet_length = 0
151
+ session_header.stream_protocol_length = 0
152
152
  allow(RubySMB::Nbss::SessionHeader).to receive(:read).and_return(session_header)
153
153
  expect(smb_socket.recv_packet(full_response: false)).to eq('')
154
154
  end