ruby_smb 1.0.5 → 2.0.3

Sign up to get free protection for your applications and to get access to all the features.
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,25 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe RubySMB::Crypto::KDF do
4
+ describe '.counter_mode' do
5
+ it 'generates the expected 128-bit key' do
6
+ expected_key = "\x3c\x5e\x0a\x1b\x0a\xce\xa5\xb2\x64\x3f\xab\x78\xdc\x82\x31\x3b".b
7
+ expect(described_class.counter_mode('ki', 'label', 'context')).to eq(expected_key)
8
+ end
9
+
10
+ it 'generates the expected 256-bit key' do
11
+ expected_key =
12
+ "\x33\x4d\xa9\x6d\x24\x7e\xcb\x14\xf6\x24\x00\x97\x26\x51\xd5\xb4"\
13
+ "\x54\x5f\xda\x95\xf0\x5a\xcb\x25\x92\x57\xae\x71\x1c\x37\x20\x5b".b
14
+ expect(described_class.counter_mode('ki', 'label', 'context', length: 256)).to eq(expected_key)
15
+ end
16
+
17
+ it 'raises the expected exception when an error occurs' do
18
+ allow(OpenSSL::Digest).to receive(:new).and_raise(OpenSSL::OpenSSLError)
19
+ expect { described_class.counter_mode('ki', 'label', 'context') }.to raise_error(
20
+ RubySMB::Error::EncryptionError,
21
+ "Crypto::KDF.counter_mode OpenSSL error: OpenSSL::OpenSSLError"
22
+ )
23
+ end
24
+ end
25
+ end
@@ -31,7 +31,7 @@ RSpec.describe RubySMB::Dcerpc::BindAck do
31
31
  end
32
32
 
33
33
  it 'should have a default value of 0xFFFF' do
34
- expect(packet.max_xmit_frag).to eq 0xFFFF
34
+ expect(packet.max_xmit_frag).to eq RubySMB::Dcerpc::MAX_XMIT_FRAG
35
35
  end
36
36
  end
37
37
 
@@ -41,7 +41,7 @@ RSpec.describe RubySMB::Dcerpc::BindAck do
41
41
  end
42
42
 
43
43
  it 'should have a default value of 0xFFFF' do
44
- expect(packet.max_recv_frag).to eq 0xFFFF
44
+ expect(packet.max_recv_frag).to eq RubySMB::Dcerpc::MAX_RECV_FRAG
45
45
  end
46
46
  end
47
47
 
@@ -41,7 +41,7 @@ RSpec.describe RubySMB::Dcerpc::Bind do
41
41
  end
42
42
 
43
43
  it 'should have a default value of 0xFFFF' do
44
- expect(packet.max_xmit_frag).to eq 0xFFFF
44
+ expect(packet.max_xmit_frag).to eq RubySMB::Dcerpc::MAX_XMIT_FRAG
45
45
  end
46
46
  end
47
47
 
@@ -51,7 +51,7 @@ RSpec.describe RubySMB::Dcerpc::Bind do
51
51
  end
52
52
 
53
53
  it 'should have a default value of 0xFFFF' do
54
- expect(packet.max_recv_frag).to eq 0xFFFF
54
+ expect(packet.max_recv_frag).to eq RubySMB::Dcerpc::MAX_RECV_FRAG
55
55
  end
56
56
  end
57
57
 
