ruby_smb 1.0.5 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. checksums.yaml +5 -5
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/.travis.yml +3 -2
  5. data/Gemfile +6 -2
  6. data/README.md +35 -47
  7. data/examples/anonymous_auth.rb +3 -3
  8. data/examples/append_file.rb +10 -8
  9. data/examples/authenticate.rb +9 -5
  10. data/examples/delete_file.rb +8 -6
  11. data/examples/enum_registry_key.rb +29 -0
  12. data/examples/enum_registry_values.rb +31 -0
  13. data/examples/list_directory.rb +8 -6
  14. data/examples/negotiate.rb +51 -8
  15. data/examples/negotiate_with_netbios_service.rb +9 -5
  16. data/examples/net_share_enum_all.rb +6 -4
  17. data/examples/pipes.rb +13 -13
  18. data/examples/query_service_status.rb +64 -0
  19. data/examples/read_file.rb +8 -6
  20. data/examples/read_file_encryption.rb +56 -0
  21. data/examples/read_registry_key_value.rb +33 -0
  22. data/examples/rename_file.rb +9 -7
  23. data/examples/tree_connect.rb +7 -5
  24. data/examples/write_file.rb +9 -7
  25. data/lib/ruby_smb.rb +4 -1
  26. data/lib/ruby_smb/client.rb +239 -21
  27. data/lib/ruby_smb/client/authentication.rb +27 -8
  28. data/lib/ruby_smb/client/encryption.rb +62 -0
  29. data/lib/ruby_smb/client/negotiation.rb +154 -12
  30. data/lib/ruby_smb/client/signing.rb +19 -0
  31. data/lib/ruby_smb/client/tree_connect.rb +4 -4
  32. data/lib/ruby_smb/client/utils.rb +8 -7
  33. data/lib/ruby_smb/client/winreg.rb +46 -0
  34. data/lib/ruby_smb/crypto.rb +30 -0
  35. data/lib/ruby_smb/dcerpc.rb +40 -0
  36. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  37. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  38. data/lib/ruby_smb/dcerpc/error.rb +6 -0
  39. data/lib/ruby_smb/dcerpc/ndr.rb +260 -16
  40. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  41. data/lib/ruby_smb/dcerpc/request.rb +41 -9
  42. data/lib/ruby_smb/dcerpc/rpc_security_attributes.rb +34 -0
  43. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +38 -0
  44. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  45. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  46. data/lib/ruby_smb/dcerpc/svcctl.rb +479 -0
  47. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request.rb +48 -0
  48. data/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response.rb +26 -0
  49. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request.rb +25 -0
  50. data/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response.rb +26 -0
  51. data/lib/ruby_smb/dcerpc/svcctl/control_service_request.rb +26 -0
  52. data/lib/ruby_smb/dcerpc/svcctl/control_service_response.rb +26 -0
  53. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request.rb +35 -0
  54. data/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response.rb +23 -0
  55. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_request.rb +31 -0
  56. data/lib/ruby_smb/dcerpc/svcctl/open_service_w_response.rb +23 -0
  57. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request.rb +25 -0
  58. data/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response.rb +44 -0
  59. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_request.rb +23 -0
  60. data/lib/ruby_smb/dcerpc/svcctl/query_service_status_response.rb +27 -0
  61. data/lib/ruby_smb/dcerpc/svcctl/service_status.rb +25 -0
  62. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_request.rb +27 -0
  63. data/lib/ruby_smb/dcerpc/svcctl/start_service_w_response.rb +25 -0
  64. data/lib/ruby_smb/dcerpc/winreg.rb +421 -0
  65. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  66. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  67. data/lib/ruby_smb/dcerpc/winreg/create_key_request.rb +73 -0
  68. data/lib/ruby_smb/dcerpc/winreg/create_key_response.rb +36 -0
  69. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  70. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  71. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  72. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  73. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  74. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  75. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  76. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  77. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  78. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  79. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +40 -0
  80. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  81. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  82. data/lib/ruby_smb/dcerpc/winreg/save_key_request.rb +37 -0
  83. data/lib/ruby_smb/dcerpc/winreg/save_key_response.rb +23 -0
  84. data/lib/ruby_smb/dispatcher/base.rb +1 -1
  85. data/lib/ruby_smb/dispatcher/socket.rb +5 -4
  86. data/lib/ruby_smb/error.rb +28 -1
  87. data/lib/ruby_smb/field/stringz16.rb +17 -1
  88. data/lib/ruby_smb/nbss/session_header.rb +4 -4
  89. data/lib/ruby_smb/smb1/commands.rb +1 -1
  90. data/lib/ruby_smb/smb1/file.rb +8 -14
  91. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
  92. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
  93. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  94. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
  95. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
  96. data/lib/ruby_smb/smb1/pipe.rb +81 -3
  97. data/lib/ruby_smb/smb1/tree.rb +12 -3
  98. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  99. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  100. data/lib/ruby_smb/smb2/file.rb +51 -61
  101. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  102. data/lib/ruby_smb/smb2/packet.rb +2 -0
  103. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  104. data/lib/ruby_smb/smb2/packet/error_packet.rb +2 -4
  105. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
  106. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
  107. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  108. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
  109. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
  110. data/lib/ruby_smb/smb2/pipe.rb +80 -3
  111. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  112. data/lib/ruby_smb/smb2/tree.rb +32 -20
  113. data/lib/ruby_smb/version.rb +1 -1
  114. data/ruby_smb.gemspec +5 -3
  115. data/spec/lib/ruby_smb/client_spec.rb +1583 -102
  116. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  117. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  118. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  119. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +1729 -0
  120. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  121. data/spec/lib/ruby_smb/dcerpc/rpc_security_attributes_spec.rb +161 -0
  122. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +135 -0
  123. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  124. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  125. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_request_spec.rb +191 -0
  126. data/spec/lib/ruby_smb/dcerpc/svcctl/change_service_config_w_response_spec.rb +38 -0
  127. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_request_spec.rb +30 -0
  128. data/spec/lib/ruby_smb/dcerpc/svcctl/close_service_handle_response_spec.rb +38 -0
  129. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_request_spec.rb +39 -0
  130. data/spec/lib/ruby_smb/dcerpc/svcctl/control_service_response_spec.rb +38 -0
  131. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_request_spec.rb +78 -0
  132. data/spec/lib/ruby_smb/dcerpc/svcctl/open_sc_manager_w_response_spec.rb +38 -0
  133. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_request_spec.rb +59 -0
  134. data/spec/lib/ruby_smb/dcerpc/svcctl/open_service_w_response_spec.rb +38 -0
  135. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_request_spec.rb +38 -0
  136. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_config_w_response_spec.rb +152 -0
  137. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_request_spec.rb +30 -0
  138. data/spec/lib/ruby_smb/dcerpc/svcctl/query_service_status_response_spec.rb +38 -0
  139. data/spec/lib/ruby_smb/dcerpc/svcctl/service_status_spec.rb +72 -0
  140. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_request_spec.rb +46 -0
  141. data/spec/lib/ruby_smb/dcerpc/svcctl/start_service_w_response_spec.rb +30 -0
  142. data/spec/lib/ruby_smb/dcerpc/svcctl_spec.rb +512 -0
  143. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  144. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  145. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_request_spec.rb +110 -0
  146. data/spec/lib/ruby_smb/dcerpc/winreg/create_key_response_spec.rb +44 -0
  147. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +104 -0
  148. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  149. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  150. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  151. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  152. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  153. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +95 -0
  154. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  155. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +35 -0
  156. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  157. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  158. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +138 -0
  159. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  160. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_request_spec.rb +57 -0
  161. data/spec/lib/ruby_smb/dcerpc/winreg/save_key_response_spec.rb +22 -0
  162. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +884 -0
  163. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  164. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +12 -12
  165. data/spec/lib/ruby_smb/error_spec.rb +59 -0
  166. data/spec/lib/ruby_smb/field/stringz16_spec.rb +12 -0
  167. data/spec/lib/ruby_smb/nbss/session_header_spec.rb +4 -11
  168. data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
  169. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  170. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  171. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  172. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  173. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +216 -147
  174. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  175. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  176. data/spec/lib/ruby_smb/smb2/file_spec.rb +146 -68
  177. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  178. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  179. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +3 -24
  180. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  181. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  182. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  183. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  184. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
  185. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +226 -148
  186. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  187. data/spec/lib/ruby_smb/smb2/tree_spec.rb +88 -9
  188. metadata +257 -81
  189. metadata.gz.sig +0 -0
  190. data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
  191. data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -0,0 +1,88 @@
