ruby_smb 1.0.3 → 2.0.1
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 +233 -22
- data/lib/ruby_smb/client/authentication.rb +70 -33
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/encryption.rb +62 -0
- data/lib/ruby_smb/client/negotiation.rb +172 -24
- data/lib/ruby_smb/client/signing.rb +19 -0
- data/lib/ruby_smb/client/tree_connect.rb +24 -18
- 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 +68 -2
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/commands.rb +1 -1
- data/lib/ruby_smb/smb1/file.rb +66 -15
- data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +3 -6
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +87 -6
- data/lib/ruby_smb/smb1/tree.rb +50 -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 +103 -25
- 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/close_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/compression_transform_header.rb +41 -0
- data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +51 -17
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +52 -5
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/transform_header.rb +84 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +93 -10
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +10 -22
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
- data/lib/ruby_smb/smb2/pipe.rb +86 -12
- data/lib/ruby_smb/smb2/smb2_header.rb +1 -1
- data/lib/ruby_smb/smb2/tree.rb +65 -21
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +5 -3
- data/spec/lib/ruby_smb/client_spec.rb +1612 -108
- 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/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
- data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -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/packet/trans2/find_first2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- 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 +323 -6
- 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 +78 -0
- 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/query_directory_response_spec.rb +8 -0
- 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 -22
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +286 -149
- data/spec/lib/ruby_smb/smb2/smb2_header_spec.rb +2 -2
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +261 -2
- metadata +191 -83
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
@@ -0,0 +1,81 @@
|
|
1
|
+
RSpec.describe RubySMB::Dcerpc do
|
2
|
+
let(:tree) { double('Tree') }
|
3
|
+
let(:pipe) do
|
4
|
+
RubySMB::SMB1::Pipe.new(
|
5
|
+
tree: tree,
|
6
|
+
response: RubySMB::SMB1::Packet::NtCreateAndxResponse.new,
|
7
|
+
name: 'winreg'
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
describe '#bind' do
|
12
|
+
let(:options) { { endpoint: RubySMB::Dcerpc::Winreg } }
|
13
|
+
let(:bind_packet) { RubySMB::Dcerpc::Bind.new(options) }
|
14
|
+
let(:bind_ack_packet) { RubySMB::Dcerpc::BindAck.new }
|
15
|
+
let(:client) { double('Client') }
|
16
|
+
|
17
|
+
before :example do
|
18
|
+
allow(RubySMB::Dcerpc::Bind).to receive(:new).and_return(bind_packet)
|
19
|
+
allow(pipe).to receive(:write)
|
20
|
+
allow(pipe).to receive(:read)
|
21
|
+
bind_ack_packet.p_result_list.n_results = 1
|
22
|
+
bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::ACCEPTANCE
|
23
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(bind_ack_packet)
|
24
|
+
allow(tree).to receive(:client).and_return(client)
|
25
|
+
allow(client).to receive(:max_buffer_size=)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'creates a Bind packet' do
|
29
|
+
pipe.bind(options)
|
30
|
+
expect(RubySMB::Dcerpc::Bind).to have_received(:new).with(options)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'writes to the named pipe' do
|
34
|
+
pipe.bind(options)
|
35
|
+
expect(pipe).to have_received(:write).with(data: bind_packet.to_binary_s)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'reads the socket' do
|
39
|
+
pipe.bind(options)
|
40
|
+
expect(pipe).to have_received(:read)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'creates a BindAck packet from the response' do
|
44
|
+
raw_response = RubySMB::Dcerpc::BindAck.new.to_binary_s
|
45
|
+
allow(pipe).to receive(:read).and_return(raw_response)
|
46
|
+
pipe.bind(options)
|
47
|
+
expect(RubySMB::Dcerpc::BindAck).to have_received(:read).with(raw_response)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'raises the expected exception when an invalid packet is received' do
|
51
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_raise(IOError)
|
52
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'raises the expected exception when it is not a BindAck packet' do
|
56
|
+
response = RubySMB::Dcerpc::Bind.new
|
57
|
+
allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(response)
|
58
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'raises an exception when no result is returned' do
|
62
|
+
bind_ack_packet.p_result_list.n_results = 0
|
63
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'raises an exception when result is not ACCEPTANCE' do
|
67
|
+
bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::USER_REJECTION
|
68
|
+
expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'sets the Tree #client.max_buffer_size property to the DCERPC response #max_xmit_frag property value' do
|
72
|
+
bind_ack_packet.max_xmit_frag = 64
|
73
|
+
pipe.bind(options)
|
74
|
+
expect(client).to have_received(:max_buffer_size=).with(64)
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'returns the expected BindAck packet' do
|
78
|
+
expect(pipe.bind(options)).to eq(bind_ack_packet)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -51,9 +51,9 @@ RSpec.describe RubySMB::Dispatcher::Socket do
|
|
51
51
|
let(:session_header) { RubySMB::Nbss::SessionHeader.new }
|
52
52
|
|
53
53
|
context 'when reading from the socket results in a nil value' do
|
54
|
-
it 'should raise Error::
|
54
|
+
it 'should raise Error::CommunicationError' do
|
55
55
|
smb_socket.tcp_socket = blank_socket
|
56
|
-
expect { smb_socket.recv_packet }.to raise_error(::RubySMB::Error::
|
56
|
+
expect { smb_socket.recv_packet }.to raise_error(::RubySMB::Error::CommunicationError)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe RubySMB::Error::InvalidPacket do
|
4
|
+
context 'with a String' do
|
5
|
+
it 'outputs the expected error message' do
|
6
|
+
ex = described_class.new('My exception')
|
7
|
+
expect(ex.to_s).to eq('My exception')
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
context 'with a Hash' do
|
12
|
+
it 'outputs the expected error message' do
|
13
|
+
ex = described_class.new(
|
14
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
15
|
+
expected_cmd: RubySMB::SMB1::Packet::NegotiateResponseExtended::COMMAND,
|
16
|
+
expected_custom: "extended_security=1",
|
17
|
+
received_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
|
18
|
+
received_cmd: RubySMB::SMB2::Packet::NegotiateResponse::COMMAND,
|
19
|
+
received_custom: "extended_security=0"
|
20
|
+
)
|
21
|
+
expect(ex.to_s).to eq('Expecting SMB1 protocol with command=114 (extended_security=1), got SMB2 protocol with command=0 (extended_security=0)')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'with an unsupported type' do
|
26
|
+
it 'raises the expected exception' do
|
27
|
+
expect { described_class.new(['wrong']) }.to raise_error(
|
28
|
+
ArgumentError,
|
29
|
+
'InvalidPacket expects a String or a Hash, got a Array'
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
RSpec.describe RubySMB::Error::UnexpectedStatusCode do
|
37
|
+
context 'with a WindowsError::ErrorCode' do
|
38
|
+
it 'outputs the expected error message' do
|
39
|
+
ex = described_class.new(WindowsError::NTStatus::STATUS_BUFFER_OVERFLOW)
|
40
|
+
expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with an Integer' do
|
45
|
+
it 'outputs the expected error message' do
|
46
|
+
ex = described_class.new(0x80000005)
|
47
|
+
expect(ex.to_s).to eq('The server responded with an unexpected status code: STATUS_BUFFER_OVERFLOW')
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'with an unsupported type' do
|
52
|
+
it 'raises the expected exception' do
|
53
|
+
expect { described_class.new(['wrong']) }.to raise_error(
|
54
|
+
ArgumentError,
|
55
|
+
'Status code must be a WindowsError::ErrorCode or an Integer, got Array'
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -63,8 +63,13 @@ RSpec.describe RubySMB::GenericPacket do
|
|
63
63
|
expect(RubySMB::SMB1::Packet::NegotiateResponse.read(smb1_error_packet.to_binary_s)).to be_a RubySMB::SMB1::Packet::EmptyPacket
|
64
64
|
end
|
65
65
|
|
66
|
-
it '
|
67
|
-
expect{RubySMB::SMB1::Packet::NegotiateResponse.read('a')}.to raise_error(
|
66
|
+
it 'raises an InvaliPacket exception if it is not a valid error packet either' do
|
67
|
+
expect{RubySMB::SMB1::Packet::NegotiateResponse.read('a')}.to raise_error(RubySMB::Error::InvalidPacket)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'sets the EmptyPacket#original_command attribute to the original COMMAND' do
|
71
|
+
packet = RubySMB::SMB1::Packet::NegotiateResponse.read(smb1_error_packet.to_binary_s)
|
72
|
+
expect(packet.original_command).to eq RubySMB::SMB1::Packet::NegotiateResponse::COMMAND
|
68
73
|
end
|
69
74
|
end
|
70
75
|
|
@@ -75,8 +80,51 @@ RSpec.describe RubySMB::GenericPacket do
|
|
75
80
|
expect(RubySMB::SMB2::Packet::NegotiateResponse.read(smb2_error_packet.to_binary_s)).to be_a RubySMB::SMB2::Packet::ErrorPacket
|
76
81
|
end
|
77
82
|
|
78
|
-
it '
|
79
|
-
expect{RubySMB::SMB2::Packet::NegotiateResponse.read('a')}.to raise_error(
|
83
|
+
it 'raises an InvaliPacket exception if it is not a valid error packet either' do
|
84
|
+
expect{RubySMB::SMB2::Packet::NegotiateResponse.read('a')}.to raise_error(RubySMB::Error::InvalidPacket)
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'sets the ErrorPacket#original_command attribute to the original COMMAND' do
|
88
|
+
packet = RubySMB::SMB2::Packet::NegotiateResponse.read(smb2_error_packet.to_binary_s)
|
89
|
+
expect(packet.original_command).to eq RubySMB::SMB2::Packet::NegotiateResponse::COMMAND
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#valid?' do
|
95
|
+
context 'when reading an SMB1 packet' do
|
96
|
+
let(:packet) { RubySMB::SMB1::Packet::NegotiateResponse.new }
|
97
|
+
|
98
|
+
it 'returns true if the packet protocol ID and header command are valid' do
|
99
|
+
expect(packet).to be_valid
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'returns false if the packet protocol ID is wrong' do
|
103
|
+
packet.smb_header.protocol = RubySMB::SMB2::SMB2_PROTOCOL_ID
|
104
|
+
expect(packet).to_not be_valid
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'returns false if the packet header command is wrong' do
|
108
|
+
packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_TREE_CONNECT
|
109
|
+
expect(packet).to_not be_valid
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'when reading an SMB2 packet' do
|
114
|
+
let(:packet) { RubySMB::SMB2::Packet::NegotiateResponse.new }
|
115
|
+
|
116
|
+
it 'returns true if the packet protocol ID and header command are valid' do
|
117
|
+
expect(packet).to be_valid
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'returns false if the packet protocol ID is wrong' do
|
121
|
+
packet.smb2_header.protocol = RubySMB::SMB1::SMB_PROTOCOL_ID
|
122
|
+
expect(packet).to_not be_valid
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'returns false if the packet header command is wrong' do
|
126
|
+
packet.smb2_header.command = RubySMB::SMB2::Commands::TREE_CONNECT
|
127
|
+
expect(packet).to_not be_valid
|
80
128
|
end
|
81
129
|
end
|
82
130
|
end
|
@@ -110,10 +110,18 @@ RSpec.describe RubySMB::SMB1::File do
|
|
110
110
|
file.read_packet
|
111
111
|
end
|
112
112
|
|
113
|
-
it 'sets the
|
113
|
+
it 'sets the #max_count_of_bytes_to_return of the packet' do
|
114
114
|
expect(file.read_packet(read_length: 55).parameter_block.max_count_of_bytes_to_return).to eq 55
|
115
115
|
end
|
116
116
|
|
117
|
+
it 'sets the #min_count_of_bytes_to_return of the packet' do
|
118
|
+
expect(file.read_packet(read_length: 55).parameter_block.min_count_of_bytes_to_return).to eq 55
|
119
|
+
end
|
120
|
+
|
121
|
+
it 'sets the #remaining of the packet' do
|
122
|
+
expect(file.read_packet(read_length: 55).parameter_block.remaining).to eq 55
|
123
|
+
end
|
124
|
+
|
117
125
|
it 'sets the offset of the packet' do
|
118
126
|
expect(file.read_packet(offset: 55).parameter_block.offset).to eq 55
|
119
127
|
end
|
@@ -163,7 +171,7 @@ RSpec.describe RubySMB::SMB1::File do
|
|
163
171
|
end
|
164
172
|
|
165
173
|
context 'when sending the request packet and gets a response back' do
|
166
|
-
context 'when the response is not
|
174
|
+
context 'when the response is not valid' do
|
167
175
|
it 'raise an InvalidPacket exception' do
|
168
176
|
read_andx_response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_ECHO
|
169
177
|
expect { file.read }.to raise_error(RubySMB::Error::InvalidPacket)
|
@@ -181,6 +189,7 @@ RSpec.describe RubySMB::SMB1::File do
|
|
181
189
|
let(:empty_packet) do
|
182
190
|
empty_packet = RubySMB::SMB1::Packet::EmptyPacket.new
|
183
191
|
empty_packet.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_READ_ANDX
|
192
|
+
empty_packet.original_command = RubySMB::SMB1::Commands::SMB_COM_READ_ANDX
|
184
193
|
empty_packet
|
185
194
|
end
|
186
195
|
|
@@ -345,6 +354,11 @@ RSpec.describe RubySMB::SMB1::File do
|
|
345
354
|
set_info_res.smb_header.nt_status = status.value
|
346
355
|
expect(file.delete).to eq status
|
347
356
|
end
|
357
|
+
|
358
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
359
|
+
allow(set_info_res).to receive(:valid?).and_return(false)
|
360
|
+
expect { file.delete }.to raise_error(RubySMB::Error::InvalidPacket)
|
361
|
+
end
|
348
362
|
end
|
349
363
|
|
350
364
|
describe '#delete_packet' do
|
@@ -415,6 +429,11 @@ RSpec.describe RubySMB::SMB1::File do
|
|
415
429
|
set_info_res.smb_header.nt_status = status.value
|
416
430
|
expect(file.rename(filename)).to eq status
|
417
431
|
end
|
432
|
+
|
433
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
434
|
+
allow(set_info_res).to receive(:valid?).and_return(false)
|
435
|
+
expect { file.rename(filename) }.to raise_error(RubySMB::Error::InvalidPacket)
|
436
|
+
end
|
418
437
|
end
|
419
438
|
|
420
439
|
describe '#rename_packet' do
|
@@ -465,5 +484,175 @@ RSpec.describe RubySMB::SMB1::File do
|
|
465
484
|
expect(parameter_block.max_data_count).to eq 16_384
|
466
485
|
end
|
467
486
|
end
|
487
|
+
|
488
|
+
describe '#close' do
|
489
|
+
let(:request) { double('CloseRequest') }
|
490
|
+
let(:response) { double('CloseResponse') }
|
491
|
+
let(:raw_response) { double('Raw response') }
|
492
|
+
|
493
|
+
before :example do
|
494
|
+
allow(RubySMB::SMB1::Packet::CloseRequest).to receive(:new).and_return(request)
|
495
|
+
allow(file).to receive(:set_header_fields).and_return(request)
|
496
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
497
|
+
allow(RubySMB::SMB1::Packet::CloseResponse).to receive(:read).and_return(response)
|
498
|
+
allow(response).to receive(:valid?).and_return(true)
|
499
|
+
allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_SUCCESS)
|
500
|
+
end
|
501
|
+
|
502
|
+
it 'creates a new SMB1 CloseRequest packet' do
|
503
|
+
expect(RubySMB::SMB1::Packet::CloseRequest).to receive(:new)
|
504
|
+
file.close
|
505
|
+
end
|
506
|
+
|
507
|
+
it 'calls Tree #set_header_fields to set SetFileInformationRequest headers' do
|
508
|
+
expect(file).to receive(:set_header_fields).with(request)
|
509
|
+
file.close
|
510
|
+
end
|
511
|
+
|
512
|
+
it 'calls Client #send_recv with the expected request' do
|
513
|
+
expect(client).to receive(:send_recv).with(request)
|
514
|
+
file.close
|
515
|
+
end
|
516
|
+
|
517
|
+
it 'parses the response as a SMB1 CloseResponse packet' do
|
518
|
+
expect(RubySMB::SMB1::Packet::CloseResponse).to receive(:read).with(raw_response)
|
519
|
+
file.close
|
520
|
+
end
|
521
|
+
|
522
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
523
|
+
allow(response).to receive(:valid?).and_return(false)
|
524
|
+
smb_header = double('SMB Header')
|
525
|
+
allow(response).to receive(:smb_header).and_return(smb_header)
|
526
|
+
allow(smb_header).to receive_messages(:protocol => nil, :command => nil)
|
527
|
+
expect { file.close }.to raise_error(RubySMB::Error::InvalidPacket)
|
528
|
+
end
|
529
|
+
|
530
|
+
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
|
531
|
+
allow(response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
532
|
+
expect { file.close }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
533
|
+
end
|
534
|
+
|
535
|
+
it 'returns the response status code' do
|
536
|
+
expect(file.close).to eq WindowsError::NTStatus::STATUS_SUCCESS
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
describe '#send_recv_read' do
|
541
|
+
let(:read_data) { 'read data' }
|
542
|
+
let(:raw_response) { double('fake raw response data') }
|
543
|
+
let(:read_andx_response) {
|
544
|
+
res = RubySMB::SMB1::Packet::ReadAndxResponse.new
|
545
|
+
res.data_block.data = read_data
|
546
|
+
res
|
547
|
+
}
|
548
|
+
|
549
|
+
before :example do
|
550
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
551
|
+
allow(RubySMB::SMB1::Packet::ReadAndxResponse).to receive(:read).with(raw_response).and_return(read_andx_response)
|
552
|
+
end
|
553
|
+
|
554
|
+
context 'when the number of bytes to read is not provided' do
|
555
|
+
it 'reads 0 bytes by default' do
|
556
|
+
expect(file).to receive(:read_packet).with(read_length: 0, offset: 0).once.and_call_original
|
557
|
+
file.send_recv_read
|
558
|
+
end
|
559
|
+
end
|
560
|
+
|
561
|
+
it 'only reads the number of bytes provided as argument' do
|
562
|
+
bytes = 5
|
563
|
+
expect(file).to receive(:read_packet).with(read_length: bytes, offset: 0).once.and_call_original
|
564
|
+
file.send_recv_read(read_length: bytes)
|
565
|
+
end
|
566
|
+
|
567
|
+
it 'reads from the offset provided as argument' do
|
568
|
+
offset = 3
|
569
|
+
expect(file).to receive(:read_packet).with(read_length: 0, offset: offset).once.and_call_original
|
570
|
+
file.send_recv_read(offset: offset)
|
571
|
+
end
|
572
|
+
|
573
|
+
it 'calls Client #send_recv with the expected request' do
|
574
|
+
request = double('Request')
|
575
|
+
allow(file).to receive(:read_packet).and_return(request)
|
576
|
+
expect(client).to receive(:send_recv).with(request)
|
577
|
+
file.send_recv_read
|
578
|
+
end
|
579
|
+
|
580
|
+
it 'parses the response as a SMB1 ReadAndxResponse packet' do
|
581
|
+
expect(RubySMB::SMB1::Packet::ReadAndxResponse).to receive(:read).with(raw_response)
|
582
|
+
file.send_recv_read
|
583
|
+
end
|
584
|
+
|
585
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
586
|
+
allow(read_andx_response).to receive(:valid?).and_return(false)
|
587
|
+
expect { file.send_recv_read }.to raise_error(RubySMB::Error::InvalidPacket)
|
588
|
+
end
|
589
|
+
|
590
|
+
it 'raises an UnexpectedStatusCode exception if the response status code is not STATUS_SUCCESS' do
|
591
|
+
allow(read_andx_response).to receive(:status_code).and_return(WindowsError::NTStatus::STATUS_OBJECT_NAME_NOT_FOUND)
|
592
|
+
expect { file.send_recv_read }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
|
593
|
+
end
|
594
|
+
|
595
|
+
it 'returns the expected string' do
|
596
|
+
expect(file.send_recv_read).to eq(read_data)
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
describe '#send_recv_write' do
|
601
|
+
let(:write_data) { 'write data' }
|
602
|
+
let(:request) { double('Request') }
|
603
|
+
let(:raw_response) { double('fake raw response data') }
|
604
|
+
let(:write_andx_response) {
|
605
|
+
res = RubySMB::SMB1::Packet::WriteAndxResponse.new
|
606
|
+
res.parameter_block.count_low = write_data.size
|
607
|
+
res
|
608
|
+
}
|
609
|
+
|
610
|
+
before :example do
|
611
|
+
allow(file).to receive(:write_packet).and_return(request)
|
612
|
+
allow(request).to receive(:set_64_bit_offset)
|
613
|
+
allow(client).to receive(:send_recv).and_return(raw_response)
|
614
|
+
allow(RubySMB::SMB1::Packet::WriteAndxResponse).to receive(:read).with(raw_response).and_return(write_andx_response)
|
615
|
+
end
|
616
|
+
|
617
|
+
it 'reads 0 bytes from offset 0 by default' do
|
618
|
+
expect(file).to receive(:write_packet).with(data: '', offset: 0).once.and_call_original
|
619
|
+
file.send_recv_write
|
620
|
+
end
|
621
|
+
|
622
|
+
it 'writes the data provided as argument' do
|
623
|
+
expect(file).to receive(:write_packet).with(data: write_data, offset: 0).once.and_call_original
|
624
|
+
file.send_recv_write(data: write_data)
|
625
|
+
end
|
626
|
+
|
627
|
+
it 'reads from the offset provided as argument' do
|
628
|
+
offset = 3
|
629
|
+
expect(file).to receive(:write_packet).with(data: '', offset: offset).once.and_call_original
|
630
|
+
file.send_recv_write(offset: offset)
|
631
|
+
end
|
632
|
+
|
633
|
+
it 'sets the 64 bit offset to true' do
|
634
|
+
expect(request).to receive(:set_64_bit_offset).with(true)
|
635
|
+
file.send_recv_write
|
636
|
+
end
|
637
|
+
|
638
|
+
it 'calls Client #send_recv with the expected request' do
|
639
|
+
expect(client).to receive(:send_recv).with(request)
|
640
|
+
file.send_recv_write
|
641
|
+
end
|
642
|
+
|
643
|
+
it 'parses the response as a SMB1 WriteAndxResponse packet' do
|
644
|
+
expect(RubySMB::SMB1::Packet::WriteAndxResponse).to receive(:read).with(raw_response)
|
645
|
+
file.send_recv_write
|
646
|
+
end
|
647
|
+
|
648
|
+
it 'raises an InvalidPacket exception if the response is not valid' do
|
649
|
+
allow(write_andx_response).to receive(:valid?).and_return(false)
|
650
|
+
expect { file.send_recv_write }.to raise_error(RubySMB::Error::InvalidPacket)
|
651
|
+
end
|
652
|
+
|
653
|
+
it 'returns the expected response #count_low value' do
|
654
|
+
expect(file.send_recv_write).to eq(write_data.size)
|
655
|
+
end
|
656
|
+
end
|
468
657
|
end
|
469
658
|
|