@@ -0,0 +1,1729 @@
1
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrPointer do
2
+ subject(:packet) do
3
+ Class.new(described_class) do
4
+ endian :little
5
+ string :referent
6
+ end.new
7
+ end
8
+
9
+ it { is_expected.to respond_to :referent_id }
10
+
11
+ it 'is little endian' do
12
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
13
+ end
14
+
15
+ describe '#referent_id' do
16
+ it 'is a 32-bit unsigned integer' do
17
+ expect(packet.referent_id).to be_a BinData::Uint32le
18
+ end
19
+
20
+ it 'has an initial value of 0' do
21
+ expect(packet.referent_id).to eq(0)
22
+ end
23
+ end
24
+
25
+ describe '#get' do
26
+ it 'returns :null when #referent_id is 0' do
27
+ packet.referent_id = 0
28
+ expect(packet.get).to eq(:null)
29
+ end
30
+
31
+ it 'returns #referent when #referent_id is not 0' do
32
+ packet.set('spec_test')
33
+ expect(packet.get).to eq(packet.referent)
34
+ end
35
+ end
36
+
37
+ describe '#set' do
38
+ context 'when the value is :null' do
39
+ it 'clears #referent' do
40
+ expect(packet.referent).to receive(:clear)
41
+ packet.set(:null)
42
+ end
43
+
44
+ it 'sets #referent_id to 0' do
45
+ packet.set(:null)
46
+ expect(packet.referent_id).to eq(0)
47
+ end
48
+ end
49
+
50
+ context 'when the value is a string' do
51
+ let(:str) { 'spec_test' }
52
+
53
+ it 'sets #referent to the value' do
54
+ packet.set(str)
55
+ expect(packet.referent).to eq(str)
56
+ end
57
+
58
+ it 'calls #set when #referent support it' do
59
+ module TestSet; def set(v); end; end
60
+ packet.referent.extend(TestSet)
61
+ expect(packet.referent).to receive(:set).with(str)
62
+ packet.set(str)
63
+ end
64
+
65
+ it 'assigns directly to #referent when it does not support #set' do
66
+ expect(packet).to receive(:referent=).with(str)
67
+ packet.set(str)
68
+ end
69
+
70
+ it 'sets #referent_id to a random value' do
71
+ rnd = double('Random Value')
72
+ allow(packet).to receive(:rand).and_return(rnd)
73
+ expect(packet).to receive(:referent_id=).with(rnd)
74
+ packet.set(str)
75
+ end
76
+
77
+ it 'does not change #referent_id if it is already set' do
78
+ packet.referent_id = 0xCCCCCC
79
+ packet.set(str)
80
+ expect(packet.referent_id).to eq(0xCCCCCC)
81
+ end
82
+ end
83
+ end
84
+
85
+ describe '#do_read' do
86
+ let(:io) { StringIO.new }
87
+
88
+ it 'asks referent_id to read the io stream' do
89
+ expect(packet.referent_id).to receive(:do_read).with(io)
90
+ packet.do_read(io)
91
+ end
92
+
93
+ context 'when it can process #referent' do
94
+ before :example do
95
+ allow(packet).to receive(:process_referent?).and_return(true)
96
+ allow(packet.referent_id).to receive(:do_read)
97
+ end
98
+
99
+ it 'asks referent to read the io stream if referent_id is not 0' do
100
+ packet.referent_id = 0xCCCC
101
+ expect(packet.referent).to receive(:do_read).with(io)
102
+ packet.do_read(io)
103
+ end
104
+
105
+ it 'does not ask referent to read the io stream if referent_id is 0' do
106
+ packet.referent_id = 0
107
+ expect(packet.referent).to_not receive(:do_read).with(io)
108
+ packet.do_read(io)
109
+ end
110
+ end
111
+ end
112
+
113
+ describe '#do_write' do
114
+ let(:io) { StringIO.new }
115
+
116
+ it 'asks referent_id to write the io stream' do
117
+ expect(packet.referent_id).to receive(:do_write).with(io)
118
+ packet.do_write(io)
119
+ end
120
+
121
+ context 'when it can process #referent' do
122
+ before :example do
123
+ allow(packet).to receive(:process_referent?).and_return(true)
124
+ allow(packet.referent_id).to receive(:do_write)
125
+ end
126
+
127
+ it 'asks referent to write the io stream if referent_id is not 0' do
128
+ packet.referent_id = 0xCCCC
129
+ expect(packet.referent).to receive(:do_write).with(io)
130
+ packet.do_write(io)
131
+ end
132
+
133
+ it 'does not ask referent to write the io stream if referent_id is 0' do
134
+ packet.referent_id = 0
135
+ expect(packet.referent).to_not receive(:do_write).with(io)
136
+ packet.do_write(io)
137
+ end
138
+ end
139
+ end
140
+
141
+ describe '#process_referent?' do
142
+ let(:ndr_struct) { RubySMB::Dcerpc::Ndr::NdrStruct.new }
143
+ it 'returns false if the parent is a NdrStruct' do
144
+ obj = described_class.new(nil, {}, ndr_struct)
145
+ expect(obj.process_referent?).to be false
146
+ end
147
+
148
+ it 'returns false if one of the parents is a NdrStruct' do
149
+ obj1 = described_class.new(nil, {}, ndr_struct)
150
+ obj2 = described_class.new(nil, {}, obj1)
151
+ obj3 = described_class.new(nil, {}, obj2)
152
+ obj4 = described_class.new(nil, {}, obj3)
153
+ obj5 = described_class.new(nil, {}, obj4)
154
+ expect(obj5.process_referent?).to be false
155
+ end
156
+
157
+ it 'returns true if none of the parents is a NdrStruct' do
158
+ obj1 = described_class.new
159
+ obj2 = described_class.new(nil, {}, obj1)
160
+ obj3 = described_class.new(nil, {}, obj2)
161
+ obj4 = described_class.new(nil, {}, obj3)
162
+ obj5 = described_class.new(nil, {}, obj4)
163
+ expect(obj5.process_referent?).to be true
164
+ end
165
+ end
166
+
167
+ describe '#read' do
168
+ let(:struct) do
169
+ Class.new(described_class) do
170
+ attr_accessor :str_length
171
+ endian :little
172
+ string :referent, read_length: -> { self.str_length }
173
+ end
174
+ end
175
+
176
+ context 'with a null string' do
177
+ it 'reads its own binary representation' do
178
+ raw = packet.to_binary_s
179
+ expect(struct.read(raw)).to eq(packet)
180
+ expect(struct.read(raw).to_binary_s).to eq(raw)
181
+ end
182
+ end
183
+
184
+ context 'with a normal string' do
185
+ it 'reads its own binary representation' do
186
+ packet.set('testing')
187
+ raw = packet.to_binary_s
188
+ struct_obj = struct.new
189
+ struct_obj.str_length = 'testing'.size
190
+ expect(struct_obj.read(raw)).to eq(packet)
191
+ expect(struct_obj.read(raw).to_binary_s).to eq(raw)
192
+ end
193
+ end
194
+ end
195
+ end
196
+
197
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrString do
198
+ subject(:packet) { described_class.new }
199
+
200
+ it { is_expected.to respond_to :max_count }
201
+ it { is_expected.to respond_to :offset }
202
+ it { is_expected.to respond_to :actual_count }
203
+ it { is_expected.to respond_to :str }
204
+
205
+ it 'is little endian' do
206
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
207
+ end
208
+
209
+ describe '#max_count' do
210
+ it 'is a 32-bit unsigned integer' do
211
+ expect(packet.max_count).to be_a BinData::Uint32le
212
+ end
213
+ end
214
+
215
+ describe '#offset' do
216
+ it 'is a 32-bit unsigned integer' do
217
+ expect(packet.offset).to be_a BinData::Uint32le
218
+ end
219
+
220
+ it 'has an initial valu of 0' do
221
+ expect(packet.offset).to eq(0)
222
+ end
223
+ end
224
+
225
+ describe '#actual_count' do
226
+ it 'is a 32-bit unsigned integer' do
227
+ expect(packet.actual_count).to be_a BinData::Uint32le
228
+ end
229
+ end
230
+
231
+ describe '#str' do
232
+ it 'is a RubySMB::Field::Stringz16' do
233
+ expect(packet.str).to be_a RubySMB::Field::Stringz16
234
+ end
235
+
236
+ it 'exists if #actual_count is greater than 0' do
237
+ packet.actual_count = 4
238
+ expect(packet.str?).to be true
239
+ end
240
+
241
+ it 'does not exist if #actual_count is 0' do
242
+ expect(packet.str?).to be false
243
+ end
244
+ end
245
+
246
+ describe '#get' do
247
+ it 'returns 0 when #actual_count is 0' do
248
+ expect(packet.get).to eq(0)
249
+ end
250
+
251
+ it 'returns #str when #actual_count is greater than 0' do
252
+ str = 'spec_test'
253
+ strz16 = RubySMB::Field::Stringz16.new(str)
254
+ packet.set(str)
255
+ expect(packet.get).to eq(strz16)
256
+ end
257
+ end
258
+
259
+ describe '#set' do
260
+ context 'when the value is 0' do
261
+ it 'sets #actual_count to 0' do
262
+ packet.set(0)
263
+ expect(packet.actual_count).to eq(0)
264
+ end
265
+
266
+ it 'clears #str' do
267
+ expect(packet.str).to receive(:clear)
268
+ packet.set(0)
269
+ end
270
+
271
+ it 'keeps #actual_count set to 0 when called from #to_binary_s' do
272
+ packet.set(0)
273
+ packet.to_binary_s
274
+ expect(packet.actual_count).to eq(0)
275
+ end
276
+
277
+ it 'keeps #actual_count set to 0 when called from #do_num_bytes' do
278
+ packet.set(0)
279
+ packet.to_binary_s
280
+ packet.do_num_bytes
281
+ expect(packet.actual_count).to eq(0)
282
+ end
283
+ end
284
+
285
+ context 'when the value is a string' do
286
+ let(:str) { 'spec_test' }
287
+
288
+ it 'sets #str to the value' do
289
+ packet.set(str)
290
+ strz16 = RubySMB::Field::Stringz16.new(str)
291
+ expect(packet.str).to eq(strz16)
292
+ end
293
+
294
+ it 'sets #max_count and #actual_count to the expected value' do
295
+ packet.set(str)
296
+ expect(packet.max_count).to eq(str.length + 1)
297
+ expect(packet.actual_count).to eq(str.length + 1)
298
+ end
299
+
300
+ it 'sets #actual_count to 0 when the value is an empty string' do
301
+ packet.actual_count = 10
302
+ packet.set('')
303
+ expect(packet.actual_count).to eq(0)
304
+ end
305
+
306
+ it 'keeps custom #max_count and #offset values when called from #to_binary_s' do
307
+ packet.set(str)
308
+ packet.max_count = 3
309
+ packet.offset = 10
310
+ packet.to_binary_s
311
+ expect(packet.max_count).to eq(3)
312
+ expect(packet.offset).to eq(10)
313
+ end
314
+
315
+ it 'keeps custom #max_count value when called from #do_num_bytes' do
316
+ packet.set(str)
317
+ packet.max_count = 3
318
+ packet.offset = 10
319
+ packet.do_num_bytes
320
+ expect(packet.max_count).to eq(3)
321
+ expect(packet.offset).to eq(10)
322
+ end
323
+
324
+ it 'sets #max_count to the number of elements set after setting custom #max_count value' do
325
+ packet.set(str)
326
+ packet.max_count = 3
327
+ packet.set(str * 2)
328
+ expect(packet.max_count).to eq(str.size * 2 + 1)
329
+ end
330
+ end
331
+ end
332
+
333
+ describe '#clear' do
334
+ it 'clears #str' do
335
+ expect(packet.str).to receive(:clear)
336
+ packet.clear
337
+ end
338
+
339
+ it 'clears #actual_count' do
340
+ expect(packet.actual_count).to receive(:clear)
341
+ packet.clear
342
+ end
343
+
344
+ it 'does to clear out #max_count and #offset' do
345
+ expect(packet.max_count).to_not receive(:clear)
346
+ expect(packet.offset).to_not receive(:clear)
347
+ packet.clear
348
+ end
349
+ end
350
+
351
+ describe '#to_s' do
352
+ it 'calls str#to_s' do
353
+ expect(packet.str).to receive(:to_s)
354
+ packet.to_s
355
+ end
356
+
357
+ it 'outputs the expected string with the correct encoding' do
358
+ str = 'testing'
359
+ packet.assign(str)
360
+ expect(packet.to_s.encoding).to eq(Encoding::UTF_16LE)
361
+ expect(packet.to_s).to eq(str.encode(Encoding::UTF_16LE))
362
+ end
363
+ end
364
+
365
+ describe '#read' do
366
+ context 'with a null string' do
367
+ it 'reads its own binary representation' do
368
+ packet.set(0)
369
+ raw = packet.to_binary_s
370
+ expect(described_class.read(raw)).to eq(packet)
371
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
372
+ end
373
+ end
374
+
375
+ context 'with a normal string' do
376
+ it 'reads its own binary representation' do
377
+ packet.set('testing')
378
+ raw = packet.to_binary_s
379
+ expect(described_class.read(raw)).to eq(packet)
380
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
381
+ end
382
+ end
383
+
384
+ context 'with different #offset and #max_count values' do
385
+ it 'reads its own binary representation' do
386
+ packet.set('testing')
387
+ packet.max_count = 256
388
+ packet.offset = 40
389
+ raw = packet.to_binary_s
390
+ expect(described_class.read(raw)).to eq(packet)
391
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
392
+ end
393
+ end
394
+
395
+ context 'with #actual_count less than elements size' do
396
+ it 'reads its own binary representation reduced to #actual_count elements' do
397
+ str = '12345'
398
+ packet.set(str)
399
+ packet.actual_count = 4
400
+ max_count = packet.max_count.to_i
401
+ raw = packet.to_binary_s
402
+ packet2 = described_class.read(raw)
403
+ expect(packet2.max_count).to eq(max_count)
404
+ expect(packet2.offset).to eq(0)
405
+ expect(packet2.actual_count).to eq(4)
406
+ expect(packet2.str).to eq(str[0,3].encode(Encoding::UTF_16LE))
407
+ expect(packet2.to_binary_s).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x04\x00\x00\x001\x002\x003\x00\x00\x00".b)
408
+ end
409
+ end
410
+ end
411
+ end
412
+
413
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStr do
414
+ it 'is NdrPointer subclass' do
415
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
416
+ end
417
+
418
+ subject(:packet) { described_class.new }
419
+
420
+ it { is_expected.to respond_to :referent }
421
+
422
+ it 'is little endian' do
423
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
424
+ end
425
+
426
+ describe '#referent' do
427
+ it 'is a NdrString' do
428
+ expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrString
429
+ end
430
+
431
+ it 'exists if superclass #referent_id is not zero' do
432
+ packet.referent_id = 0xCCCC
433
+ expect(packet.referent?).to be true
434
+ end
435
+
436
+ it 'does not exist if superclass #referent_id is zero' do
437
+ packet.referent_id = 0
438
+ expect(packet.referent?).to be false
439
+ end
440
+ end
441
+
442
+ describe '#read' do
443
+ context 'with a null pointer' do
444
+ it 'reads its own binary representation' do
445
+ raw = packet.to_binary_s
446
+ expect(described_class.read(raw)).to eq(packet)
447
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
448
+ end
449
+ end
450
+
451
+ context 'with a normal string' do
452
+ it 'reads its own binary representation' do
453
+ packet.set('testing')
454
+ raw = packet.to_binary_s
455
+ expect(described_class.read(raw)).to eq(packet)
456
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
457
+ end
458
+ end
459
+ end
460
+ end
461
+
462
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrContextHandle do
463
+ let(:uuid) { 'c3bce70d-5155-472b-9f2f-b824e5fc9b60' }
464
+ let(:attr) { 123 }
465
+ subject(:packet) { described_class.new }
466
+
467
+ it { is_expected.to respond_to :context_handle_attributes }
468
+ it { is_expected.to respond_to :context_handle_uuid }
469
+
470
+ it 'is little endian' do
471
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
472
+ end
473
+
474
+ describe '#context_handle_attributes' do
475
+ it 'is a 32-bit unsigned integer' do
476
+ expect(packet.context_handle_attributes).to be_a BinData::Uint32le
477
+ end
478
+ end
479
+
480
+ describe '#context_handle_uuid' do
481
+ it 'is a UUID' do
482
+ expect(packet.context_handle_uuid).to be_a RubySMB::Dcerpc::Uuid
483
+ end
484
+ end
485
+
486
+ describe '#get' do
487
+ it 'returns the expeted hash' do
488
+ packet.context_handle_attributes = attr
489
+ packet.context_handle_uuid = uuid
490
+ expect(packet.get).to eq({context_handle_attributes: attr, context_handle_uuid: uuid})
491
+ end
492
+ end
493
+
494
+ describe '#set' do
495
+ let(:handle) { {context_handle_attributes: attr, context_handle_uuid: uuid} }
496
+
497
+ context 'when the value is a hash' do
498
+ it 'sets #context_handle_attributes and #context_handle_uuid to the expected values' do
499
+ packet.set(handle)
500
+ expect(packet.context_handle_attributes).to eq(attr)
501
+ expect(packet.context_handle_uuid).to eq(uuid)
502
+ end
503
+ end
504
+
505
+ context 'when the value is a NdrContextHandle'do
506
+ it 'reads the value binary representaion ' do
507
+ ndr_context_handle = described_class.new(handle)
508
+ allow(ndr_context_handle).to receive(:to_binary_s).and_call_original
509
+ packet.set(ndr_context_handle)
510
+ expect(ndr_context_handle).to have_received(:to_binary_s)
511
+ expect(packet.get).to eq(ndr_context_handle)
512
+ end
513
+ end
514
+
515
+ context 'when the value is a binary string'do
516
+ it 'reads the value' do
517
+ ndr_context_handle = described_class.new(handle)
518
+ packet.set(ndr_context_handle.to_binary_s)
519
+ expect(packet.get).to eq(ndr_context_handle)
520
+ end
521
+ end
522
+ end
523
+
524
+ describe '#read' do
525
+ context 'with a hash' do
526
+ it 'reads its own binary representation' do
527
+ packet.set({context_handle_attributes: attr, context_handle_uuid: uuid})
528
+ raw = packet.to_binary_s
529
+ expect(described_class.read(raw)).to eq(packet)
530
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
531
+ end
532
+ end
533
+
534
+ context 'with a NdrContextHandle' do
535
+ it 'reads its own binary representation' do
536
+ nch = described_class.new
537
+ nch.set({context_handle_attributes: attr, context_handle_uuid: uuid})
538
+ packet.set(nch)
539
+ raw = packet.to_binary_s
540
+ expect(described_class.read(raw)).to eq(packet)
541
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
542
+ end
543
+ end
544
+
545
+ context 'with a binary string' do
546
+ it 'reads its own binary representation' do
547
+ packet.set("{\x00\x00\x00\r\xE7\xBC\xC3UQ+G\x9F/\xB8$\xE5\xFC\x9B`".b)
548
+ raw = packet.to_binary_s
549
+ expect(described_class.read(raw)).to eq(packet)
550
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
551
+ end
552
+ end
553
+ end
554
+ end
555
+
556
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpDword do
557
+ it 'is NdrPointer subclass' do
558
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
559
+ end
560
+
561
+ subject(:packet) { described_class.new }
562
+
563
+ it { is_expected.to respond_to :referent }
564
+
565
+ it 'is little endian' do
566
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
567
+ end
568
+
569
+ describe '#referent' do
570
+ it 'is a 32-bit unsigned integer' do
571
+ expect(packet.referent).to be_a BinData::Uint32le
572
+ end
573
+
574
+ it 'exists if superclass #referent_id is not zero' do
575
+ packet.referent_id = 0xCCCC
576
+ expect(packet.referent?).to be true
577
+ end
578
+
579
+ it 'does not exist if superclass #referent_id is zero' do
580
+ packet.referent_id = 0
581
+ expect(packet.referent?).to be false
582
+ end
583
+ end
584
+
585
+ describe '#read' do
586
+ context 'with a null pointer' do
587
+ it 'reads its own binary representation' do
588
+ raw = packet.to_binary_s
589
+ expect(described_class.read(raw)).to eq(packet)
590
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
591
+ end
592
+ end
593
+
594
+ context 'with a normal integer' do
595
+ it 'reads its own binary representation' do
596
+ packet.set(123)
597
+ raw = packet.to_binary_s
598
+ expect(described_class.read(raw)).to eq(packet)
599
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
600
+ end
601
+ end
602
+ end
603
+ end
604
+
605
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByteArray do
606
+ it 'is NdrPointer subclass' do
607
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
608
+ end
609
+
610
+ subject(:packet) { described_class.new }
611
+
612
+ it { is_expected.to respond_to :referent }
613
+
614
+ it 'is little endian' do
615
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
616
+ end
617
+
618
+ describe '#referent' do
619
+ it 'is a NdrByteArray structure' do
620
+ expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrByteArray
621
+ end
622
+
623
+ it 'exists if superclass #referent_id is not zero' do
624
+ packet.referent_id = 0xCCCC
625
+ expect(packet.referent?).to be true
626
+ end
627
+
628
+ it 'does not exist if superclass #referent_id is zero' do
629
+ packet.referent_id = 0
630
+ expect(packet.referent?).to be false
631
+ end
632
+ end
633
+
634
+ describe '#set' do
635
+ it 'accepts a NdrLpByteArray structure' do
636
+ struct = described_class.new([1, 2, 3])
637
+ packet.set(struct)
638
+ expect(packet).to eq(struct)
639
+ end
640
+
641
+ it 'accepts a NdrLpByteArray null pointer' do
642
+ struct = described_class.new
643
+ packet.set(struct)
644
+ expect(packet).to eq(:null)
645
+ end
646
+
647
+ it 'accepts a BinData::Array' do
648
+ struct = BinData::Array.new([1, 2, 3], type: :uint8)
649
+ packet.set(struct)
650
+ expect(packet).to eq(struct)
651
+ end
652
+
653
+ it 'accepts an Array' do
654
+ struct = Array.new([1, 2, 3])
655
+ packet.set(struct)
656
+ expect(packet).to eq(struct)
657
+ end
658
+ end
659
+
660
+ describe '#read' do
661
+ context 'with a null pointer' do
662
+ it 'reads its own binary representation' do
663
+ raw = packet.to_binary_s
664
+ expect(described_class.read(raw)).to eq(packet)
665
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
666
+ end
667
+ end
668
+
669
+ context 'with a normal array of bytes' do
670
+ it 'reads its own binary representation' do
671
+ packet.set([1, 2, 3])
672
+ raw = packet.to_binary_s
673
+ expect(described_class.read(raw)).to eq(packet)
674
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
675
+ end
676
+ end
677
+ end
678
+ end
679
+
680
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
681
+ subject(:packet) { described_class.new }
682
+
683
+ it { is_expected.to respond_to :max_count }
684
+ it { is_expected.to respond_to :elements }
685
+
686
+ it 'is little endian' do
687
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
688
+ end
689
+
690
+ describe '#max_count' do
691
+ it 'is a 32-bit unsigned integer' do
692
+ expect(packet.max_count).to be_a BinData::Uint32le
693
+ end
694
+
695
+ it 'has an initial value equal to #elements size' do
696
+ packet.elements = [1, 2, 3]
697
+ expect(packet.max_count).to eq(3)
698
+ end
699
+ end
700
+
701
+ describe '#elements' do
702
+ it 'is a Bindata::Array' do
703
+ expect(packet.elements).to be_a BinData::Array
704
+ end
705
+
706
+ it 'is 8-bit unsigned integer elements' do
707
+ expect(packet.elements[0]).to be_a BinData::Uint8
708
+ end
709
+
710
+ it 'exists if #max_count is greater than 0' do
711
+ packet.max_count = 2
712
+ expect(packet.elements?).to be true
713
+ end
714
+
715
+ it 'does not exist if #max_count is 0' do
716
+ packet.max_count = 0
717
+ expect(packet.elements?).to be false
718
+ end
719
+
720
+ it 'reads at most #max_counts elements' do
721
+ bin = "ABCDEFG".b
722
+ packet.max_count = 3
723
+ packet.elements.read(bin)
724
+ expect(packet.elements).to eq(bin.bytes[0,3])
725
+ end
726
+ end
727
+
728
+ describe '#get' do
729
+ it 'returns the elements' do
730
+ packet.elements = [1, 2, 3]
731
+ expect(packet.get).to eq([1, 2, 3])
732
+ end
733
+ end
734
+
735
+ describe '#set' do
736
+ it 'sets #elements as expected' do
737
+ packet.set([1, 2, 3])
738
+ expect(packet.elements).to eq([1, 2, 3])
739
+ end
740
+
741
+ it 'sets #max_count to the number of elements set' do
742
+ packet.set([1, 2, 3])
743
+ expect(packet.max_count).to eq(3)
744
+ end
745
+
746
+ it 'calls #to_ary before setting the elements' do
747
+ ary = BinData::Array.new([1, 2, 3], type: :uint8)
748
+ expect(ary).to receive(:to_ary).and_call_original
749
+ packet.set(ary)
750
+ expect(packet.elements).to eq([1, 2, 3])
751
+ end
752
+
753
+ it 'keeps custom #max_count value when called from #to_binary_s' do
754
+ packet.set([1, 2, 3, 4, 5])
755
+ packet.max_count = 3
756
+ packet.to_binary_s
757
+ expect(packet.max_count).to eq(3)
758
+ end
759
+
760
+ it 'keeps custom #max_count value when called from #do_num_bytes' do
761
+ packet.set([1, 2, 3, 4, 5])
762
+ packet.max_count = 3
763
+ packet.do_num_bytes
764
+ expect(packet.max_count).to eq(3)
765
+ end
766
+
767
+ it 'sets #max_count to the number of elements set after setting custom #max_count value' do
768
+ packet.set([1, 2, 3, 4, 5])
769
+ packet.max_count = 3
770
+ packet.set([1, 2, 3, 4, 5])
771
+ expect(packet.max_count).to eq(5)
772
+ end
773
+ end
774
+
775
+ describe '#read' do
776
+ context 'with a no elements' do
777
+ it 'reads its own binary representation' do
778
+ raw = packet.to_binary_s
779
+ expect(described_class.read(raw)).to eq(packet)
780
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
781
+ end
782
+ end
783
+
784
+ context 'with some elements' do
785
+ it 'reads its own binary representation' do
786
+ packet.set([1, 2, 3])
787
+ raw = packet.to_binary_s
788
+ expect(described_class.read(raw)).to eq(packet)
789
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
790
+ end
791
+ end
792
+
793
+ context 'with #max_count less than elements size' do
794
+ it 'reads its own binary representation reduced to #max_count elements' do
795
+ packet.set([1, 2, 3, 4, 5])
796
+ packet.max_count = 3
797
+ raw = packet.to_binary_s
798
+ packet2 = described_class.new([1, 2, 3])
799
+ raw2 = packet2.to_binary_s
800
+ expect(described_class.read(raw)).to eq(packet2)
801
+ expect(described_class.read(raw).to_binary_s).to eq(raw2)
802
+ end
803
+ end
804
+ end
805
+ end
806
+
807
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrByteArray do
808
+ subject(:packet) { described_class.new }
809
+
810
+ it { is_expected.to respond_to :max_count }
811
+ it { is_expected.to respond_to :offset }
812
+ it { is_expected.to respond_to :actual_count }
813
+ it { is_expected.to respond_to :bytes }
814
+
815
+ it 'is little endian' do
816
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
817
+ end
818
+
819
+ describe '#max_count' do
820
+ it 'is a 32-bit unsigned integer' do
821
+ expect(packet.max_count).to be_a BinData::Uint32le
822
+ end
823
+
824
+ it 'has an initial value equal to #actual_count' do
825
+ packet.actual_count = 345
826
+ expect(packet.max_count).to eq(345)
827
+ end
828
+ end
829
+
830
+ describe '#offset' do
831
+ it 'is a 32-bit unsigned integer' do
832
+ expect(packet.offset).to be_a BinData::Uint32le
833
+ end
834
+
835
+ it 'has an initial value of 0' do
836
+ expect(packet.offset).to eq(0)
837
+ end
838
+ end
839
+
840
+ describe '#actual_count' do
841
+ it 'is a 32-bit unsigned integer' do
842
+ expect(packet.actual_count).to be_a BinData::Uint32le
843
+ end
844
+
845
+ it 'has an initial value equal to #bytes size' do
846
+ packet.bytes << 2 << 3 << 4 << 5
847
+ expect(packet.actual_count).to eq(4)
848
+ end
849
+ end
850
+
851
+ describe '#bytes' do
852
+ it 'is a Bindata::Array' do
853
+ expect(packet.bytes).to be_a BinData::Array
854
+ end
855
+
856
+ it 'has an initial length equal to #actual_count' do
857
+ packet.actual_count = 3
858
+ expect(packet.bytes.size).to eq(3)
859
+ end
860
+
861
+ it 'is 8-bit unsigned integer elements' do
862
+ expect(packet.bytes[0]).to be_a BinData::Uint8
863
+ end
864
+ end
865
+
866
+ describe '#get' do
867
+ it 'returns bytes' do
868
+ packet.bytes = [1, 2, 3]
869
+ expect(packet.get).to eq([1, 2, 3])
870
+ end
871
+ end
872
+
873
+ describe '#set' do
874
+ it 'sets #bytes as expected' do
875
+ packet.set([1, 2, 3])
876
+ expect(packet.bytes).to eq([1, 2, 3])
877
+ end
878
+
879
+ it 'sets #actual_count and #max_count to the number of bytes set' do
880
+ packet.set([1, 2, 3])
881
+ expect(packet.max_count).to eq(3)
882
+ expect(packet.actual_count).to eq(3)
883
+ end
884
+
885
+ it 'calls #to_ary before setting the elements' do
886
+ ary = BinData::Array.new([1, 2, 3], type: :uint8)
887
+ expect(ary).to receive(:to_ary).and_call_original
888
+ packet.set(ary)
889
+ expect(packet.bytes).to eq([1, 2, 3])
890
+ end
891
+
892
+ it 'keeps custom #max_count and #offset values when called from #to_binary_s' do
893
+ packet.set([1, 2, 3, 4, 5])
894
+ packet.max_count = 3
895
+ packet.offset = 40
896
+ packet.to_binary_s
897
+ expect(packet.max_count).to eq(3)
898
+ expect(packet.offset).to eq(40)
899
+ end
900
+
901
+ it 'keeps custom #max_count and #offset values when called from #do_num_bytes' do
902
+ packet.set([1, 2, 3, 4, 5])
903
+ packet.max_count = 3
904
+ packet.offset = 40
905
+ packet.do_num_bytes
906
+ expect(packet.max_count).to eq(3)
907
+ expect(packet.offset).to eq(40)
908
+ end
909
+
910
+ it 'sets #max_count to the number of bytes set after setting custom #max_count value' do
911
+ packet.set([1, 2, 3, 4, 5])
912
+ packet.max_count = 3
913
+ packet.set([1, 2, 3, 4, 5])
914
+ expect(packet.max_count).to eq(5)
915
+ end
916
+ end
917
+
918
+ describe '#read' do
919
+ context 'with a no elements' do
920
+ it 'reads its own binary representation' do
921
+ raw = packet.to_binary_s
922
+ expect(described_class.read(raw)).to eq(packet)
923
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
924
+ end
925
+ end
926
+
927
+ context 'with some elements' do
928
+ it 'reads its own binary representation' do
929
+ packet.set([1, 2, 3])
930
+ raw = packet.to_binary_s
931
+ expect(described_class.read(raw)).to eq(packet)
932
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
933
+ end
934
+ end
935
+
936
+ context 'with #max_count less than elements size' do
937
+ it 'reads its own binary representation reduced to #max_count elements' do
938
+ packet.set([1, 2, 3, 4, 5])
939
+ packet.actual_count = 3
940
+ max_count = packet.max_count.to_i
941
+ raw = packet.to_binary_s
942
+ packet2 = described_class.read(raw)
943
+ expect(packet2.max_count).to eq(max_count)
944
+ expect(packet2.offset).to eq(0)
945
+ expect(packet2.actual_count).to eq(3)
946
+ expect(packet2.bytes).to eq([1, 2, 3])
947
+ expect(packet2.to_binary_s).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x01\x02\x03".b)
948
+ end
949
+ end
950
+ end
951
+ end
952
+
953
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpFileTime do
954
+ it 'is NdrPointer subclass' do
955
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
956
+ end
957
+
958
+ subject(:packet) { described_class.new }
959
+
960
+ it { is_expected.to respond_to :referent }
961
+
962
+ it 'is little endian' do
963
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
964
+ end
965
+
966
+ describe '#referent' do
967
+ it 'is a FileTime' do
968
+ expect(packet.referent).to be_a RubySMB::Field::FileTime
969
+ end
970
+
971
+ it 'exists if superclass #referent_id is not zero' do
972
+ packet.referent_id = 0xCCCC
973
+ expect(packet.referent?).to be true
974
+ end
975
+
976
+ it 'does not exist if superclass #referent_id is zero' do
977
+ packet.referent_id = 0
978
+ expect(packet.referent?).to be false
979
+ end
980
+ end
981
+
982
+ describe '#read' do
983
+ context 'with a null pointer' do
984
+ it 'reads its own binary representation' do
985
+ raw = packet.to_binary_s
986
+ expect(described_class.read(raw)).to eq(packet)
987
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
988
+ end
989
+ end
990
+
991
+ context 'with a normal FileTime' do
992
+ it 'reads its own binary representation' do
993
+ time = RubySMB::Field::FileTime.new(Time.now)
994
+ packet.set(time)
995
+ raw = packet.to_binary_s
996
+ expect(described_class.read(raw)).to eq(packet)
997
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
998
+ end
999
+ end
1000
+ end
1001
+ end
1002
+
1003
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrStruct do
1004
+ describe '#do_read' do
1005
+ let(:io) { BinData::IO::Read.new(bin_str) }
1006
+ context 'with a structure containg an array of pointers to integer' do
1007
+ subject(:struct) do
1008
+ Class.new(described_class) do
1009
+ endian :little
1010
+ uint32 :a
1011
+ array :b, type: :ndr_lp_dword, read_until: -> { index == a - 1 }
1012
+ uint32 :c
1013
+ end.new
1014
+ end
1015
+
1016
+ context 'without null pointers' do
1017
+ let(:bin_str) do
1018
+ "\x03\x00\x00\x00" + # a
1019
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1020
+ "&_>=" + # b[1] referent_id
1021
+ "T\r%\x18" + # b[2] referent_id
1022
+ "7\x00\x00\x00" + # c
1023
+ "\x01\x00\x00\x00" + # b[0]
1024
+ "\x02\x00\x00\x00" + # b[1]
1025
+ "\x03\x00\x00\x00" # b[2]
1026
+ end
1027
+
1028
+ it 'reads as expected' do
1029
+ struct.do_read(io)
1030
+ expect(struct.a).to eq(3)
1031
+ expect(struct.b).to eq([1, 2, 3])
1032
+ expect(struct.b[0].referent_id).to eq(2635975080)
1033
+ expect(struct.b[0].referent).to eq(1)
1034
+ expect(struct.b[1].referent_id).to eq(1027497766)
1035
+ expect(struct.b[1].referent).to eq(2)
1036
+ expect(struct.b[2].referent_id).to eq(405081428)
1037
+ expect(struct.b[2].referent).to eq(3)
1038
+ expect(struct.c).to eq(55)
1039
+ end
1040
+ end
1041
+
1042
+ context 'with null pointers' do
1043
+ let(:bin_str) do
1044
+ "\x03\x00\x00\x00" + # a
1045
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1046
+ "\x00\x00\x00\x00" + # b[1] referent_id (null)
1047
+ "T\r%\x18" + # b[2] referent_id
1048
+ "7\x00\x00\x00" + # c
1049
+ "\x01\x00\x00\x00" + # b[0]
1050
+ "\x03\x00\x00\x00" # b[2]
1051
+ end
1052
+
1053
+ it 'reads as expected' do
1054
+ struct.do_read(io)
1055
+ expect(struct.a).to eq(3)
1056
+ expect(struct.b).to eq([1, :null, 3])
1057
+ expect(struct.b[0].referent_id).to eq(2635975080)
1058
+ expect(struct.b[0].referent).to eq(1)
1059
+ expect(struct.b[1].referent_id).to eq(0)
1060
+ expect(struct.b[2].referent_id).to eq(405081428)
1061
+ expect(struct.b[2].referent).to eq(3)
1062
+ expect(struct.c).to eq(55)
1063
+ end
1064
+ end
1065
+ end
1066
+
1067
+ context 'with a structure containg an array of pointers to strings' do
1068
+ subject(:struct) do
1069
+ Class.new(described_class) do
1070
+ endian :little
1071
+ uint32 :a
1072
+ array :b, type: :ndr_lp_str, read_until: -> { index == a - 1 }
1073
+ uint32 :c
1074
+ end.new
1075
+ end
1076
+
1077
+ context 'without null pointers' do
1078
+ let(:bin_str) do
1079
+ "\x03\x00\x00\x00" + # a
1080
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1081
+ "&_>=" + # b[1] referent_id
1082
+ "T\r%\x18" + # b[2] referent_id
1083
+ "7\x00\x00\x00" + # c
1084
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
1085
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # b[1]
1086
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
1087
+ end
1088
+
1089
+ it 'reads as expected' do
1090
+ struct.do_read(io)
1091
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1092
+ str2 = 'test2'.encode(Encoding::UTF_16LE)
1093
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1094
+ expect(struct.a).to eq(3)
1095
+ expect(struct.b).to eq([str1, str2, str3])
1096
+ expect(struct.b[0].referent_id).to eq(2635975080)
1097
+ expect(struct.b[0].referent).to eq(str1)
1098
+ expect(struct.b[1].referent_id).to eq(1027497766)
1099
+ expect(struct.b[1].referent).to eq(str2)
1100
+ expect(struct.b[2].referent_id).to eq(405081428)
1101
+ expect(struct.b[2].referent).to eq(str3)
1102
+ expect(struct.c).to eq(55)
1103
+ end
1104
+ end
1105
+
1106
+ context 'with null pointers' do
1107
+ let(:bin_str) do
1108
+ "\x03\x00\x00\x00" + # a
1109
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1110
+ "\x00\x00\x00\x00" + # b[1] referent_id (null)
1111
+ "T\r%\x18" + # b[2] referent_id
1112
+ "7\x00\x00\x00" + # c
1113
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
1114
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
1115
+ end
1116
+
1117
+ it 'reads as expected' do
1118
+ struct.do_read(io)
1119
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1120
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1121
+ expect(struct.a).to eq(3)
1122
+ expect(struct.b).to eq([str1, :null, str3])
1123
+ expect(struct.b[0].referent_id).to eq(2635975080)
1124
+ expect(struct.b[0].referent).to eq(str1)
1125
+ expect(struct.b[1].referent_id).to eq(0)
1126
+ expect(struct.b[2].referent_id).to eq(405081428)
1127
+ expect(struct.b[2].referent).to eq(str3)
1128
+ expect(struct.c).to eq(55)
1129
+ end
1130
+ end
1131
+
1132
+ context 'with null strings' do
1133
+ let(:bin_str) do
1134
+ "\x03\x00\x00\x00" + # a
1135
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1136
+ "&_>=" + # b[1] referent_id
1137
+ "T\r%\x18" + # b[2] referent_id
1138
+ "7\x00\x00\x00" + # c
1139
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b[0]
1140
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # b[1] null string
1141
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
1142
+ end
1143
+
1144
+ it 'reads as expected' do
1145
+ struct.do_read(io)
1146
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1147
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1148
+ expect(struct.a).to eq(3)
1149
+ expect(struct.b).to eq([str1, 0, str3])
1150
+ expect(struct.b[0].referent_id).to eq(2635975080)
1151
+ expect(struct.b[0].referent).to eq(str1)
1152
+ expect(struct.b[1].referent_id).to eq(1027497766)
1153
+ expect(struct.b[1].referent).to eq(0)
1154
+ expect(struct.b[2].referent_id).to eq(405081428)
1155
+ expect(struct.b[2].referent).to eq(str3)
1156
+ expect(struct.c).to eq(55)
1157
+ end
1158
+ end
1159
+
1160
+ context 'with padding' do
1161
+ let(:bin_str) do
1162
+ "\x03\x00\x00\x00" + # a
1163
+ "\xA8\xC9\x1D\x9D" + # b[0] referent_id
1164
+ "&_>=" + # b[1] referent_id
1165
+ "T\r%\x18" + # b[2] referent_id
1166
+ "7\x00\x00\x00" + # c
1167
+ "\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00" + # b[0]
1168
+ "\x00\x00" + # pad
1169
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # b[1]
1170
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # b[2]
1171
+ end
1172
+
1173
+ it 'reads as expected' do
1174
+ struct.do_read(io)
1175
+ str1 = 'test'.encode(Encoding::UTF_16LE)
1176
+ str2 = 'test2'.encode(Encoding::UTF_16LE)
1177
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1178
+ expect(struct.a).to eq(3)
1179
+ expect(struct.b).to eq([str1, str2, str3])
1180
+ expect(struct.b[0].referent_id).to eq(2635975080)
1181
+ expect(struct.b[0].referent).to eq(str1)
1182
+ expect(struct.b[1].referent_id).to eq(1027497766)
1183
+ expect(struct.b[1].referent).to eq(str2)
1184
+ expect(struct.b[2].referent_id).to eq(405081428)
1185
+ expect(struct.b[2].referent).to eq(str3)
1186
+ expect(struct.c).to eq(55)
1187
+ end
1188
+ end
1189
+ end
1190
+
1191
+ context 'with a structure containg an pointers to strings' do
1192
+ subject(:struct) do
1193
+ Class.new(described_class) do
1194
+ endian :little
1195
+ uint32 :a
1196
+ ndr_lp_str :b
1197
+ ndr_lp_str :c
1198
+ ndr_lp_str :d
1199
+ uint32 :e
1200
+ end.new
1201
+ end
1202
+
1203
+ context 'without null pointers' do
1204
+ let(:bin_str) do
1205
+ "\x03\x00\x00\x00" + # a
1206
+ "\xA8\xC9\x1D\x9D" + # b referent_id
1207
+ "&_>=" + # c referent_id
1208
+ "T\r%\x18" + # d referent_id
1209
+ "7\x00\x00\x00" + # c
1210
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
1211
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # c
1212
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
1213
+ end
1214
+
1215
+ it 'reads as expected' do
1216
+ struct.do_read(io)
1217
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1218
+ str2 = 'test2'.encode(Encoding::UTF_16LE)
1219
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1220
+ expect(struct.a).to eq(3)
1221
+ expect(struct.b).to eq(str1)
1222
+ expect(struct.c).to eq(str2)
1223
+ expect(struct.d).to eq(str3)
1224
+ expect(struct.b.referent_id).to eq(2635975080)
1225
+ expect(struct.b.referent).to eq(str1)
1226
+ expect(struct.c.referent_id).to eq(1027497766)
1227
+ expect(struct.c.referent).to eq(str2)
1228
+ expect(struct.d.referent_id).to eq(405081428)
1229
+ expect(struct.d.referent).to eq(str3)
1230
+ expect(struct.e).to eq(55)
1231
+ end
1232
+ end
1233
+
1234
+ context 'with null pointers' do
1235
+ let(:bin_str) do
1236
+ "\x03\x00\x00\x00" + # a
1237
+ "\xA8\xC9\x1D\x9D" + # b referent_id
1238
+ "\x00\x00\x00\x00" + # c referent_id (null)
1239
+ "T\r%\x18" + # d referent_id
1240
+ "7\x00\x00\x00" + # c
1241
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
1242
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
1243
+ end
1244
+
1245
+ it 'reads as expected' do
1246
+ struct.do_read(io)
1247
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1248
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1249
+ expect(struct.a).to eq(3)
1250
+ expect(struct.b).to eq(str1)
1251
+ expect(struct.c).to eq(:null)
1252
+ expect(struct.d).to eq(str3)
1253
+ expect(struct.b.referent_id).to eq(2635975080)
1254
+ expect(struct.b.referent).to eq(str1)
1255
+ expect(struct.c.referent_id).to eq(0)
1256
+ expect(struct.d.referent_id).to eq(405081428)
1257
+ expect(struct.d.referent).to eq(str3)
1258
+ expect(struct.e).to eq(55)
1259
+ end
1260
+ end
1261
+
1262
+ context 'with null strings' do
1263
+ let(:bin_str) do
1264
+ "\x03\x00\x00\x00" + # a
1265
+ "\xA8\xC9\x1D\x9D" + # b referent_id
1266
+ "&_>=" + # c referent_id
1267
+ "T\r%\x18" + # d referent_id
1268
+ "7\x00\x00\x00" + # c
1269
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00" + # b
1270
+ "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + # c null string
1271
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
1272
+ end
1273
+
1274
+ it 'reads as expected' do
1275
+ struct.do_read(io)
1276
+ str1 = 'test1'.encode(Encoding::UTF_16LE)
1277
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1278
+ expect(struct.a).to eq(3)
1279
+ expect(struct.b).to eq(str1)
1280
+ expect(struct.c).to eq(0)
1281
+ expect(struct.d).to eq(str3)
1282
+ expect(struct.b.referent_id).to eq(2635975080)
1283
+ expect(struct.b.referent).to eq(str1)
1284
+ expect(struct.c.referent_id).to eq(1027497766)
1285
+ expect(struct.c.referent).to eq(0)
1286
+ expect(struct.d.referent_id).to eq(405081428)
1287
+ expect(struct.d.referent).to eq(str3)
1288
+ expect(struct.e).to eq(55)
1289
+ end
1290
+ end
1291
+
1292
+ context 'with padding' do
1293
+ let(:bin_str) do
1294
+ "\x03\x00\x00\x00" + # a
1295
+ "\xA8\xC9\x1D\x9D" + # b referent_id
1296
+ "&_>=" + # c referent_id
1297
+ "T\r%\x18" + # d referent_id
1298
+ "7\x00\x00\x00" + # c
1299
+ "\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00" + # b
1300
+ "\x00\x00" + # pad
1301
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00" + # c
1302
+ "\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00" # d
1303
+ end
1304
+
1305
+ it 'reads as expected' do
1306
+ struct.do_read(io)
1307
+ str1 = 'test'.encode(Encoding::UTF_16LE)
1308
+ str2 = 'test2'.encode(Encoding::UTF_16LE)
1309
+ str3 = 'test3'.encode(Encoding::UTF_16LE)
1310
+ expect(struct.a).to eq(3)
1311
+ expect(struct.b).to eq(str1)
1312
+ expect(struct.c).to eq(str2)
1313
+ expect(struct.d).to eq(str3)
1314
+ expect(struct.b.referent_id).to eq(2635975080)
1315
+ expect(struct.b.referent).to eq(str1)
1316
+ expect(struct.c.referent_id).to eq(1027497766)
1317
+ expect(struct.c.referent).to eq(str2)
1318
+ expect(struct.d.referent_id).to eq(405081428)
1319
+ expect(struct.d.referent).to eq(str3)
1320
+ expect(struct.e).to eq(55)
1321
+ end
1322
+ end
1323
+ end
1324
+ end
1325
+
1326
+ describe '#do_write' do
1327
+ let(:raw_io) { BinData::IO.create_string_io }
1328
+ let(:io) { BinData::IO::Write.new(raw_io) }
1329
+ context 'with a structure containg an array of pointers to integer' do
1330
+ subject(:struct) do
1331
+ Class.new(described_class) do
1332
+ endian :little
1333
+ uint32 :a
1334
+ array :b, type: :ndr_lp_dword, read_until: -> { index == a - 1 }
1335
+ uint32 :c
1336
+ end.new
1337
+ end
1338
+
1339
+ context 'without null pointers' do
1340
+ let(:packet) do
1341
+ struct.new(a: 3, b: [1, 2, 3], c: 55)
1342
+ end
1343
+
1344
+ it 'writes as expected' do
1345
+ packet.do_write(io)
1346
+ raw_io.rewind
1347
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1348
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1349
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
1350
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1351
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1352
+ expect(raw_io.read(4)).to eq("\x01\x00\x00\x00".b) # b[0]
1353
+ expect(raw_io.read(4)).to eq("\x02\x00\x00\x00".b) # b[1]
1354
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # b[2]
1355
+ expect(raw_io.eof).to be true
1356
+ end
1357
+ end
1358
+
1359
+ context 'with null pointers' do
1360
+ let(:packet) do
1361
+ struct.new(a: 3, b: [1, :null, 3], c: 55)
1362
+ end
1363
+
1364
+ it 'writes as expected' do
1365
+ packet.do_write(io)
1366
+ raw_io.rewind
1367
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1368
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1369
+ expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # b[1] referent_id (null)
1370
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1371
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1372
+ expect(raw_io.read(4)).to eq("\x01\x00\x00\x00".b) # b[0]
1373
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # b[2]
1374
+ expect(raw_io.eof).to be true
1375
+ end
1376
+ end
1377
+ end
1378
+
1379
+ context 'with a structure containg an array of pointers to strings' do
1380
+ subject(:struct) do
1381
+ Class.new(described_class) do
1382
+ endian :little
1383
+ uint32 :a
1384
+ array :b, type: :ndr_lp_str, read_until: -> { index == a - 1 }
1385
+ uint32 :c
1386
+ end.new
1387
+ end
1388
+
1389
+ context 'without null pointers' do
1390
+ let(:packet) do
1391
+ struct.new(a: 3, b: ['test1', 'test2', 'test3'], c: 55)
1392
+ end
1393
+
1394
+ it 'writes as expected' do
1395
+ packet.do_write(io)
1396
+ raw_io.rewind
1397
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1398
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1399
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
1400
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1401
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1402
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
1403
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00".b) # b[1]
1404
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
1405
+ expect(raw_io.eof).to be true
1406
+ end
1407
+ end
1408
+
1409
+ context 'with null pointers' do
1410
+ let(:packet) do
1411
+ struct.new(a: 3, b: ['test1', :null, 'test3'], c: 55)
1412
+ end
1413
+
1414
+ it 'writes as expected' do
1415
+ packet.do_write(io)
1416
+ raw_io.rewind
1417
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1418
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1419
+ expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # b[1] referent_id (null)
1420
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1421
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1422
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
1423
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
1424
+ expect(raw_io.eof).to be true
1425
+ end
1426
+ end
1427
+
1428
+ context 'with null strings' do
1429
+ let(:packet) do
1430
+ struct.new(a: 3, b: ['test1', 0, 'test3'], c: 55)
1431
+ end
1432
+
1433
+ it 'writes as expected' do
1434
+ packet.do_write(io)
1435
+ raw_io.rewind
1436
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1437
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1438
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
1439
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1440
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1441
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
1442
+ expect(raw_io.read(12)).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".b) # b[1] null string
1443
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
1444
+ expect(raw_io.eof).to be true
1445
+ end
1446
+ end
1447
+
1448
+ context 'with padding' do
1449
+ let(:packet) do
1450
+ struct.new(a: 3, b: ['test1', 'test', 'test3'], c: 55)
1451
+ end
1452
+
1453
+ it 'writes as expected' do
1454
+ packet.do_write(io)
1455
+ raw_io.rewind
1456
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1457
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[0] referent_id (random but not null)
1458
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[1] referent_id (random but not null)
1459
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b[2] referent_id (random but not null)
1460
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # c
1461
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b[0]
1462
+ expect(raw_io.read(22)).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00".b) # b[1]
1463
+ expect(raw_io.read(2)).to eq("\x00\x00".b) # pad
1464
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # b[2]
1465
+ expect(raw_io.eof).to be true
1466
+ end
1467
+ end
1468
+ end
1469
+
1470
+ context 'with a structure containg pointers to strings' do
1471
+ subject(:struct) do
1472
+ Class.new(described_class) do
1473
+ endian :little
1474
+ uint32 :a
1475
+ ndr_lp_str :b
1476
+ ndr_lp_str :c
1477
+ ndr_lp_str :d
1478
+ uint32 :e
1479
+ end.new
1480
+ end
1481
+
1482
+ context 'without null pointers' do
1483
+ let(:packet) do
1484
+ struct.new(a: 3, b: 'test1', c: 'test2', d: 'test3', e: 55)
1485
+ end
1486
+
1487
+ it 'writes as expected' do
1488
+ packet.do_write(io)
1489
+ raw_io.rewind
1490
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1491
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
1492
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
1493
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
1494
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
1495
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
1496
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x002\x00\x00\x00".b) # c
1497
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
1498
+ expect(raw_io.eof).to be true
1499
+ end
1500
+ end
1501
+
1502
+ context 'with null pointers' do
1503
+ let(:packet) do
1504
+ struct.new(a: 3, b: 'test1', c: :null, d: 'test3', e: 55)
1505
+ end
1506
+
1507
+ it 'writes as expected' do
1508
+ packet.do_write(io)
1509
+ raw_io.rewind
1510
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1511
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
1512
+ expect(raw_io.read(4)).to eq("\x00\x00\x00\x00".b) # c referent_id (null)
1513
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
1514
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
1515
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
1516
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
1517
+ expect(raw_io.eof).to be true
1518
+ end
1519
+ end
1520
+
1521
+ context 'with null strings' do
1522
+ let(:packet) do
1523
+ struct.new(a: 3, b: 'test1', c: 0, d: 'test3', e: 55)
1524
+ end
1525
+
1526
+ it 'writes as expected' do
1527
+ packet.do_write(io)
1528
+ raw_io.rewind
1529
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1530
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
1531
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
1532
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
1533
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
1534
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
1535
+ expect(raw_io.read(12)).to eq("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00".b) # c
1536
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
1537
+ expect(raw_io.eof).to be true
1538
+ end
1539
+ end
1540
+
1541
+ context 'with padding' do
1542
+ let(:packet) do
1543
+ struct.new(a: 3, b: 'test1', c: 'test', d: 'test3', e: 55)
1544
+ end
1545
+
1546
+ it 'writes as expected' do
1547
+ packet.do_write(io)
1548
+ raw_io.rewind
1549
+ expect(raw_io.read(4)).to eq("\x03\x00\x00\x00".b) # a
1550
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # b referent_id (random but not null)
1551
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # c referent_id (random but not null)
1552
+ expect(raw_io.read(4)).to_not eq("\x00\x00\x00\x00".b) # d referent_id (random but not null)
1553
+ expect(raw_io.read(4)).to eq("7\x00\x00\x00".b) # e
1554
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x001\x00\x00\x00".b) # b
1555
+ expect(raw_io.read(22)).to eq("\x05\x00\x00\x00\x00\x00\x00\x00\x05\x00\x00\x00t\x00e\x00s\x00t\x00\x00\x00".b) # c
1556
+ expect(raw_io.read(2)).to eq("\x00\x00".b) # pad
1557
+ expect(raw_io.read(24)).to eq("\x06\x00\x00\x00\x00\x00\x00\x00\x06\x00\x00\x00t\x00e\x00s\x00t\x003\x00\x00\x00".b) # d
1558
+ expect(raw_io.eof).to be true
1559
+ end
1560
+ end
1561
+ end
1562
+ end
1563
+ end
1564
+
1565
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrStringPtrsw do
1566
+ subject(:packet) { described_class.new }
1567
+
1568
+ it { is_expected.to respond_to :max_count }
1569
+ it { is_expected.to respond_to :elements }
1570
+
1571
+ it 'is little endian' do
1572
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
1573
+ end
1574
+
1575
+ describe '#max_count' do
1576
+ it 'is a 32-bit unsigned integer' do
1577
+ expect(packet.max_count).to be_a BinData::Uint32le
1578
+ end
1579
+
1580
+ it 'has an initial value equal to #elements size' do
1581
+ packet.elements = ['A', 'B', 'C']
1582
+ expect(packet.max_count).to eq(3)
1583
+ end
1584
+ end
1585
+
1586
+ describe '#elements' do
1587
+ it 'is a Bindata::Array' do
1588
+ expect(packet.elements).to be_a BinData::Array
1589
+ end
1590
+
1591
+ it 'is an array of NdrLpStr' do
1592
+ expect(packet.elements[0]).to be_a RubySMB::Dcerpc::Ndr::NdrLpStr
1593
+ end
1594
+
1595
+ it 'exists if #max_count is greater than 0' do
1596
+ packet.max_count = 2
1597
+ expect(packet.elements?).to be true
1598
+ end
1599
+
1600
+ it 'does not exist if #max_count is 0' do
1601
+ packet.max_count = 0
1602
+ expect(packet.elements?).to be false
1603
+ end
1604
+ end
1605
+
1606
+ describe '#get' do
1607
+ it 'returns elements' do
1608
+ packet.elements = ['1', '2', '3']
1609
+ expect(packet.get).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
1610
+ end
1611
+ end
1612
+
1613
+ describe '#set' do
1614
+ it 'sets #elements as expected' do
1615
+ packet.set(['1', '2', '3'])
1616
+ expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
1617
+ end
1618
+
1619
+ it 'sets #max_count to the number of elements set' do
1620
+ packet.set(['1', '2', '3'])
1621
+ expect(packet.max_count).to eq(3)
1622
+ end
1623
+
1624
+ it 'calls #to_ary before setting the elements' do
1625
+ ary = BinData::Array.new(['1','2', '3'], type: :ndr_lp_str)
1626
+ expect(ary).to receive(:to_ary).and_call_original
1627
+ packet.set(ary)
1628
+ expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
1629
+ end
1630
+
1631
+ it 'keeps custom #max_count value when called from #to_binary_s' do
1632
+ packet.set(['1', '2', '3', '4', '5'])
1633
+ packet.max_count = 3
1634
+ packet.to_binary_s
1635
+ expect(packet.max_count).to eq(3)
1636
+ end
1637
+
1638
+ it 'keeps custom #max_count and #offset values when called from #do_num_bytes' do
1639
+ packet.set(['1', '2', '3', '4', '5'])
1640
+ packet.max_count = 3
1641
+ packet.do_num_bytes
1642
+ expect(packet.max_count).to eq(3)
1643
+ end
1644
+
1645
+ it 'sets #max_count to the number of elements set after setting custom #max_count value' do
1646
+ packet.set(['1', '2', '3', '4', '5'])
1647
+ packet.max_count = 3
1648
+ packet.set(['1', '2', '3', '4', '5'])
1649
+ expect(packet.max_count).to eq(5)
1650
+ end
1651
+ end
1652
+
1653
+ describe '#read' do
1654
+ context 'with a no elements' do
1655
+ it 'reads its own binary representation' do
1656
+ raw = packet.to_binary_s
1657
+ expect(described_class.read(raw)).to eq(packet)
1658
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
1659
+ end
1660
+ end
1661
+
1662
+ context 'with some elements' do
1663
+ it 'reads its own binary representation' do
1664
+ packet.set(['1', '2', '3'])
1665
+ raw = packet.to_binary_s
1666
+ expect(described_class.read(raw)).to eq(packet)
1667
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
1668
+ end
1669
+ end
1670
+ end
1671
+ end
1672
+
1673
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStringPtrsw do
1674
+ it 'is NdrPointer subclass' do
1675
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrPointer
1676
+ end
1677
+
1678
+ subject(:packet) { described_class.new }
1679
+
1680
+ it { is_expected.to respond_to :referent }
1681
+
1682
+ it 'is little endian' do
1683
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
1684
+ end
1685
+
1686
+ describe '#referent' do
1687
+ it 'is a NdrStringPtrsw structure' do
1688
+ expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrStringPtrsw
1689
+ end
1690
+
1691
+ it 'exists if superclass #referent_id is not zero' do
1692
+ packet.referent_id = 0xCCCC
1693
+ expect(packet.referent?).to be true
1694
+ end
1695
+
1696
+ it 'does not exist if superclass #referent_id is zero' do
1697
+ packet.referent_id = 0
1698
+ expect(packet.referent?).to be false
1699
+ end
1700
+ end
1701
+
1702
+ describe '#set' do
1703
+ it 'calls #to_ary before setting the elements, if supported' do
1704
+ ary = BinData::Array.new(['1', '2', '3'], type: :ndr_lp_str)
1705
+ expect(ary).to receive(:to_ary).and_call_original
1706
+ packet.set(ary)
1707
+ expect(packet.elements).to eq(['1', '2', '3'].map {|e| e.encode(Encoding::UTF_16LE)})
1708
+ end
1709
+ end
1710
+
1711
+ describe '#read' do
1712
+ context 'with a null pointer' do
1713
+ it 'reads its own binary representation' do
1714
+ raw = packet.to_binary_s
1715
+ expect(described_class.read(raw)).to eq(packet)
1716
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
1717
+ end
1718
+ end
1719
+
1720
+ context 'with a normal NdrStringPtrsw structure' do
1721
+ it 'reads its own binary representation' do
1722
+ packet.set(['1', '2', '3'])
1723
+ raw = packet.to_binary_s
1724
+ expect(described_class.read(raw)).to eq(packet)
1725
+ expect(described_class.read(raw).to_binary_s).to eq(raw)
1726
+ end
1727
+ end
1728
+ end
1729
+ end