1
+ RSpec.describe RubySMB::Dcerpc::Winreg::RpcHkey do
2
+ it 'is NdrContextHandle subclass' do
3
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrContextHandle
4
+ end
5
+ end
6
+
7
+ RSpec.describe RubySMB::Dcerpc::Winreg::QueryValueRequest do
8
+ subject(:packet) { described_class.new }
9
+
10
+ it { is_expected.to respond_to :hkey }
11
+ it { is_expected.to respond_to :lp_value_name }
12
+ it { is_expected.to respond_to :pad1 }
13
+ it { is_expected.to respond_to :lp_type }
14
+ it { is_expected.to respond_to :lp_data }
15
+ it { is_expected.to respond_to :pad2 }
16
+ it { is_expected.to respond_to :lpcb_data }
17
+ it { is_expected.to respond_to :lpcb_len }
18
+ it { is_expected.to respond_to :opnum }
19
+
20
+ it 'is little endian' do
21
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
22
+ end
23
+
24
+ describe '#hkey' do
25
+ it 'is a RpcHkey structure' do
26
+ expect(packet.hkey).to be_a RubySMB::Dcerpc::Winreg::RpcHkey
27
+ end
28
+ end
29
+
30
+ describe '#lp_value_name' do
31
+ it 'is a RrpUnicodeString structure' do
32
+ expect(packet.lp_value_name).to be_a RubySMB::Dcerpc::RrpUnicodeString
33
+ end
34
+ end
35
+
36
+ describe '#pad1' do
37
+ it 'is a string' do
38
+ expect(packet.pad1).to be_a BinData::String
39
+ end
40
+
41
+ it 'should keep #lp_type 4-byte aligned' do
42
+ packet.lp_value_name = 'test'
43
+ expect(packet.lp_type.abs_offset % 4).to eq 0
44
+ end
45
+ end
46
+
47
+ describe '#lp_type' do
48
+ it 'is a NdrLpDword structure' do
49
+ expect(packet.lp_type).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
50
+ end
51
+ end
52
+
53
+ describe '#lp_data' do
54
+ it 'is a NdrLpByteArray structure' do
55
+ expect(packet.lp_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpByteArray
56
+ end
57
+ end
58
+
59
+ describe '#lpcb_data' do
60
+ it 'is a NdrLpDword structure' do
61
+ expect(packet.lpcb_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
62
+ end
63
+ end
64
+
65
+ describe '#pad2' do
66
+ it 'is a string' do
67
+ expect(packet.pad2).to be_a BinData::String
68
+ end
69
+
70
+ it 'should keep #lpcb_data 4-byte aligned' do
71
+ packet.lp_data = [1, 2]
72
+ expect(packet.lpcb_data.abs_offset % 4).to eq 0
73
+ end
74
+ end
75
+
76
+ describe '#lpcb_len' do
77
+ it 'is a NdrLpDword structure' do
78
+ expect(packet.lpcb_len).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
79
+ end
80
+ end
81
+
82
+ describe '#initialize_instance' do
83
+ it 'sets #opnum to REG_QUERY_VALUE constant' do
84
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_QUERY_VALUE)
85
+ end
86
+ end
87
+ end
88
+
@@ -0,0 +1,138 @@
1
+ RSpec.describe RubySMB::Dcerpc::Winreg::QueryValueResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :lp_type }
5
+ it { is_expected.to respond_to :lp_data }
6
+ it { is_expected.to respond_to :pad }
7
+ it { is_expected.to respond_to :lpcb_data }
8
+ it { is_expected.to respond_to :lpcb_len }
9
+ it { is_expected.to respond_to :error_status }
10
+ it { is_expected.to respond_to :opnum }
11
+
12
+ it 'is little endian' do
13
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
14
+ end
15
+
16
+ describe '#lp_type' do
17
+ it 'is a NdrLpDword structure' do
18
+ expect(packet.lp_type).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
19
+ end
20
+ end
21
+
22
+ describe '#lp_data' do
23
+ it 'is a NdrLpByteArray structure' do
24
+ expect(packet.lp_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpByteArray
25
+ end
26
+ end
27
+
28
+ describe '#pad' do
29
+ it 'is a string' do
30
+ expect(packet.pad).to be_a BinData::String
31
+ end
32
+
33
+ it 'should keep #lpcb_data 4-byte aligned' do
34
+ packet.lp_data = 'spec_test'.bytes
35
+ expect(packet.lpcb_data.abs_offset % 4).to eq 0
36
+ end
37
+ end
38
+
39
+ describe '#lpcb_data' do
40
+ it 'is a NdrLpDword structure' do
41
+ expect(packet.lpcb_data).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
42
+ end
43
+ end
44
+
45
+ describe '#lpcb_len' do
46
+ it 'is a NdrLpDword structure' do
47
+ expect(packet.lpcb_len).to be_a RubySMB::Dcerpc::Ndr::NdrLpDword
48
+ end
49
+ end
50
+
51
+ describe '#error_status' do
52
+ it 'is a 32-bit unsigned integer' do
53
+ expect(packet.error_status).to be_a BinData::Uint32le
54
+ end
55
+ end
56
+
57
+ describe '#initialize_instance' do
58
+ it 'sets #opnum to REG_QUERY_VALUE constant' do
59
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_QUERY_VALUE)
60
+ end
61
+ end
62
+
63
+ describe '#data' do
64
+ context 'when #lp_type is 1 (unicode null-terminated string)' do
65
+ it 'returns the expected value' do
66
+ str = 'spec test string'.encode('utf-16le')
67
+ packet.lp_type = 1
68
+ packet.lp_data = str.bytes
69
+ expect(packet.data).to eq(str)
70
+ end
71
+ end
72
+
73
+ context 'when #lp_type is 2 (unicode null-terminated string with unexpanded references to environment variables)' do
74
+ it 'returns the expected value' do
75
+ str = '/%PATH%/foo'.encode('utf-16le')
76
+ packet.lp_type = 2
77
+ packet.lp_data = str.bytes
78
+ expect(packet.data).to eq(str)
79
+ end
80
+ end
81
+
82
+ context 'when #lp_type is 3 (binary data)' do
83
+ it 'returns the expected value' do
84
+ bytes = [0xFF, 0xEE, 0xDD, 0xCC].pack('C*')
85
+ packet.lp_type = 3
86
+ packet.lp_data = bytes.bytes
87
+ expect(packet.data).to eq(bytes)
88
+ end
89
+ end
90
+
91
+ context 'when #lp_type is 4 (a 32-bit number in little-endian format)' do
92
+ it 'returns the expected value' do
93
+ number = 12345
94
+ packet.lp_type = 4
95
+ packet.lp_data = [number].pack('V').bytes
96
+ expect(packet.data).to eq(number)
97
+ end
98
+ end
99
+
100
+ context 'when #lp_type is 5 (a 32-bit number in big-endian format)' do
101
+ it 'returns the expected value' do
102
+ number = 12345
103
+ packet.lp_type = 5
104
+ packet.lp_data = [number].pack('N').bytes
105
+ expect(packet.data).to eq(number)
106
+ end
107
+ end
108
+
109
+ context 'when #lp_type is 7 (a sequence of unicode null-terminated strings, terminated by an empty string)' do
110
+ it 'returns the expected value' do
111
+ str_array = ['String1', 'String2', 'String3', 'LastString'].map {|v| v.encode('utf-16le')}
112
+ null_byte = "\0".encode('utf-16le')
113
+ str = (str_array + [null_byte]).join(null_byte)
114
+ packet.lp_type = 7
115
+ packet.lp_data = str.bytes
116
+ expect(packet.data).to eq(str_array)
117
+ end
118
+ end
119
+
120
+ context 'when #lp_type is 11 (a 64-bit number in little-endian format)' do
121
+ it 'returns the expected value' do
122
+ number = 0x1234567812345678
123
+ packet.lp_type = 11
124
+ packet.lp_data = [number].pack('Q<').bytes
125
+ expect(packet.data).to eq(number)
126
+ end
127
+ end
128
+
129
+ context 'when #lp_type is an unknown value' do
130
+ it 'returns an empty string' do
131
+ str = 'test'
132
+ packet.lp_type = 6
133
+ packet.lp_data = str.bytes
134
+ expect(packet.data).to eq('')
135
+ end
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,32 @@
1
+ RSpec.describe RubySMB::Dcerpc::Winreg::Regsam do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :reserved }
5
+ it { is_expected.to respond_to :key_create_link }
6
+ it { is_expected.to respond_to :key_notify }
7
+ it { is_expected.to respond_to :key_enumerate_sub_keys }
8
+ it { is_expected.to respond_to :key_create_sub_key }
9
+ it { is_expected.to respond_to :key_set_value }
10
+ it { is_expected.to respond_to :key_query_value }
11
+ it { is_expected.to respond_to :reserved2 }
12
+ it { is_expected.to respond_to :key_wow64_32key }
13
+ it { is_expected.to respond_to :key_wow64_64key }
14
+ it { is_expected.to respond_to :reserved3 }
15
+ it { is_expected.to respond_to :synchronize }
16
+ it { is_expected.to respond_to :write_owner }
17
+ it { is_expected.to respond_to :write_dac }
18
+ it { is_expected.to respond_to :read_control }
19
+ it { is_expected.to respond_to :delete_access }
20
+ it { is_expected.to respond_to :generic_read }
21
+ it { is_expected.to respond_to :generic_write }
22
+ it { is_expected.to respond_to :generic_execute }
23
+ it { is_expected.to respond_to :generic_all }
24
+ it { is_expected.to respond_to :reserved4 }
25
+ it { is_expected.to respond_to :maximum }
26
+ it { is_expected.to respond_to :system_security }
27
+
28
+
29
+ it 'is little endian' do
30
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
31
+ end
32
+ end
@@ -0,0 +1,57 @@
1
+ RSpec.describe RubySMB::Dcerpc::Winreg::RpcHkey do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it 'is NdrContextHandle subclass' do
5
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrContextHandle
6
+ end
7
+ end
8
+
9
+ RSpec.describe RubySMB::Dcerpc::Winreg::SaveKeyRequest do
10
+ subject(:packet) { described_class.new }
11
+
12
+
13
+ it 'is little endian' do
14
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
15
+ end
16
+
17
+ it { is_expected.to respond_to :hkey }
18
+ it { is_expected.to respond_to :lp_file }
19
+ it { is_expected.to respond_to :pad }
20
+ it { is_expected.to respond_to :lp_security_attributes }
21
+
22
+ describe '#hkey' do
23
+ it 'is a RpcHkey structure' do
24
+ expect(packet.hkey).to be_a RubySMB::Dcerpc::Winreg::RpcHkey
25
+ end
26
+ end
27
+
28
+ describe '#lp_file' do
29
+ it 'is a RrpUnicodeString structure' do
30
+ expect(packet.lp_file).to be_a RubySMB::Dcerpc::RrpUnicodeString
31
+ end
32
+ end
33
+
34
+ describe '#pad' do
35
+ it 'is a string' do
36
+ expect(packet.pad).to be_a BinData::String
37
+ end
38
+
39
+ it 'should keep #lp_security_attributes 4-byte aligned' do
40
+ packet.lp_file = "test"
41
+ expect(packet.lp_security_attributes.abs_offset % 4).to eq 0
42
+ end
43
+ end
44
+
45
+ describe '#lp_security_attributes' do
46
+ it 'is a PrpcSecurityAttributes structure' do
47
+ expect(packet.lp_security_attributes).to be_a RubySMB::Dcerpc::PrpcSecurityAttributes
48
+ end
49
+ end
50
+
51
+ describe '#initialize_instance' do
52
+ it 'sets #opnum to REG_SAVE_KEY constant' do
53
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::Winreg::REG_SAVE_KEY)
54
+ end
55
+ end
56
+ end
57
+
@@ -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
+
@@ -0,0 +1,884 @@
1
+ RSpec.describe RubySMB::Dcerpc::Winreg do
2
+ let(:winreg) do
3
+ RubySMB::SMB1::Pipe.new(
4
+ tree: double('Tree'),
5
+ response: RubySMB::SMB1::Packet::NtCreateAndxResponse.new,
6
+ name: 'winreg'
7
+ )
8
+ end
9
+
10
+ describe '#open_root_key' do
11
+ let(:root_key_request_packet) { double('Root Key Request Packet') }
12
+ let(:response) { double('Response') }
13
+ let(:root_key_response_packet) { double('Root Key Response Packet') }
14
+ let(:ph_key) { double('PHKEY') }
15
+ before :example do
16
+ allow(described_class::OpenRootKeyRequest).to receive(:new).and_return(root_key_request_packet)
17
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
18
+ allow(described_class::OpenRootKeyResponse).to receive(:read).and_return(root_key_response_packet)
19
+ allow(root_key_response_packet).to receive_messages(
20
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
21
+ :ph_key => ph_key
22
+ )
23
+ end
24
+
25
+ context 'when the root key is unknown' do
26
+ it 'raises an ArgumentError exception' do
27
+ expect { winreg.open_root_key('UNKNOWN') }.to raise_error(ArgumentError)
28
+ end
29
+ end
30
+
31
+ it 'create the expected OpenRootKeyRequest packet' do
32
+ winreg.open_root_key('HKLM')
33
+ expect(described_class::OpenRootKeyRequest).to have_received(:new).with(opnum: described_class::OPEN_HKLM)
34
+ end
35
+
36
+ it 'sends the expected dcerpc request' do
37
+ winreg.open_root_key('HKLM')
38
+ expect(winreg).to have_received(:dcerpc_request).with(root_key_request_packet)
39
+ end
40
+
41
+ it 'creates a OpenRootKeyResponse structure from the expected dcerpc response' do
42
+ winreg.open_root_key('HKLM')
43
+ expect(described_class::OpenRootKeyResponse).to have_received(:read).with(response)
44
+ end
45
+
46
+ context 'when an IOError occurs while parsing the response' do
47
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
48
+ allow(described_class::OpenRootKeyResponse).to receive(:read).and_raise(IOError)
49
+ expect { winreg.open_root_key('HKLM') }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
50
+ end
51
+ end
52
+
53
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
54
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
55
+ allow(root_key_response_packet).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
56
+ expect { winreg.open_root_key('HKLM') }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
57
+ end
58
+ end
59
+
60
+ it 'returns the expected handler' do
61
+ expect(winreg.open_root_key('HKLM')).to eq(ph_key)
62
+ end
63
+ end
64
+
65
+ describe '#open_key' do
66
+ let(:handle) { double('Handle') }
67
+ let(:sub_key) { double('Sub-key') }
68
+ let(:openkey_request_packet) { double('OpenKey Request Packet') }
69
+ let(:regsam) { double('Regsam') }
70
+ let(:response) { double('Response') }
71
+ let(:open_key_response) { double('OpenKey Response') }
72
+ let(:phk_result) { double('Phk Result') }
73
+ before :example do
74
+ allow(described_class::OpenKeyRequest).to receive(:new).and_return(openkey_request_packet)
75
+ allow(openkey_request_packet).to receive(:sam_desired).and_return(regsam)
76
+ allow(regsam).to receive_messages(
77
+ :read_control= => nil,
78
+ :key_query_value= => nil,
79
+ :key_enumerate_sub_keys= => nil,
80
+ :key_notify= => nil,
81
+ )
82
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
83
+ allow(described_class::OpenKeyResponse).to receive(:read).and_return(open_key_response)
84
+ allow(open_key_response).to receive_messages(
85
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
86
+ :phk_result => phk_result
87
+ )
88
+ end
89
+
90
+ it 'create the expected OpenKeyRequest packet' do
91
+ winreg.open_key(handle, sub_key)
92
+ expect(described_class::OpenKeyRequest).to have_received(:new).with(hkey: handle, lp_sub_key: sub_key)
93
+ end
94
+
95
+ it 'sets the expected user rights on the request packet' do
96
+ winreg.open_key(handle, sub_key)
97
+ expect(regsam).to have_received(:read_control=).with(1)
98
+ expect(regsam).to have_received(:key_query_value=).with(1)
99
+ expect(regsam).to have_received(:key_enumerate_sub_keys=).with(1)
100
+ expect(regsam).to have_received(:key_notify=).with(1)
101
+ end
102
+
103
+ it 'sends the expected dcerpc request' do
104
+ winreg.open_key(handle, sub_key)
105
+ expect(winreg).to have_received(:dcerpc_request).with(openkey_request_packet)
106
+ end
107
+
108
+ it 'creates a OpenKeyResponse structure from the expected dcerpc response' do
109
+ winreg.open_key(handle, sub_key)
110
+ expect(described_class::OpenKeyResponse).to have_received(:read).with(response)
111
+ end
112
+
113
+ context 'when an IOError occurs while parsing the response' do
114
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
115
+ allow(described_class::OpenKeyResponse).to receive(:read).and_raise(IOError)
116
+ expect { winreg.open_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
117
+ end
118
+ end
119
+
120
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
121
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
122
+ allow(open_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
123
+ expect { winreg.open_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
124
+ end
125
+ end
126
+
127
+ it 'returns the expected handler' do
128
+ expect(winreg.open_key(handle, sub_key)).to eq(phk_result)
129
+ end
130
+ end
131
+
132
+ describe '#query_value' do
133
+ let(:handle) { double('Handle') }
134
+ let(:value_name) { double('Value Name') }
135
+ let(:query_value_request_packet) { double('Query Value Request Packet #1') }
136
+ let(:lp_data1) { double('LpData #1') }
137
+ let(:lp_data2) { double('LpData #2') }
138
+ let(:response1) { double('Response #1') }
139
+ let(:response2) { double('Response #2') }
140
+ let(:query_value_response1) { double('Query Value Response #1') }
141
+ let(:query_value_response2) { double('Query Value Response #2') }
142
+ let(:data) { double('Data') }
143
+ let(:lpcb_data) { double('LpcbData') }
144
+ let(:lpcb_data_referent) { double('LpcbData Referent') }
145
+ let(:lp_data2_referent) { double('LpData Referent') }
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=)
157
+ first_request = true
158
+ allow(winreg).to receive(:dcerpc_request) do |arg|
159
+ if first_request
160
+ first_request = false
161
+ response1
162
+ else
163
+ response2
164
+ end
165
+ end
166
+ allow(described_class::QueryValueResponse).to receive(:read).with(response1).and_return(query_value_response1)
167
+ allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_return(query_value_response2)
168
+ allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
169
+ allow(query_value_response2).to receive_messages(
170
+ :error_status => WindowsError::Win32::ERROR_SUCCESS,
171
+ :data => data
172
+ )
173
+ allow(query_value_response1).to receive(:lpcb_data).and_return(lpcb_data)
174
+ allow(lpcb_data).to receive(:referent).and_return(lpcb_data_referent)
175
+ end
176
+
177
+ it 'create the expected QueryValueRequest packets' do
178
+ winreg.query_value(handle, value_name)
179
+ expect(described_class::QueryValueRequest).to have_received(:new).with(hkey: handle, lp_value_name: value_name)
180
+ end
181
+
182
+ it 'sets the expected fields on the request packet' do
183
+ winreg.query_value(handle, value_name)
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
+ end
191
+
192
+ it 'sends the expected dcerpc requests' do
193
+ winreg.query_value(handle, value_name)
194
+ expect(winreg).to have_received(:dcerpc_request).with(query_value_request_packet).twice
195
+ end
196
+
197
+ context 'when receiving the first response' do
198
+ it 'creates a QueryValueResponse structure from the expected dcerpc response' do
199
+ winreg.query_value(handle, value_name)
200
+ expect(described_class::QueryValueResponse).to have_received(:read).with(response1)
201
+ end
202
+
203
+ context 'when an IOError occurs while parsing the response' do
204
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
205
+ allow(described_class::QueryValueResponse).to receive(:read).with(response1).and_raise(IOError)
206
+ expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
207
+ end
208
+ end
209
+
210
+ context 'when the first response error status is not WindowsError::Win32::ERROR_SUCCESS' do
211
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
212
+ allow(query_value_response1).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
213
+ expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
214
+ end
215
+ end
216
+ end
217
+
218
+ context 'when receiving the second response' do
219
+ it 'creates a QueryValueResponse structure from the expected dcerpc response' do
220
+ winreg.query_value(handle, value_name)
221
+ expect(described_class::QueryValueResponse).to have_received(:read).with(response2)
222
+ end
223
+
224
+ context 'when an IOError occurs while parsing the response' do
225
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
226
+ allow(described_class::QueryValueResponse).to receive(:read).with(response2).and_raise(IOError)
227
+ expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
228
+ end
229
+ end
230
+
231
+ context 'when the first response error status is not WindowsError::Win32::ERROR_SUCCESS' do
232
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
233
+ allow(query_value_response2).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
234
+ expect { winreg.query_value(handle, value_name) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
235
+ end
236
+ end
237
+ end
238
+
239
+ it 'returns the expected response data' do
240
+ expect(winreg.query_value(handle, value_name)).to eq(data)
241
+ end
242
+ end
243
+
244
+ describe '#close_key' do
245
+ let(:handle) { double('Handle') }
246
+ let(:close_key_request_packet) { double('CloseKey Request Packet') }
247
+ let(:response) { double('Response') }
248
+ let(:close_key_response) { double('CloseKey Response') }
249
+ before :example do
250
+ allow(described_class::CloseKeyRequest).to receive(:new).and_return(close_key_request_packet)
251
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
252
+ allow(described_class::CloseKeyResponse).to receive(:read).and_return(close_key_response)
253
+ allow(close_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
254
+ end
255
+
256
+ it 'create the expected CloseKeyRequest packet' do
257
+ winreg.close_key(handle)
258
+ expect(described_class::CloseKeyRequest).to have_received(:new).with(hkey: handle)
259
+ end
260
+
261
+ it 'sends the expected dcerpc request' do
262
+ winreg.close_key(handle)
263
+ expect(winreg).to have_received(:dcerpc_request).with(close_key_request_packet)
264
+ end
265
+
266
+ it 'creates a CloseKeyResponse structure from the expected dcerpc response' do
267
+ winreg.close_key(handle)
268
+ expect(described_class::CloseKeyResponse).to have_received(:read).with(response)
269
+ end
270
+
271
+ context 'when an IOError occurs while parsing the response' do
272
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
273
+ allow(described_class::CloseKeyResponse).to receive(:read).and_raise(IOError)
274
+ expect { winreg.close_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
275
+ end
276
+ end
277
+
278
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
279
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
280
+ allow(close_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
281
+ expect { winreg.close_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
282
+ end
283
+ end
284
+
285
+ it 'returns the expected error status' do
286
+ expect(winreg.close_key(handle)).to eq(WindowsError::Win32::ERROR_SUCCESS)
287
+ end
288
+ end
289
+
290
+ describe '#query_info_key' do
291
+ let(:handle) { double('Handle') }
292
+ let(:query_info_key_request_packet) { double('CloseKey Request Packet') }
293
+ let(:response) { double('Response') }
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') }
298
+ before :example do
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=)
309
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
310
+ allow(described_class::QueryInfoKeyResponse).to receive(:read).and_return(query_info_key_response)
311
+ allow(query_info_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
312
+ end
313
+
314
+ it 'create the expected QueryInfoKeyRequest packet' do
315
+ winreg.query_info_key(handle)
316
+ expect(described_class::QueryInfoKeyRequest).to have_received(:new).with(hkey: handle)
317
+ end
318
+
319
+ it 'sends the expected dcerpc request' do
320
+ winreg.query_info_key(handle)
321
+ expect(winreg).to have_received(:dcerpc_request).with(query_info_key_request_packet)
322
+ end
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
+
332
+ it 'creates a QueryInfoKeyResponse structure from the expected dcerpc response' do
333
+ winreg.query_info_key(handle)
334
+ expect(described_class::QueryInfoKeyResponse).to have_received(:read).with(response)
335
+ end
336
+
337
+ context 'when an IOError occurs while parsing the response' do
338
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
339
+ allow(described_class::QueryInfoKeyResponse).to receive(:read).and_raise(IOError)
340
+ expect { winreg.query_info_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
341
+ end
342
+ end
343
+
344
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
345
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
346
+ allow(query_info_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
347
+ expect { winreg.query_info_key(handle) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
348
+ end
349
+ end
350
+
351
+ it 'returns the expected response' do
352
+ expect(winreg.query_info_key(handle)).to eq(query_info_key_response)
353
+ end
354
+ end
355
+
356
+ describe '#enum_key' do
357
+ let(:handle) { double('Handle') }
358
+ let(:index) { double('Index') }
359
+ let(:enum_key_request_packet) { double('enum_key Request Packet') }
360
+ let(:lp_name) { double('Lp Name') }
361
+ let(:buffer) { double('Buffer') }
362
+ let(:lp_name_buffer_referent) { double('Lp Name buffer referent') }
363
+ let(:response) { double('Response') }
364
+ let(:enum_key_response) { double('enum_key Response') }
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') }
368
+ before :example do
369
+ allow(described_class::EnumKeyRequest).to receive(:new).and_return(enum_key_request_packet)
370
+ allow(enum_key_request_packet).to receive_messages(
371
+ :lpft_last_write_time= => nil,
372
+ :lp_class= => nil,
373
+ :lp_name => lp_name,
374
+ :lp_class => lp_class
375
+ )
376
+ allow(lp_class).to receive(:referent).and_return(lp_class_buffer_referent)
377
+ allow(lp_class_buffer_referent).to receive(:buffer=)
378
+ allow(lp_name).to receive(:buffer).and_return(buffer)
379
+ allow(lp_name).to receive(:buffer=)
380
+ allow(buffer).to receive(:referent).and_return(lp_name_buffer_referent)
381
+ allow(lp_name_buffer_referent).to receive(:max_count=)
382
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
383
+ allow(described_class::EnumKeyResponse).to receive(:read).and_return(enum_key_response)
384
+ allow(enum_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
385
+ allow(enum_key_response).to receive_message_chain(:lp_name, :to_s => result_str)
386
+ end
387
+
388
+ it 'create the expected EnumKeyRequest packet' do
389
+ winreg.enum_key(handle, index)
390
+ expect(described_class::EnumKeyRequest).to have_received(:new).with(hkey: handle, dw_index: index)
391
+ end
392
+
393
+ it 'sets the expected parameters on the request packet' do
394
+ winreg.enum_key(handle, index)
395
+ expect(enum_key_request_packet).to have_received(:lpft_last_write_time=).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('')
399
+ expect(lp_name_buffer_referent).to have_received(:max_count=).with(256)
400
+ end
401
+
402
+ it 'sends the expected dcerpc request' do
403
+ winreg.enum_key(handle, index)
404
+ expect(winreg).to have_received(:dcerpc_request).with(enum_key_request_packet)
405
+ end
406
+
407
+ it 'creates a EnumKeyResponse structure from the expected dcerpc response' do
408
+ winreg.enum_key(handle, index)
409
+ expect(described_class::EnumKeyResponse).to have_received(:read).with(response)
410
+ end
411
+
412
+ context 'when an IOError occurs while parsing the response' do
413
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
414
+ allow(described_class::EnumKeyResponse).to receive(:read).and_raise(IOError)
415
+ expect { winreg.enum_key(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
416
+ end
417
+ end
418
+
419
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
420
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
421
+ allow(enum_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
422
+ expect { winreg.enum_key(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
423
+ end
424
+ end
425
+
426
+ it 'returns the expected key name' do
427
+ expect(winreg.enum_key(handle, index)).to eq(result_str)
428
+ end
429
+ end
430
+
431
+ describe '#enum_value' do
432
+ let(:handle) { double('Handle') }
433
+ let(:index) { double('Index') }
434
+ let(:enum_value_request_packet) { double('EnumValue Request Packet') }
435
+ let(:lp_value_name) { double('Lp Value Name') }
436
+ let(:buffer) { double('Buffer') }
437
+ let(:referent) { double('Referent') }
438
+ let(:response) { double('Response') }
439
+ let(:enum_value_response) { double('EnumValue Response') }
440
+ let(:result_str) { double('Result String') }
441
+ before :example do
442
+ allow(described_class::EnumValueRequest).to receive(:new).and_return(enum_value_request_packet)
443
+ allow(enum_value_request_packet).to receive(:lp_value_name).and_return(lp_value_name)
444
+ allow(lp_value_name).to receive(:buffer).and_return(buffer)
445
+ allow(lp_value_name).to receive(:buffer=)
446
+ allow(buffer).to receive(:referent).and_return(referent)
447
+ allow(referent).to receive(:max_count=)
448
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
449
+ allow(described_class::EnumValueResponse).to receive(:read).and_return(enum_value_response)
450
+ allow(enum_value_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
451
+ allow(enum_value_response).to receive_message_chain(:lp_value_name, :to_s => result_str)
452
+ end
453
+
454
+ it 'create the expected EnumValueRequest packet' do
455
+ winreg.enum_value(handle, index)
456
+ expect(described_class::EnumValueRequest).to have_received(:new).with(hkey: handle, dw_index: index)
457
+ end
458
+
459
+ it 'sets the expected buffer on the request packet' do
460
+ winreg.enum_value(handle, index)
461
+ expect(referent).to have_received(:max_count=).with(256)
462
+ expect(lp_value_name).to have_received(:buffer=).with('')
463
+ end
464
+
465
+ it 'sends the expected dcerpc request' do
466
+ winreg.enum_value(handle, index)
467
+ expect(winreg).to have_received(:dcerpc_request).with(enum_value_request_packet)
468
+ end
469
+
470
+ it 'creates a EnumValueResponse structure from the expected dcerpc response' do
471
+ winreg.enum_value(handle, index)
472
+ expect(described_class::EnumValueResponse).to have_received(:read).with(response)
473
+ end
474
+
475
+ context 'when an IOError occurs while parsing the response' do
476
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
477
+ allow(described_class::EnumValueResponse).to receive(:read).and_raise(IOError)
478
+ expect { winreg.enum_value(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
479
+ end
480
+ end
481
+
482
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
483
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
484
+ allow(enum_value_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
485
+ expect { winreg.enum_value(handle, index) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
486
+ end
487
+ end
488
+
489
+ it 'returns the expected key name' do
490
+ expect(winreg.enum_value(handle, index)).to eq(result_str)
491
+ end
492
+ end
493
+
494
+ describe '#has_registry_key?' do
495
+ let(:root_key) { 'HKLM' }
496
+ let(:sub_key) { 'my\\sub\\key\\path' }
497
+ let(:key) { "#{root_key}\\#{sub_key}" }
498
+ let(:root_key_handle) { double('Root Key Handle') }
499
+ let(:subkey_handle) { double('Subkey Handle') }
500
+ before :example do
501
+ allow(winreg).to receive_messages(
502
+ :bind => nil,
503
+ :open_root_key => root_key_handle,
504
+ :open_key => subkey_handle,
505
+ :close_key => nil
506
+ )
507
+ end
508
+
509
+ it 'binds a DCERPC connection to the expected remote endpoint' do
510
+ winreg.has_registry_key?(key)
511
+ expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
512
+ end
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
+
519
+ it 'opens the expected root key' do
520
+ winreg.has_registry_key?(key)
521
+ expect(winreg).to have_received(:open_root_key).with(root_key)
522
+ end
523
+
524
+ it 'opens the expected registry key' do
525
+ winreg.has_registry_key?(key)
526
+ expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
527
+ end
528
+
529
+ context 'when a WinregError occurs while opening the root key' do
530
+ it 'returns false' do
531
+ allow(winreg).to receive(:open_root_key).and_raise(RubySMB::Dcerpc::Error::WinregError)
532
+ expect(winreg.has_registry_key?(key)).to be false
533
+ end
534
+ end
535
+
536
+ context 'when a WinregError occurs while opening the registry key' do
537
+ it 'returns false' do
538
+ allow(winreg).to receive(:open_key).and_raise(RubySMB::Dcerpc::Error::WinregError)
539
+ expect(winreg.has_registry_key?(key)).to be false
540
+ end
541
+ end
542
+
543
+ it 'closes the key' do
544
+ winreg.has_registry_key?(key)
545
+ expect(winreg).to have_received(:close_key).with(subkey_handle)
546
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
547
+ end
548
+
549
+ it 'returns true when no error occurs' do
550
+ expect(winreg.has_registry_key?(key)).to be true
551
+ end
552
+ end
553
+
554
+ describe '#read_registry_key_value' do
555
+ let(:root_key) { 'HKLM' }
556
+ let(:sub_key) { 'my\\sub\\key\\path' }
557
+ let(:key) { "#{root_key}\\#{sub_key}" }
558
+ let(:value_name) { 'registry_value_name' }
559
+ let(:root_key_handle) { double('Root Key Handle') }
560
+ let(:subkey_handle) { double('Subkey Handle') }
561
+ let(:value) { double('Value') }
562
+ before :example do
563
+ allow(winreg).to receive_messages(
564
+ :bind => nil,
565
+ :open_root_key => root_key_handle,
566
+ :open_key => subkey_handle,
567
+ :query_value => value,
568
+ :close_key => nil
569
+ )
570
+ end
571
+
572
+ it 'binds a DCERPC connection to the expected remote endpoint' do
573
+ winreg.read_registry_key_value(key, value_name)
574
+ expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
575
+ end
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
+
582
+ it 'opens the expected root key' do
583
+ winreg.read_registry_key_value(key, value_name)
584
+ expect(winreg).to have_received(:open_root_key).with(root_key)
585
+ end
586
+
587
+ it 'opens the expected registry key' do
588
+ winreg.read_registry_key_value(key, value_name)
589
+ expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
590
+ end
591
+
592
+ it 'queries the expected registry key value' do
593
+ winreg.read_registry_key_value(key, value_name)
594
+ expect(winreg).to have_received(:query_value).with(subkey_handle, value_name)
595
+ end
596
+
597
+ it 'closes the key' do
598
+ winreg.read_registry_key_value(key, value_name)
599
+ expect(winreg).to have_received(:close_key).with(subkey_handle)
600
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
601
+ end
602
+
603
+ it 'returns expect registry key value' do
604
+ expect(winreg.read_registry_key_value(key, value_name)).to eq(value)
605
+ end
606
+ end
607
+
608
+ describe '#enum_registry_key' do
609
+ let(:root_key) { 'HKLM' }
610
+ let(:sub_key) { 'my\\sub\\key\\path' }
611
+ let(:key) { "#{root_key}\\#{sub_key}" }
612
+ let(:value_name) { 'registry_value_name' }
613
+ let(:root_key_handle) { double('Root Key Handle') }
614
+ let(:subkey_handle) { double('Subkey Handle') }
615
+ let(:query_info_key_response) { double('Query Info Key Response') }
616
+ let(:subkey_nb) { 2 }
617
+ before :example do
618
+ allow(winreg).to receive_messages(
619
+ :bind => nil,
620
+ :open_root_key => root_key_handle,
621
+ :open_key => subkey_handle,
622
+ :query_info_key => query_info_key_response,
623
+ :enum_key => nil,
624
+ :close_key => nil
625
+ )
626
+ allow(query_info_key_response).to receive(:lpc_sub_keys).and_return(subkey_nb)
627
+ end
628
+
629
+ it 'binds a DCERPC connection to the expected remote endpoint' do
630
+ winreg.enum_registry_key(key)
631
+ expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
632
+ end
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
+
639
+ it 'opens the expected root key' do
640
+ winreg.enum_registry_key(key)
641
+ expect(winreg).to have_received(:open_root_key).with(root_key)
642
+ end
643
+
644
+ context 'when the registry key only contains the root key' do
645
+ it 'queries information for the root key' do
646
+ winreg.enum_registry_key(root_key)
647
+ expect(winreg).to have_received(:query_info_key).with(root_key_handle)
648
+ end
649
+ end
650
+
651
+ it 'opens the expected registry key' do
652
+ winreg.enum_registry_key(key)
653
+ expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
654
+ end
655
+
656
+ it 'queries information for the expected registry key' do
657
+ winreg.enum_registry_key(key)
658
+ expect(winreg).to have_received(:query_info_key).with(subkey_handle)
659
+ end
660
+
661
+ it 'calls #enum_key the expected number of times' do
662
+ winreg.enum_registry_key(key)
663
+ expect(winreg).to have_received(:enum_key).with(subkey_handle, instance_of(Fixnum)).twice
664
+ end
665
+
666
+ it 'closes the key' do
667
+ winreg.enum_registry_key(key)
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 'returns the expected array of enumerated keys' do
673
+ key1 = 'key1'
674
+ key2 = 'key2'
675
+ allow(winreg).to receive(:enum_key).with(subkey_handle, 0).and_return(key1)
676
+ allow(winreg).to receive(:enum_key).with(subkey_handle, 1).and_return(key2)
677
+ expect(winreg.enum_registry_key(key)).to eq([key1, key2])
678
+ end
679
+ end
680
+
681
+ describe '#enum_registry_values' do
682
+ let(:root_key) { 'HKLM' }
683
+ let(:sub_key) { 'my\\sub\\key\\path' }
684
+ let(:key) { "#{root_key}\\#{sub_key}" }
685
+ let(:value_name) { 'registry_value_name' }
686
+ let(:root_key_handle) { double('Root Key Handle') }
687
+ let(:subkey_handle) { double('Subkey Handle') }
688
+ let(:query_info_key_response) { double('Query Info Key Response') }
689
+ let(:subkey_nb) { 2 }
690
+ before :example do
691
+ allow(winreg).to receive_messages(
692
+ :bind => nil,
693
+ :open_root_key => root_key_handle,
694
+ :open_key => subkey_handle,
695
+ :query_info_key => query_info_key_response,
696
+ :enum_value => nil,
697
+ :close_key => nil
698
+ )
699
+ allow(query_info_key_response).to receive(:lpc_values).and_return(subkey_nb)
700
+ end
701
+
702
+ it 'binds a DCERPC connection to the expected remote endpoint' do
703
+ winreg.enum_registry_values(key)
704
+ expect(winreg).to have_received(:bind).with(endpoint: RubySMB::Dcerpc::Winreg)
705
+ end
706
+
707
+ it 'does not bind a DCERPC connection if #bind argument is false' do
708
+ winreg.enum_registry_values(key, bind: false)
709
+ expect(winreg).to_not have_received(:bind)
710
+ end
711
+
712
+ it 'opens the expected root key' do
713
+ winreg.enum_registry_values(key)
714
+ expect(winreg).to have_received(:open_root_key).with(root_key)
715
+ end
716
+
717
+ context 'when the registry key only contains the root key' do
718
+ it 'queries information for the root key' do
719
+ winreg.enum_registry_values(root_key)
720
+ expect(winreg).to have_received(:query_info_key).with(root_key_handle)
721
+ end
722
+ end
723
+
724
+ it 'opens the expected registry key' do
725
+ winreg.enum_registry_values(key)
726
+ expect(winreg).to have_received(:open_key).with(root_key_handle, sub_key)
727
+ end
728
+
729
+ it 'queries information for the expected registry key' do
730
+ winreg.enum_registry_values(key)
731
+ expect(winreg).to have_received(:query_info_key).with(subkey_handle)
732
+ end
733
+
734
+ it 'calls #enum_key the expected number of times' do
735
+ winreg.enum_registry_values(key)
736
+ expect(winreg).to have_received(:enum_value).with(subkey_handle, instance_of(Fixnum)).twice
737
+ end
738
+
739
+ it 'closes the key' do
740
+ winreg.enum_registry_values(key)
741
+ expect(winreg).to have_received(:close_key).with(subkey_handle)
742
+ expect(winreg).to have_received(:close_key).with(root_key_handle)
743
+ end
744
+
745
+ it 'returns the expected array of enumerated keys' do
746
+ value1 = 'value1'
747
+ value2 = 'value2'
748
+ allow(winreg).to receive(:enum_value).with(subkey_handle, 0).and_return(value1)
749
+ allow(winreg).to receive(:enum_value).with(subkey_handle, 1).and_return(value2)
750
+ expect(winreg.enum_registry_values(key)).to eq([value1, value2])
751
+ end
752
+ end
753
+
754
+ describe '#create_key' do
755
+ let(:handle) { double('Handle') }
756
+ let(:sub_key) { double('Sub key') }
757
+ let(:create_key_request) { double('CreateKey Request') }
758
+ let(:response) { double('Response') }
759
+ let(:create_key_response) { double('CreateKey Response') }
760
+ let(:hkey) { double('hkey') }
761
+ before :example do
762
+ allow(described_class::CreateKeyRequest).to receive(:new).and_return(create_key_request)
763
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
764
+ allow(described_class::CreateKeyResponse).to receive(:read).and_return(create_key_response)
765
+ allow(create_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
766
+ allow(create_key_response).to receive(:hkey).and_return(hkey)
767
+ end
768
+
769
+ it 'create the expected CreateKeyRequest packet with the default options' do
770
+ opts = {
771
+ hkey: handle,
772
+ lp_sub_key: sub_key,
773
+ lp_class: :null,
774
+ dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_VOLATILE,
775
+ sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(maximum: 1),
776
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
777
+ lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_CREATED_NEW_KEY
778
+ }
779
+ winreg.create_key(handle, sub_key)
780
+ expect(described_class::CreateKeyRequest).to have_received(:new).with(opts)
781
+ end
782
+
783
+ it 'create the expected CreateKeyRequest packet with custom options' do
784
+ opts = {
785
+ hkey: handle,
786
+ lp_sub_key: sub_key,
787
+ lp_class: 'MyClass',
788
+ dw_options: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_KEY_TYPE_SYMLINK,
789
+ sam_desired: RubySMB::Dcerpc::Winreg::Regsam.new(key_set_value: 1),
790
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new(n_length: 3),
791
+ lpdw_disposition: RubySMB::Dcerpc::Winreg::CreateKeyRequest::REG_OPENED_EXISTING_KEY
792
+ }
793
+ winreg.create_key(handle, sub_key, opts)
794
+ expect(described_class::CreateKeyRequest).to have_received(:new).with(opts)
795
+ end
796
+
797
+ it 'sends the expected dcerpc request' do
798
+ winreg.create_key(handle, sub_key)
799
+ expect(winreg).to have_received(:dcerpc_request).with(create_key_request)
800
+ end
801
+
802
+ it 'creates a CreateKeyResponse structure from the expected dcerpc response' do
803
+ winreg.create_key(handle, sub_key)
804
+ expect(described_class::CreateKeyResponse).to have_received(:read).with(response)
805
+ end
806
+
807
+ context 'when an IOError occurs while parsing the response' do
808
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
809
+ allow(described_class::CreateKeyResponse).to receive(:read).and_raise(IOError)
810
+ expect { winreg.create_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
811
+ end
812
+ end
813
+
814
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
815
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
816
+ allow(create_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
817
+ expect { winreg.create_key(handle, sub_key) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
818
+ end
819
+ end
820
+
821
+ it 'returns the expected key name' do
822
+ expect(winreg.create_key(handle, sub_key)).to eq(hkey)
823
+ end
824
+ end
825
+
826
+ describe '#save_key' do
827
+ let(:handle) { double('Handle') }
828
+ let(:filename) { double('Filename') }
829
+ let(:save_key_request) { double('CreateKey Request') }
830
+ let(:response) { double('Response') }
831
+ let(:save_key_response) { double('CreateKey Response') }
832
+ let(:hkey) { double('hkey') }
833
+ before :example do
834
+ allow(described_class::SaveKeyRequest).to receive(:new).and_return(save_key_request)
835
+ allow(winreg).to receive(:dcerpc_request).and_return(response)
836
+ allow(described_class::SaveKeyResponse).to receive(:read).and_return(save_key_response)
837
+ allow(save_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_SUCCESS)
838
+ end
839
+
840
+ it 'create the expected SaveKeyRequest packet with the default options' do
841
+ opts = {
842
+ hkey: handle,
843
+ lp_file: filename,
844
+ lp_security_attributes: :null,
845
+ }
846
+ winreg.save_key(handle, filename)
847
+ expect(described_class::SaveKeyRequest).to have_received(:new).with(opts)
848
+ end
849
+
850
+ it 'create the expected SaveKeyRequest packet with custom options' do
851
+ opts = {
852
+ hkey: handle,
853
+ lp_file: filename,
854
+ lp_security_attributes: RubySMB::Dcerpc::RpcSecurityAttributes.new,
855
+ }
856
+ winreg.save_key(handle, filename, opts)
857
+ expect(described_class::SaveKeyRequest).to have_received(:new).with(opts)
858
+ end
859
+
860
+ it 'sends the expected dcerpc request' do
861
+ winreg.save_key(handle, filename)
862
+ expect(winreg).to have_received(:dcerpc_request).with(save_key_request)
863
+ end
864
+
865
+ it 'creates a SaveKeyResponse structure from the expected dcerpc response' do
866
+ winreg.save_key(handle, filename)
867
+ expect(described_class::SaveKeyResponse).to have_received(:read).with(response)
868
+ end
869
+
870
+ context 'when an IOError occurs while parsing the response' do
871
+ it 'raises a RubySMB::Dcerpc::Error::InvalidPacket' do
872
+ allow(described_class::SaveKeyResponse).to receive(:read).and_raise(IOError)
873
+ expect { winreg.save_key(handle, filename) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
874
+ end
875
+ end
876
+
877
+ context 'when the response error status is not WindowsError::Win32::ERROR_SUCCESS' do
878
+ it 'raises a RubySMB::Dcerpc::Error::WinregError' do
879
+ allow(save_key_response).to receive(:error_status).and_return(WindowsError::Win32::ERROR_INVALID_DATA)
880
+ expect { winreg.save_key(handle, filename) }.to raise_error(RubySMB::Dcerpc::Error::WinregError)
881
+ end
882
+ end
883
+ end
884
+ end