ruby_smb 1.0.4 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/.travis.yml +3 -2
- data/Gemfile +6 -2
- data/README.md +35 -47
- data/examples/enum_registry_key.rb +28 -0
- data/examples/enum_registry_values.rb +30 -0
- data/examples/negotiate.rb +51 -8
- data/examples/pipes.rb +2 -1
- data/examples/read_file_encryption.rb +56 -0
- data/examples/read_registry_key_value.rb +32 -0
- data/lib/ruby_smb.rb +4 -1
- data/lib/ruby_smb/client.rb +207 -18
- data/lib/ruby_smb/client/authentication.rb +27 -8
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +153 -12
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +4 -4
- data/lib/ruby_smb/client/utils.rb +8 -7
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/crypto.rb +30 -0
- data/lib/ruby_smb/dcerpc.rb +38 -0
- data/lib/ruby_smb/dcerpc/bind.rb +2 -2
- data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +28 -9
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
- data/lib/ruby_smb/dispatcher/socket.rb +4 -3
- data/lib/ruby_smb/error.rb +28 -1
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +6 -4
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +4 -2
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -2
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +1 -1
- data/lib/ruby_smb/smb1/pipe.rb +79 -3
- data/lib/ruby_smb/smb1/tree.rb +12 -3
- data/lib/ruby_smb/smb2/bit_field/session_flags.rb +2 -1
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +6 -4
- data/lib/ruby_smb/smb2/file.rb +25 -43
- data/lib/ruby_smb/smb2/negotiate_context.rb +108 -0
- data/lib/ruby_smb/smb2/packet.rb +2 -0
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/error_packet.rb +9 -4
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -14
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +50 -4
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +92 -6
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -26
- data/lib/ruby_smb/smb2/pipe.rb +77 -3
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +23 -17
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1441 -61
- data/spec/lib/ruby_smb/crypto_spec.rb +25 -0
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +2 -2
- data/spec/lib/ruby_smb/error_spec.rb +59 -0
- data/spec/lib/ruby_smb/smb1/file_spec.rb +9 -1
- data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +10 -0
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_legacy_response_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_request_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb1/packet/session_setup_response_spec.rb +1 -1
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +210 -148
- data/spec/lib/ruby_smb/smb2/bit_field/session_flags_spec.rb +9 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +27 -0
- data/spec/lib/ruby_smb/smb2/file_spec.rb +86 -62
- data/spec/lib/ruby_smb/smb2/negotiate_context_spec.rb +332 -0
- data/spec/lib/ruby_smb/smb2/packet/compression_transform_header_spec.rb +108 -0
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +29 -2
- data/spec/lib/ruby_smb/smb2/packet/negotiate_request_spec.rb +138 -3
- data/spec/lib/ruby_smb/smb2/packet/negotiate_response_spec.rb +120 -2
- data/spec/lib/ruby_smb/smb2/packet/transform_header_spec.rb +220 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +339 -9
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +3 -30
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +220 -149
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +53 -8
- metadata +187 -81
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -72
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -75
@@ -0,0 +1,220 @@
|
|
1
|
+
RSpec.describe RubySMB::SMB2::Packet::TransformHeader do
|
2
|
+
subject(:packet) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :protocol }
|
5
|
+
it { is_expected.to respond_to :signature }
|
6
|
+
it { is_expected.to respond_to :nonce }
|
7
|
+
it { is_expected.to respond_to :original_message_size }
|
8
|
+
it { is_expected.to respond_to :flags }
|
9
|
+
it { is_expected.to respond_to :session_id }
|
10
|
+
it { is_expected.to respond_to :encrypted_data }
|
11
|
+
|
12
|
+
it 'is little endian' do
|
13
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#protocol' do
|
17
|
+
it 'is a 32-bit field' do
|
18
|
+
expect(packet.protocol).to be_a BinData::Bit32
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'has an initial value of 0xFD534D42' do
|
22
|
+
expect(packet.protocol).to eq(0xFD534D42)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#signature' do
|
27
|
+
it 'is a String' do
|
28
|
+
expect(packet.signature).to be_a BinData::String
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#nonce' do
|
33
|
+
it 'is a String' do
|
34
|
+
expect(packet.nonce).to be_a BinData::String
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#original_message_size ' do
|
39
|
+
it 'is a 32-bit unsigned integer' do
|
40
|
+
expect(packet.original_message_size).to be_a BinData::Uint32le
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#flags' do
|
45
|
+
it 'is a 16-bit unsigned integer' do
|
46
|
+
expect(packet.flags).to be_a BinData::Uint16le
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#session_id' do
|
51
|
+
it 'is a 64-bit unsigned integer' do
|
52
|
+
expect(packet.session_id).to be_a BinData::Uint64le
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#encrypted_data' do
|
57
|
+
it 'is an Array' do
|
58
|
+
expect(packet.encrypted_data).to be_a BinData::Array
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#decrypt' do
|
63
|
+
let(:key) { "\x56\x89\xd1\xbb\xf7\x45\xc0\xb6\x68\x81\x07\xe4\x7d\x35\xaf\xd3".b }
|
64
|
+
let(:data) { 'data'.b }
|
65
|
+
before :example do
|
66
|
+
packet.original_message_size = data.length
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'raises the expected exception if the given algorithm is invalid' do
|
70
|
+
expect { packet.decrypt(key, algorithm: 'RC4') }.to raise_error(
|
71
|
+
RubySMB::Error::EncryptionError,
|
72
|
+
'Error while decrypting with \'RC4\' (ArgumentError: Invalid algorithm, must be either AES-128-CCM or AES-128-GCM)'
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'with AES-128-GCM algorithm (default)' do
|
77
|
+
before :example do
|
78
|
+
begin
|
79
|
+
OpenSSL::Cipher.new('AES-128-GCM')
|
80
|
+
rescue
|
81
|
+
skip(
|
82
|
+
"This test cannot be run since the version of OpenSSL the ruby "\
|
83
|
+
"OpenSSL extension was built with (#{OpenSSL::OPENSSL_VERSION}) "\
|
84
|
+
"does not support AES-128-GCM cipher")
|
85
|
+
end
|
86
|
+
packet.encrypted_data = "\x06\x45\x16\x36".bytes
|
87
|
+
packet.signature = "\x63\xb2\xf9\xe0\xb7\x43\xdb\xaf\x26\x8e\xd7\x42\xd3\xb2\xde\x0d"
|
88
|
+
packet.nonce = "\xe1\xb0\xa7\x20\xd9\xd9\x69\x3c\x79\xd0\x9c\x53\x00\x00\x00\x00"
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'generates a cipher using OpenSSL::Cipher' do
|
92
|
+
expect(OpenSSL::Cipher).to receive(:new).with('AES-128-GCM').and_call_original
|
93
|
+
packet.decrypt(key)
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'returns the expected decrypted string' do
|
97
|
+
expect(packet.decrypt(key)).to eq(data)
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'raises the expected exception if an error occurs' do
|
101
|
+
allow(OpenSSL::Cipher).to receive(:new).and_raise(
|
102
|
+
RuntimeError.new('unsupported cipher algorithm (AES-128-GCM)'))
|
103
|
+
expect { packet.decrypt(key) }.to raise_error(
|
104
|
+
RubySMB::Error::EncryptionError,
|
105
|
+
'Error while decrypting with \'AES-128-GCM\' (RuntimeError: unsupported cipher algorithm (AES-128-GCM))'
|
106
|
+
)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
context 'with AES-128-CCM algorithm' do
|
111
|
+
before :example do
|
112
|
+
packet.encrypted_data = "\xf0\x05\x61\x91".bytes
|
113
|
+
packet.signature = "\xdd\x51\x9a\xc5\x6d\x38\x68\xdc\x36\x89\xb8\x99\xd8\x4a\xb8\x4a".b
|
114
|
+
packet.nonce = "\x8a\x6e\x2a\x87\x11\x61\x85\xd2\x15\x69\xf7\x00\x00\x00\x00\x00".b
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'generates a cipher using OpenSSL::CCM' do
|
118
|
+
expect(OpenSSL::CCM).to receive(:new).with('AES', key, 16).and_call_original
|
119
|
+
packet.decrypt(key, algorithm: 'AES-128-CCM')
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'returns the expected decrypted string' do
|
123
|
+
expect(packet.decrypt(key, algorithm: 'AES-128-CCM')).to eq(data)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'raises the expected exception if an error occurs' do
|
127
|
+
allow(OpenSSL::CCM).to receive(:new).and_raise(
|
128
|
+
OpenSSL::CCMError.new('unsupported cipher algorithm (AES-128-CCM)'))
|
129
|
+
expect { packet.decrypt(key, algorithm: 'AES-128-CCM') }.to raise_error(
|
130
|
+
RubySMB::Error::EncryptionError,
|
131
|
+
'Error while decrypting with \'AES-128-CCM\' (OpenSSL::CCMError: unsupported cipher algorithm (AES-128-CCM))'
|
132
|
+
)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#encrypt' do
|
138
|
+
let(:key) { "\x56\x89\xd1\xbb\xf7\x45\xc0\xb6\x68\x81\x07\xe4\x7d\x35\xaf\xd3".b }
|
139
|
+
let(:struct) { RubySMB::SMB2::Packet::TreeConnectRequest.new }
|
140
|
+
|
141
|
+
it 'raises the expected exception if the given algorithm is invalid' do
|
142
|
+
expect { packet.encrypt(struct, key, algorithm: 'RC4') }.to raise_error(
|
143
|
+
RubySMB::Error::EncryptionError,
|
144
|
+
'Error while encrypting with \'RC4\' (ArgumentError: Invalid algorithm, must be either AES-128-CCM or AES-128-GCM)'
|
145
|
+
)
|
146
|
+
end
|
147
|
+
|
148
|
+
context 'with AES-128-GCM algorithm (default)' do
|
149
|
+
before :example do
|
150
|
+
begin
|
151
|
+
OpenSSL::Cipher.new('AES-128-GCM')
|
152
|
+
rescue
|
153
|
+
skip(
|
154
|
+
"This test cannot be run since the version of OpenSSL the ruby "\
|
155
|
+
"OpenSSL extension was built with (#{OpenSSL::OPENSSL_VERSION}) "\
|
156
|
+
"does not support AES-128-GCM cipher")
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it 'generates a cipher using OpenSSL::Cipher' do
|
161
|
+
expect(OpenSSL::Cipher).to receive(:new).with('AES-128-GCM').and_call_original
|
162
|
+
packet.encrypt(struct, key)
|
163
|
+
end
|
164
|
+
|
165
|
+
it 'encrypts a BinData structure' do
|
166
|
+
packet.encrypt(struct, key)
|
167
|
+
expect(packet.decrypt(key)).to eq(struct.to_binary_s)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'encrypts a string' do
|
171
|
+
packet.encrypt('data', key)
|
172
|
+
expect(packet.decrypt(key)).to eq('data')
|
173
|
+
end
|
174
|
+
|
175
|
+
it 'raises the expected exception if an error occurs' do
|
176
|
+
allow(OpenSSL::Cipher).to receive(:new).and_raise(
|
177
|
+
RuntimeError.new('unsupported cipher algorithm (AES-128-GCM)'))
|
178
|
+
expect { packet.encrypt('data', key) }.to raise_error(
|
179
|
+
RubySMB::Error::EncryptionError,
|
180
|
+
'Error while encrypting with \'AES-128-GCM\' (RuntimeError: unsupported cipher algorithm (AES-128-GCM))'
|
181
|
+
)
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'with AES-128-CCM algorithm' do
|
186
|
+
it 'generates a cipher using OpenSSL::CCM' do
|
187
|
+
expect(OpenSSL::CCM).to receive(:new).with('AES', key, 16).and_call_original
|
188
|
+
packet.encrypt(struct, key, algorithm: 'AES-128-CCM')
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'encrypts a BinData structure' do
|
192
|
+
packet.encrypt(struct, key, algorithm: 'AES-128-CCM')
|
193
|
+
expect(packet.decrypt(key, algorithm: 'AES-128-CCM')).to eq(struct.to_binary_s)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'encrypts a string' do
|
197
|
+
packet.encrypt('data', key, algorithm: 'AES-128-CCM')
|
198
|
+
expect(packet.decrypt(key, algorithm: 'AES-128-CCM')).to eq('data')
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'raises the expected exception if an error occurs' do
|
202
|
+
allow(OpenSSL::CCM).to receive(:new).and_raise(
|
203
|
+
OpenSSL::CCMError.new('unsupported cipher algorithm (AES-128-CCM)'))
|
204
|
+
expect { packet.encrypt('data', key, algorithm: 'AES-128-CCM') }.to raise_error(
|
205
|
+
RubySMB::Error::EncryptionError,
|
206
|
+
'Error while encrypting with \'AES-128-CCM\' (OpenSSL::CCMError: unsupported cipher algorithm (AES-128-CCM))'
|
207
|
+
)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'reads binary data as expected' do
|
213
|
+
data = described_class.new
|
214
|
+
key = "\x56\x89\xd1\xbb\xf7\x45\xc0\xb6\x68\x81\x07\xe4\x7d\x35\xaf\xd3".b
|
215
|
+
struct = RubySMB::SMB2::Packet::TreeConnectRequest.new
|
216
|
+
data.encrypt(struct, key, algorithm: 'AES-128-CCM')
|
217
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
@@ -9,6 +9,7 @@ RSpec.describe RubySMB::SMB2::Packet::TreeConnectRequest do
|
|
9
9
|
it { is_expected.to respond_to :path_offset }
|
10
10
|
it { is_expected.to respond_to :path_length }
|
11
11
|
it { is_expected.to respond_to :path }
|
12
|
+
it { is_expected.to respond_to :tree_connect_request_extension }
|
12
13
|
|
13
14
|
it 'is little endian' do
|
14
15
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
@@ -30,18 +31,347 @@ RSpec.describe RubySMB::SMB2::Packet::TreeConnectRequest do
|
|
30
31
|
end
|
31
32
|
end
|
32
33
|
|
33
|
-
describe '#
|
34
|
-
|
35
|
-
|
34
|
+
describe '#structure_size' do
|
35
|
+
it 'should be a 16-bit unsigned integer' do
|
36
|
+
expect(packet.structure_size).to be_a BinData::Uint16le
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should have a default value of 9 as per the SMB2 spec' do
|
40
|
+
expect(packet.structure_size).to eq 9
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#flags' do
|
45
|
+
it 'should be a 16-bit unsigned integer' do
|
46
|
+
expect(packet.flags).to be_a BinData::Uint16le
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#path_offset' do
|
51
|
+
it 'should be a 16-bit unsigned integer' do
|
52
|
+
expect(packet.path_offset).to be_a BinData::Uint16le
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when flags is set to SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT' do
|
56
|
+
it 'should be set to the offset, in bytes, of the full share path name from the beginning of the packet header' do
|
57
|
+
packet.flags = described_class::SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT
|
58
|
+
expect(packet.path_offset).to eq(88)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
context 'when flags is not set to SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT' do
|
63
|
+
it 'should be set to the offset, in bytes, of the full share path name from the beginning of the packet header' do
|
64
|
+
expect(packet.path_offset).to eq(72)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#path_length' do
|
70
|
+
let(:path) { '\\\\server\\path' }
|
71
|
+
|
72
|
+
it 'should be a 16-bit unsigned integer' do
|
73
|
+
expect(packet.path_length).to be_a BinData::Uint16le
|
74
|
+
end
|
75
|
+
|
76
|
+
context 'when flags is set to SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT' do
|
77
|
+
it 'should be the length of the full share path name (unicode) in bytes' do
|
78
|
+
packet.flags = described_class::SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT
|
79
|
+
packet.tree_connect_request_extension.path = path
|
80
|
+
expect(packet.path_length).to eq(path.length * 2)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when flags is not set to SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT' do
|
85
|
+
it 'should be the length of the full share path name (unicode) in bytes' do
|
86
|
+
packet.path = path
|
87
|
+
expect(packet.path_length).to eq(path.length * 2)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe '#path' do
|
93
|
+
it 'should be a unicode string' do
|
94
|
+
expect(packet.path).to be_a RubySMB::Field::String16
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'exists if #flags is not set to SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT' do
|
98
|
+
packet.flags = described_class::SMB2_TREE_CONNECT_FLAG_REDIRECT_TO_OWNER
|
99
|
+
expect(packet.path?).to be true
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '#tree_connect_request_extension' do
|
104
|
+
it 'is a TreeConnectRequestExtension structure' do
|
105
|
+
expect(packet.tree_connect_request_extension).to be_a RubySMB::SMB2::Packet::TreeConnectRequestExtension
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'exists if #flags is set to SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT' do
|
109
|
+
packet.flags = described_class::SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT
|
110
|
+
expect(packet.tree_connect_request_extension?).to be true
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'reads binary data as expected' do
|
115
|
+
data = described_class.new
|
116
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
117
|
+
data = described_class.new(flags: described_class::SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT)
|
118
|
+
data.tree_connect_request_extension.tree_connect_contexts << RubySMB::SMB2::Packet::TreeConnectContext.new(context_type: 1)
|
119
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
RSpec.describe RubySMB::SMB2::Packet::TreeConnectRequestExtension do
|
124
|
+
subject(:packet) { described_class.new }
|
125
|
+
|
126
|
+
it { is_expected.to respond_to :tree_connect_context_offset }
|
127
|
+
it { is_expected.to respond_to :tree_connect_context_count }
|
128
|
+
it { is_expected.to respond_to :reserved }
|
129
|
+
it { is_expected.to respond_to :path }
|
130
|
+
it { is_expected.to respond_to :tree_connect_contexts }
|
131
|
+
|
132
|
+
it 'is little endian' do
|
133
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
134
|
+
end
|
135
|
+
|
136
|
+
describe '#tree_connect_context_offset' do
|
137
|
+
it 'is a 32-bit unsigned integer' do
|
138
|
+
expect(packet.tree_connect_context_offset).to be_a BinData::Uint32le
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'is the offset from the start of the SMB2 TREE_CONNECT request of an array of tree connect contexts' do
|
142
|
+
tc = RubySMB::SMB2::Packet::TreeConnectRequest.new(
|
143
|
+
flags: RubySMB::SMB2::Packet::TreeConnectRequest::SMB2_TREE_CONNECT_FLAG_EXTENSION_PRESENT
|
144
|
+
)
|
145
|
+
expect(tc.tree_connect_request_extension.tree_connect_context_offset).to eq(16)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
describe '#tree_connect_context_count' do
|
150
|
+
it 'should be a 16-bit unsigned integer' do
|
151
|
+
expect(packet.tree_connect_context_count).to be_a BinData::Uint16le
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should be the #tree_connect_contexts size' do
|
155
|
+
packet.tree_connect_contexts << RubySMB::SMB2::Packet::TreeConnectContext.new(context_type: 1)
|
156
|
+
packet.tree_connect_contexts << RubySMB::SMB2::Packet::TreeConnectContext.new(context_type: 1)
|
157
|
+
expect(packet.tree_connect_context_count).to eq(2)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
describe '#reserved' do
|
162
|
+
it 'should be a binary string' do
|
163
|
+
expect(packet.reserved).to be_a BinData::String
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'is 10-bytes long' do
|
167
|
+
expect(packet.reserved.length).to eq(10)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
describe '#path' do
|
172
|
+
it 'should be a unicode string' do
|
173
|
+
expect(packet.path).to be_a RubySMB::Field::String16
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe '#tree_connect_contexts' do
|
178
|
+
it 'is an Array field' do
|
179
|
+
expect(packet.tree_connect_contexts).to be_a BinData::Array
|
180
|
+
end
|
181
|
+
|
182
|
+
it 'has #tree_connect_context_count elements' do
|
183
|
+
packet.tree_connect_context_count = 3
|
184
|
+
expect(packet.tree_connect_contexts.size).to eq(3)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'reads binary data as expected' do
|
189
|
+
data = described_class.new
|
190
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
191
|
+
data.tree_connect_contexts << RubySMB::SMB2::Packet::TreeConnectContext.new(context_type: 1)
|
192
|
+
data.tree_connect_contexts << RubySMB::SMB2::Packet::TreeConnectContext.new(context_type: 1)
|
193
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
RSpec.describe RubySMB::SMB2::Packet::TreeConnectContext do
|
198
|
+
subject(:packet) do
|
199
|
+
described_class.new(
|
200
|
+
context_type: described_class::SMB2_REMOTED_IDENTITY_TREE_CONNECT_CONTEXT_ID
|
201
|
+
)
|
202
|
+
end
|
203
|
+
|
204
|
+
it { is_expected.to respond_to :context_type }
|
205
|
+
it { is_expected.to respond_to :data_length }
|
206
|
+
it { is_expected.to respond_to :reserved }
|
207
|
+
it { is_expected.to respond_to :data }
|
208
|
+
|
209
|
+
it 'is little endian' do
|
210
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
211
|
+
end
|
212
|
+
|
213
|
+
describe '#context_type' do
|
214
|
+
it 'should be a 16-bit unsigned integer' do
|
215
|
+
expect(packet.context_type).to be_a BinData::Uint16le
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
describe '#data_length' do
|
220
|
+
it 'should be a 16-bit unsigned integer' do
|
221
|
+
expect(packet.data_length).to be_a BinData::Uint16le
|
222
|
+
end
|
223
|
+
|
224
|
+
it 'is the length, in bytes, of the Data field' do
|
225
|
+
expect(packet.data_length).to eq(packet.data.to_binary_s.size)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
describe '#reserved' do
|
230
|
+
it 'is a 32-bit unsigned integer' do
|
231
|
+
expect(packet.reserved).to be_a BinData::Uint32le
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
describe '#data' do
|
236
|
+
it 'is a BinData Choice' do
|
237
|
+
expect(packet.data).to be_a BinData::Choice
|
238
|
+
end
|
239
|
+
|
240
|
+
it 'contains the structure defined by #context_type' do
|
241
|
+
expect(packet.data).to eq(RubySMB::SMB2::Packet::RemotedIdentityTreeConnectContext.new)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'reads binary data as expected' do
|
246
|
+
data = described_class.new(context_type: 1)
|
247
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
RSpec.describe RubySMB::SMB2::Packet::RemotedIdentityTreeConnectContext do
|
252
|
+
subject(:packet) { described_class.new }
|
253
|
+
|
254
|
+
it { is_expected.to respond_to :ticket_type }
|
255
|
+
it { is_expected.to respond_to :ticket_size }
|
256
|
+
it { is_expected.to respond_to :user }
|
257
|
+
it { is_expected.to respond_to :user_name }
|
258
|
+
it { is_expected.to respond_to :domain }
|
259
|
+
it { is_expected.to respond_to :groups }
|
260
|
+
it { is_expected.to respond_to :restricted_groups }
|
261
|
+
it { is_expected.to respond_to :privileges }
|
262
|
+
it { is_expected.to respond_to :primary_group }
|
263
|
+
it { is_expected.to respond_to :owner }
|
264
|
+
it { is_expected.to respond_to :default_dacl }
|
265
|
+
it { is_expected.to respond_to :device_groups }
|
266
|
+
it { is_expected.to respond_to :user_claims }
|
267
|
+
it { is_expected.to respond_to :device_claims }
|
268
|
+
it { is_expected.to respond_to :ticket_info }
|
269
|
+
|
270
|
+
it 'is little endian' do
|
271
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
272
|
+
end
|
273
|
+
|
274
|
+
describe '#ticket_type' do
|
275
|
+
it 'should be a 16-bit unsigned integer' do
|
276
|
+
expect(packet.ticket_type).to be_a BinData::Uint16le
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should be 1' do
|
280
|
+
expect(packet.ticket_type).to eq(1)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
describe '#ticket_size' do
|
285
|
+
it 'should be a 16-bit unsigned integer' do
|
286
|
+
expect(packet.ticket_size).to be_a BinData::Uint16le
|
287
|
+
end
|
288
|
+
|
289
|
+
it 'is the total size of this structure' do
|
290
|
+
packet.ticket_info = 'Ticket Info'
|
291
|
+
expect(packet.ticket_size).to eq(packet.num_bytes)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
describe '#user' do
|
296
|
+
it 'should be a 16-bit unsigned integer' do
|
297
|
+
expect(packet.user).to be_a BinData::Uint16le
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
describe '#user_name' do
|
302
|
+
it 'should be a 16-bit unsigned integer' do
|
303
|
+
expect(packet.user_name).to be_a BinData::Uint16le
|
304
|
+
end
|
305
|
+
end
|
36
306
|
|
37
|
-
|
38
|
-
|
39
|
-
expect(packet.
|
307
|
+
describe '#domain' do
|
308
|
+
it 'should be a 16-bit unsigned integer' do
|
309
|
+
expect(packet.domain).to be_a BinData::Uint16le
|
40
310
|
end
|
311
|
+
end
|
41
312
|
|
42
|
-
|
43
|
-
|
44
|
-
expect(packet.
|
313
|
+
describe '#groups' do
|
314
|
+
it 'should be a 16-bit unsigned integer' do
|
315
|
+
expect(packet.groups).to be_a BinData::Uint16le
|
45
316
|
end
|
46
317
|
end
|
318
|
+
|
319
|
+
describe '#restricted_groups' do
|
320
|
+
it 'should be a 16-bit unsigned integer' do
|
321
|
+
expect(packet.restricted_groups).to be_a BinData::Uint16le
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
describe '#privileges' do
|
326
|
+
it 'should be a 16-bit unsigned integer' do
|
327
|
+
expect(packet.privileges).to be_a BinData::Uint16le
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
describe '#primary_group' do
|
332
|
+
it 'should be a 16-bit unsigned integer' do
|
333
|
+
expect(packet.primary_group).to be_a BinData::Uint16le
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
describe '#owner' do
|
338
|
+
it 'should be a 16-bit unsigned integer' do
|
339
|
+
expect(packet.owner).to be_a BinData::Uint16le
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
describe '#default_dacl' do
|
344
|
+
it 'should be a 16-bit unsigned integer' do
|
345
|
+
expect(packet.default_dacl).to be_a BinData::Uint16le
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
describe '#device_groups' do
|
350
|
+
it 'should be a 16-bit unsigned integer' do
|
351
|
+
expect(packet.device_groups).to be_a BinData::Uint16le
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
describe '#user_claims' do
|
356
|
+
it 'should be a 16-bit unsigned integer' do
|
357
|
+
expect(packet.user_claims).to be_a BinData::Uint16le
|
358
|
+
end
|
359
|
+
end
|
360
|
+
|
361
|
+
describe '#device_claims' do
|
362
|
+
it 'should be a 16-bit unsigned integer' do
|
363
|
+
expect(packet.device_claims).to be_a BinData::Uint16le
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
describe '#ticket_info' do
|
368
|
+
it 'should be string' do
|
369
|
+
expect(packet.ticket_info).to be_a BinData::String
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'reads binary data as expected' do
|
374
|
+
data = described_class.new(ticket_info: 'ticket info')
|
375
|
+
expect(described_class.read(data.to_binary_s)).to eq(data)
|
376
|
+
end
|
47
377
|
end
|