ruby_smb 1.0.4 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) 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/enum_registry_key.rb +28 -0
  8. data/examples/enum_registry_values.rb +30 -0
  9. data/examples/negotiate.rb +51 -8
  10. data/examples/pipes.rb +2 -1
  11. data/examples/read_file_encryption.rb +56 -0
  12. data/examples/read_registry_key_value.rb +32 -0
  13. data/lib/ruby_smb.rb +4 -1
  14. data/lib/ruby_smb/client.rb +207 -18
  15. data/lib/ruby_smb/client/authentication.rb +27 -8
  16. data/lib/ruby_smb/client/encryption.rb +62 -0
  17. data/lib/ruby_smb/client/negotiation.rb +153 -12
  18. data/lib/ruby_smb/client/signing.rb +19 -0
  19. data/lib/ruby_smb/client/tree_connect.rb +4 -4
  20. data/lib/ruby_smb/client/utils.rb +8 -7
  21. data/lib/ruby_smb/client/winreg.rb +46 -0
  22. data/lib/ruby_smb/crypto.rb +30 -0
  23. data/lib/ruby_smb/dcerpc.rb +38 -0
  24. data/lib/ruby_smb/dcerpc/bind.rb +2 -2
  25. data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
  26. data/lib/ruby_smb/dcerpc/error.rb +3 -0
  27. data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
  28. data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
  29. data/lib/ruby_smb/dcerpc/request.rb +28 -9
  30. data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
  31. data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
  32. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
  33. data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
  34. data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
  35. data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
  36. data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
  37. data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
  38. data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
  39. data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
  40. data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
  41. data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
  42. data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
  43. data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
  44. data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
  45. data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
  46. data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
  47. data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
  48. data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
  49. data/lib/ruby_smb/dispatcher/socket.rb +4 -3
  50. data/lib/ruby_smb/error.rb +28 -1
  51. data/lib/ruby_smb/smb1/commands.rb +1 -1
  52. data/lib/ruby_smb/smb1/file.rb +6 -4
  53. data/lib/ruby_smb/smb1/packet/empty_packet.rb +4 -2
  54. data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
  55. data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
  56. data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
  57. data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
  58. data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
  59. data/lib/ruby_smb/smb1/pipe.rb +79 -3
  60. data/lib/ruby_smb/smb1/tree.rb +12 -3
  61. data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
  62. data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
  63. data/lib/ruby_smb/smb2/file.rb +25 -43
  64. data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
  65. data/lib/ruby_smb/smb2/packet.rb +2 -0
  66. data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
  67. data/lib/ruby_smb/smb2/packet/error_packet.rb +9 -4
  68. data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
  69. data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
  70. data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
  71. data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
  72. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
  73. data/lib/ruby_smb/smb2/pipe.rb +77 -3
  74. data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
  75. data/lib/ruby_smb/smb2/tree.rb +23 -17
  76. data/lib/ruby_smb/version.rb +1 -1
  77. data/ruby_smb.gemspec +5 -3
  78. data/spec/lib/ruby_smb/client_spec.rb +1441 -61
  79. data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
  80. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
  81. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
  82. data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
  83. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
  84. data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
  85. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
  86. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
  87. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
  88. data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
  89. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
  90. data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
  91. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
  92. data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
  93. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
  94. data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
  95. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
  96. data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
  97. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
  98. data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
  99. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
  100. data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
  101. data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
  102. data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
  103. data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
  104. data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +2 -2
  105. data/spec/lib/ruby_smb/error_spec.rb +59 -0
  106. data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
  107. data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +10 -0
  108. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
  109. data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
  110. data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
  111. data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
  112. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +210 -148
  113. data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
  114. data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
  115. data/spec/lib/ruby_smb/smb2/file_spec.rb +86 -62
  116. data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
  117. data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
  118. data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +29 -2
  119. data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
  120. data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
  121. data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
  122. data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
  123. data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
  124. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +220 -149
  125. data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
  126. data/spec/lib/ruby_smb/smb2/tree_spec.rb +53 -8
  127. metadata +187 -81
  128. metadata.gz.sig +0 -0
  129. data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
  130. 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,410 @@
