ruby_smb 2.0.1 → 2.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (143) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +2 -1
  4. data/examples/anonymous_auth.rb +3 -3
  5. data/examples/append_file.rb +10 -8
  6. data/examples/authenticate.rb +9 -5
  7. data/examples/delete_file.rb +8 -6
  8. data/examples/enum_registry_key.rb +5 -4
  9. data/examples/enum_registry_values.rb +5 -4
  10. data/examples/list_directory.rb +8 -6
  11. data/examples/negotiate_with_netbios_service.rb +9 -5
  12. data/examples/net_share_enum_all.rb +6 -4
  13. data/examples/pipes.rb +11 -12
  14. data/examples/query_service_status.rb +64 -0
  15. data/examples/read_file.rb +8 -6
  16. data/examples/read_registry_key_value.rb +6 -5
  17. data/examples/rename_file.rb +9 -7
  18. data/examples/tree_connect.rb +7 -5
  19. data/examples/write_file.rb +9 -7
  20. data/lib/ruby_smb/client.rb +81 -48
  21. data/lib/ruby_smb/client/authentication.rb +5 -10
  22. data/lib/ruby_smb/client/echo.rb +2 -4
  23. data/lib/ruby_smb/client/negotiation.rb +21 -14
  24. data/lib/ruby_smb/client/tree_connect.rb +2 -4
  25. data/lib/ruby_smb/client/utils.rb +16 -10
  26. data/lib/ruby_smb/client/winreg.rb +1 -1
  27. data/lib/ruby_smb/dcerpc.rb +4 -0
  28. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  29. data/lib/ruby_smb/dcerpc/ndr.rb +306 -44
  30. data/lib/ruby_smb/dcerpc/netlogon.rb +101 -0
  31. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request.rb +28 -0
  32. data/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response.rb +26 -0
  33. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request.rb +27 -0
  34. data/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response.rb +23 -0
  35. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request.rb +25 -0
  36. data/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response.rb +24 -0
  37. data/lib/ruby_smb/dcerpc/request.rb +19 -0
  38. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  39. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +9 -6
  40. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  41. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  42. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  43. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  44. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  45. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  46. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/winreg.rb +98 -17
  59. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  60. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  61. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +1 -1
  62. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +1 -1
  63. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +1 -1
  64. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +4 -4
  65. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +1 -1
  66. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +7 -6
  67. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +10 -10
  68. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  69. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  70. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  71. data/lib/ruby_smb/dispatcher/socket.rb +1 -1
  72. data/lib/ruby_smb/error.rb +21 -5
  73. data/lib/ruby_smb/field/stringz16.rb +17 -1
  74. data/lib/ruby_smb/generic_packet.rb +11 -1
  75. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  76. data/lib/ruby_smb/smb1/file.rb +10 -25
  77. data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +0 -1
  78. data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +0 -1
  79. data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +1 -2
  80. data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +1 -13
  81. data/lib/ruby_smb/smb1/pipe.rb +8 -6
  82. data/lib/ruby_smb/smb1/tree.rb +13 -9
  83. data/lib/ruby_smb/smb2/file.rb +33 -33
  84. data/lib/ruby_smb/smb2/pipe.rb +9 -6
  85. data/lib/ruby_smb/smb2/tree.rb +21 -11
  86. data/lib/ruby_smb/version.rb +1 -1
  87. data/spec/lib/ruby_smb/client_spec.rb +195 -101
  88. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1396 -77
  89. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_request_spec.rb +69 -0
  90. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_authenticate3_response_spec.rb +53 -0
  91. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_request_spec.rb +69 -0
  92. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_password_set2_response_spec.rb +37 -0
  93. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_request_spec.rb +45 -0
  94. data/spec/lib/ruby_smb/dcerpc/netlogon/netr_server_req_challenge_response_spec.rb +37 -0
  95. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  96. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +49 -12
  97. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  98. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  99. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  100. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  101. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  102. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  103. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  104. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  105. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  106. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  107. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  108. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  109. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  110. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  111. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  112. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  113. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  114. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  115. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  116. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  117. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +0 -4
  118. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +2 -2
  119. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +2 -2
  120. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +9 -4
  121. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +0 -4
  122. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +17 -17
  123. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +11 -23
  124. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  125. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  126. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +227 -41
  127. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +10 -10
  128. data/spec/lib/ruby_smb/error_spec.rb +34 -5
  129. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  130. data/spec/lib/ruby_smb/generic_packet_spec.rb +7 -0
  131. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  132. data/spec/lib/ruby_smb/smb1/file_spec.rb +2 -4
  133. data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +0 -1
  134. data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +0 -1
  135. data/spec/lib/ruby_smb/smb1/packet/trans2/open2_response_spec.rb +0 -5
  136. data/spec/lib/ruby_smb/smb1/packet/trans2/set_file_information_response_spec.rb +0 -6
  137. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +30 -5
  138. data/spec/lib/ruby_smb/smb1/tree_spec.rb +22 -0
  139. data/spec/lib/ruby_smb/smb2/file_spec.rb +61 -9
  140. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +9 -5
  141. data/spec/lib/ruby_smb/smb2/tree_spec.rb +58 -1
  142. metadata +91 -2
  143. metadata.gz.sig +0 -0
@@ -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