1
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer 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_identifier }
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_identifier' do
16
+ it 'is a 32-bit unsigned integer' do
17
+ expect(packet.referent_identifier).to be_a BinData::Uint32le
18
+ end
19
+
20
+ it 'has an initial value of 0x00020000' do
21
+ expect(packet.referent_identifier).to eq(0x00020000)
22
+ end
23
+ end
24
+
25
+ describe '#get' do
26
+ it 'returns 0 when #referent_identifier is 0' do
27
+ packet.referent_identifier = 0
28
+ expect(packet.get).to eq(0)
29
+ end
30
+
31
+ it 'returns #referent when #referent_identifier is greater than 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 0' do
39
+ it 'sets #referent_identifier to 0' do
40
+ packet.set(0)
41
+ expect(packet.referent_identifier).to eq(0)
42
+ end
43
+ end
44
+
45
+ context 'when the value is a string' do
46
+ it 'sets #referent to the value' do
47
+ str = 'spec_test'
48
+ packet.set(str)
49
+ expect(packet.referent).to eq(str)
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrString do
56
+ subject(:packet) { described_class.new }
57
+
58
+ it { is_expected.to respond_to :max_count }
59
+ it { is_expected.to respond_to :offset }
60
+ it { is_expected.to respond_to :actual_count }
61
+ it { is_expected.to respond_to :str }
62
+
63
+ it 'is little endian' do
64
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
65
+ end
66
+
67
+ describe '#max_count' do
68
+ it 'is a 32-bit unsigned integer' do
69
+ expect(packet.max_count).to be_a BinData::Uint32le
70
+ end
71
+ end
72
+
73
+ describe '#offset' do
74
+ it 'is a 32-bit unsigned integer' do
75
+ expect(packet.offset).to be_a BinData::Uint32le
76
+ end
77
+
78
+ it 'has an initial valu of 0' do
79
+ expect(packet.offset).to eq(0)
80
+ end
81
+ end
82
+
83
+ describe '#actual_count' do
84
+ it 'is a 32-bit unsigned integer' do
85
+ expect(packet.actual_count).to be_a BinData::Uint32le
86
+ end
87
+ end
88
+
89
+ describe '#str' do
90
+ it 'is a RubySMB::Field::Stringz16' do
91
+ expect(packet.str).to be_a RubySMB::Field::Stringz16
92
+ end
93
+
94
+ it 'exists if #actual_count is greater than 0' do
95
+ packet.actual_count = 4
96
+ expect(packet.str?).to be true
97
+ end
98
+
99
+ it 'does not exist if #actual_count is 0' do
100
+ expect(packet.str?).to be false
101
+ end
102
+ end
103
+
104
+ describe '#get' do
105
+ it 'returns 0 when #actual_count is 0' do
106
+ expect(packet.get).to eq(0)
107
+ end
108
+
109
+ it 'returns #str when #actual_count is greater than 0' do
110
+ str = 'spec_test'
111
+ strz16 = RubySMB::Field::Stringz16.new(str)
112
+ packet.set(str)
113
+ expect(packet.get).to eq(strz16)
114
+ end
115
+ end
116
+
117
+ describe '#set' do
118
+ context 'when the value is 0' do
119
+ it 'sets #actual_count to 0' do
120
+ packet.set(0)
121
+ expect(packet.actual_count).to eq(0)
122
+ end
123
+ end
124
+
125
+ context 'when the value is a string' do
126
+ let(:str) { 'spec_test' }
127
+
128
+ it 'sets #str to the value' do
129
+ packet.set(str)
130
+ strz16 = RubySMB::Field::Stringz16.new(str)
131
+ expect(packet.str).to eq(strz16)
132
+ end
133
+
134
+ it 'sets #max_count and #actual_count to the expected value' do
135
+ packet.set(str)
136
+ expect(packet.max_count).to eq(str.length + 1)
137
+ expect(packet.actual_count).to eq(str.length + 1)
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpStr do
144
+ it 'is NdrTopLevelFullPointer subclass' do
145
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer
146
+ end
147
+
148
+ subject(:packet) { described_class.new }
149
+
150
+ it { is_expected.to respond_to :referent }
151
+
152
+ it 'is little endian' do
153
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
154
+ end
155
+
156
+ describe '#referent' do
157
+ it 'is a NdrString' do
158
+ expect(packet.referent).to be_a RubySMB::Dcerpc::Ndr::NdrString
159
+ end
160
+
161
+ it 'exists if superclass #referent_identifier is not zero' do
162
+ expect(packet.referent?).to be true
163
+ end
164
+
165
+ it 'does not exist if superclass #referent_identifier is zero' do
166
+ packet.referent_identifier = 0
167
+ expect(packet.referent?).to be false
168
+ end
169
+ end
170
+
171
+ describe '#to_s' do
172
+ it 'returns "\0" when #referent_identifier is 0' do
173
+ packet.referent_identifier = 0
174
+ expect(packet.to_s).to eq("\0")
175
+ end
176
+
177
+ it 'returns #referent when #referent_identifier is greater than 0' do
178
+ packet.set('spec_test')
179
+ expect(packet.to_s).to eq(packet.referent)
180
+ end
181
+ end
182
+ end
183
+
184
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrContextHandle do
185
+ let(:uuid) { 'c3bce70d-5155-472b-9f2f-b824e5fc9b60' }
186
+ let(:attr) { 123 }
187
+ subject(:packet) { described_class.new }
188
+
189
+ it { is_expected.to respond_to :context_handle_attributes }
190
+ it { is_expected.to respond_to :context_handle_uuid }
191
+
192
+ it 'is little endian' do
193
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
194
+ end
195
+
196
+ describe '#context_handle_attributes' do
197
+ it 'is a 32-bit unsigned integer' do
198
+ expect(packet.context_handle_attributes).to be_a BinData::Uint32le
199
+ end
200
+ end
201
+
202
+ describe '#context_handle_uuid' do
203
+ it 'is a UUID' do
204
+ expect(packet.context_handle_uuid).to be_a RubySMB::Dcerpc::Uuid
205
+ end
206
+ end
207
+
208
+ describe '#get' do
209
+ it 'returns the expeted hash' do
210
+ packet.context_handle_attributes = attr
211
+ packet.context_handle_uuid = uuid
212
+ expect(packet.get).to eq({context_handle_attributes: attr, context_handle_uuid: uuid})
213
+ end
214
+ end
215
+
216
+ describe '#set' do
217
+ let(:handle) { {context_handle_attributes: attr, context_handle_uuid: uuid} }
218
+
219
+ context 'when the value is a hash' do
220
+ it 'sets #context_handle_attributes and #context_handle_uuid to the expected values' do
221
+ packet.set(handle)
222
+ expect(packet.context_handle_attributes).to eq(attr)
223
+ expect(packet.context_handle_uuid).to eq(uuid)
224
+ end
225
+ end
226
+
227
+ context 'when the value is a NdrContextHandle'do
228
+ it 'reads the value binary representaion ' do
229
+ ndr_context_handle = described_class.new(handle)
230
+ allow(ndr_context_handle).to receive(:to_binary_s).and_call_original
231
+ packet.set(ndr_context_handle)
232
+ expect(ndr_context_handle).to have_received(:to_binary_s)
233
+ expect(packet.get).to eq(ndr_context_handle)
234
+ end
235
+ end
236
+
237
+ context 'when the value is a binary string'do
238
+ it 'reads the value' do
239
+ ndr_context_handle = described_class.new(handle)
240
+ packet.set(ndr_context_handle.to_binary_s)
241
+ expect(packet.get).to eq(ndr_context_handle)
242
+ end
243
+ end
244
+ end
245
+ end
246
+
247
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpDword do
248
+ it 'is NdrTopLevelFullPointer subclass' do
249
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer
250
+ end
251
+
252
+ subject(:packet) { described_class.new }
253
+
254
+ it { is_expected.to respond_to :referent }
255
+
256
+ it 'is little endian' do
257
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
258
+ end
259
+
260
+ describe '#referent' do
261
+ it 'is a 32-bit unsigned integer' do
262
+ expect(packet.referent).to be_a BinData::Uint32le
263
+ end
264
+
265
+ it 'exists if superclass #referent_identifier is not zero' do
266
+ expect(packet.referent?).to be true
267
+ end
268
+
269
+ it 'does not exist if superclass #referent_identifier is zero' do
270
+ packet.referent_identifier = 0
271
+ expect(packet.referent?).to be false
272
+ end
273
+ end
274
+ end
275
+
276
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpByte do
277
+ subject(:packet) { described_class.new }
278
+
279
+ it { is_expected.to respond_to :referent_identifier }
280
+ it { is_expected.to respond_to :max_count }
281
+ it { is_expected.to respond_to :offset }
282
+ it { is_expected.to respond_to :actual_count }
283
+ it { is_expected.to respond_to :bytes }
284
+
285
+ it 'is little endian' do
286
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
287
+ end
288
+
289
+ describe '#referent_identifier' do
290
+ it 'is a 32-bit unsigned integer' do
291
+ expect(packet.referent_identifier).to be_a BinData::Uint32le
292
+ end
293
+
294
+ it 'has an initial value of 0x00020000' do
295
+ expect(packet.referent_identifier).to eq(0x00020000)
296
+ end
297
+ end
298
+
299
+ describe '#max_count' do
300
+ it 'is a 32-bit unsigned integer' do
301
+ expect(packet.max_count).to be_a BinData::Uint32le
302
+ end
303
+
304
+ it 'has an initial value equal to #actual_count' do
305
+ packet.actual_count = 345
306
+ expect(packet.max_count).to eq(345)
307
+ end
308
+
309
+ it 'exists if #referent_identifier is not zero' do
310
+ expect(packet.max_count?).to be true
311
+ end
312
+
313
+ it 'does not exist if #referent_identifier is zero' do
314
+ packet.referent_identifier = 0
315
+ expect(packet.max_count?).to be false
316
+ end
317
+ end
318
+
319
+ describe '#offset' do
320
+ it 'is a 32-bit unsigned integer' do
321
+ expect(packet.offset).to be_a BinData::Uint32le
322
+ end
323
+
324
+ it 'has an initial value of 0' do
325
+ expect(packet.offset).to eq(0)
326
+ end
327
+
328
+ it 'exists if #referent_identifier is not zero' do
329
+ expect(packet.offset?).to be true
330
+ end
331
+
332
+ it 'does not exist if #referent_identifier is zero' do
333
+ packet.referent_identifier = 0
334
+ expect(packet.offset?).to be false
335
+ end
336
+ end
337
+
338
+ describe '#actual_count' do
339
+ it 'is a 32-bit unsigned integer' do
340
+ expect(packet.actual_count).to be_a BinData::Uint32le
341
+ end
342
+
343
+ it 'has an initial value equal to #bytes size' do
344
+ packet.bytes << 2 << 3 << 4 << 5
345
+ expect(packet.actual_count).to eq(4)
346
+ end
347
+
348
+ it 'exists if #referent_identifier is not zero' do
349
+ expect(packet.actual_count?).to be true
350
+ end
351
+
352
+ it 'does not exist if #referent_identifier is zero' do
353
+ packet.referent_identifier = 0
354
+ expect(packet.actual_count?).to be false
355
+ end
356
+ end
357
+
358
+ describe '#bytes' do
359
+ it 'is a Bindata::Array' do
360
+ expect(packet.bytes).to be_a BinData::Array
361
+ end
362
+
363
+ it 'has an initial length equal to #actual_count' do
364
+ packet.actual_count = 3
365
+ expect(packet.bytes.size).to eq(3)
366
+ end
367
+
368
+ it 'is 8-bit unsigned integer elements' do
369
+ expect(packet.bytes[0]).to be_a BinData::Uint8
370
+ end
371
+
372
+ it 'exists if #referent_identifier is not zero' do
373
+ expect(packet.bytes?).to be true
374
+ end
375
+
376
+ it 'does not exist if #referent_identifier is zero' do
377
+ packet.referent_identifier = 0
378
+ expect(packet.bytes?).to be false
379
+ end
380
+ end
381
+ end
382
+
383
+ RSpec.describe RubySMB::Dcerpc::Ndr::NdrLpFileTime do
384
+ it 'is NdrTopLevelFullPointer subclass' do
385
+ expect(described_class).to be < RubySMB::Dcerpc::Ndr::NdrTopLevelFullPointer
386
+ end
387
+
388
+ subject(:packet) { described_class.new }
389
+
390
+ it { is_expected.to respond_to :referent }
391
+
392
+ it 'is little endian' do
393
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
394
+ end
395
+
396
+ describe '#referent' do
397
+ it 'is a FileTime' do
398
+ expect(packet.referent).to be_a RubySMB::Field::FileTime
399
+ end
400
+
401
+ it 'exists if superclass #referent_identifier is not zero' do
402
+ expect(packet.referent?).to be true
403
+ end
404
+
405
+ it 'does not exist if superclass #referent_identifier is zero' do
406
+ packet.referent_identifier = 0
407
+ expect(packet.referent?).to be false
408
+ end
409
+ end
410
+ end