ruby_smb 0.0.8 → 0.0.9
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/examples/tree_connect.rb +27 -0
- data/lib/ruby_smb/client.rb +25 -2
- data/lib/ruby_smb/client/authentication.rb +5 -6
- data/lib/ruby_smb/client/negotiation.rb +2 -3
- data/lib/ruby_smb/client/signing.rb +6 -2
- data/lib/ruby_smb/client/tree_connect.rb +86 -0
- data/lib/ruby_smb/generic_packet.rb +1 -1
- data/lib/ruby_smb/smb1.rb +1 -1
- data/lib/ruby_smb/smb1/bit_field.rb +4 -0
- data/lib/ruby_smb/smb1/bit_field/directory_access_mask.rb +38 -0
- data/lib/ruby_smb/smb1/bit_field/file_access_mask.rb +38 -0
- data/lib/ruby_smb/smb1/bit_field/optional_support.rb +19 -0
- data/lib/ruby_smb/smb1/bit_field/tree_connect_flags.rb +18 -0
- data/lib/ruby_smb/smb1/commands.rb +2 -0
- data/lib/ruby_smb/smb1/packet.rb +4 -0
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +34 -0
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +74 -0
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +29 -0
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +30 -0
- data/lib/ruby_smb/smb1/tree.rb +55 -0
- data/lib/ruby_smb/smb2.rb +1 -0
- data/lib/ruby_smb/smb2/bit_field.rb +4 -0
- data/lib/ruby_smb/smb2/bit_field/directory_access_mask.rb +38 -0
- data/lib/ruby_smb/smb2/bit_field/file_access_mask.rb +38 -0
- data/lib/ruby_smb/smb2/bit_field/share_capabailities.rb +21 -0
- data/lib/ruby_smb/smb2/bit_field/share_flags.rb +75 -0
- data/lib/ruby_smb/smb2/packet.rb +5 -0
- data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +27 -0
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +50 -0
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +21 -0
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +22 -0
- data/lib/ruby_smb/smb2/smb2_header.rb +3 -3
- data/lib/ruby_smb/smb2/tree.rb +51 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/ruby_smb.gemspec +1 -1
- data/spec/lib/ruby_smb/client_spec.rb +114 -4
- data/spec/lib/ruby_smb/smb1/bit_field/directory_access_mask_spec.rb +190 -0
- data/spec/lib/ruby_smb/smb1/bit_field/file_access_mask_spec.rb +190 -0
- data/spec/lib/ruby_smb/smb1/bit_field/optional_support_spec.rb +52 -0
- data/spec/lib/ruby_smb/smb1/bit_field/tree_connect_flags_spec.rb +37 -0
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_request_spec.rb +53 -0
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +86 -0
- data/spec/lib/ruby_smb/smb1/packet/tree_disconnect_request_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/packet/tree_disconnect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +55 -0
- data/spec/lib/ruby_smb/smb2/bit_field/directory_access_mask_spec.rb +190 -0
- data/spec/lib/ruby_smb/smb2/bit_field/file_access_mask_spec.rb +190 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_capabilities_spec.rb +54 -0
- data/spec/lib/ruby_smb/smb2/bit_field/share_flags_spec.rb +184 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_request_spec.rb +49 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +57 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_disconnect_request_spec.rb +30 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_disconnect_response_spec.rb +30 -0
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +54 -0
- metadata +63 -6
- metadata.gz.sig +0 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
module Packet
|
4
|
+
|
5
|
+
# An SMB2 TreeConnectResponse Packet as defined in
|
6
|
+
# [2.2.10 SMB2 TREE_CONNECT Response](https://msdn.microsoft.com/en-us/library/cc246499.aspx)
|
7
|
+
class TreeConnectResponse < RubySMB::GenericPacket
|
8
|
+
endian :little
|
9
|
+
smb2_header :smb2_header
|
10
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 16
|
11
|
+
uint8 :share_type, label: 'Share Type', initial_value: 0x01
|
12
|
+
uint8 :reserved, label: 'Reserved Space', initial_value: 0x00
|
13
|
+
share_flags :share_flags
|
14
|
+
share_capabilities :capabilities
|
15
|
+
directory_access_mask :maximal_access, label: 'Maximal Access'
|
16
|
+
|
17
|
+
def initialize_instance
|
18
|
+
super
|
19
|
+
smb2_header.command = RubySMB::SMB2::Commands::TREE_CONNECT
|
20
|
+
smb2_header.flags.reply = 1
|
21
|
+
end
|
22
|
+
|
23
|
+
# Returns the ACCESS_MASK for the Maximal Share Access Rights. The packet
|
24
|
+
# defaults this to a {RubySMB::SMB2::BitField::DirectoryAccessMask}. If it is anything other than
|
25
|
+
# a directory that has been connected to, it will re-cast it as a {RubySMB::SMB2::BitField::FileAccessMask}
|
26
|
+
#
|
27
|
+
# @return [RubySMB::SMB2::BitField::DirectoryAccessMask] if a directory was connected to
|
28
|
+
# @return [RubySMB::SMB2::BitField::FileAccessMask] if anything else was connected to
|
29
|
+
def access_rights
|
30
|
+
if is_directory?
|
31
|
+
self.maximal_access
|
32
|
+
else
|
33
|
+
mask = self.maximal_access.to_binary_s
|
34
|
+
RubySMB::SMB2::BitField::FileAccessMask.read(mask)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Checks if the remote Tree is a directory
|
39
|
+
#
|
40
|
+
# @return [Boolean]
|
41
|
+
def is_directory?
|
42
|
+
self.share_type == 0x01
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
module Packet
|
4
|
+
|
5
|
+
# An SMB2 TreeDisconnectRequest Packet as defined in
|
6
|
+
# [2.2.11 SMB2 TREE_DISCONNECT Request](https://msdn.microsoft.com/en-us/library/cc246500.aspx)
|
7
|
+
class TreeDisconnectRequest < RubySMB::GenericPacket
|
8
|
+
endian :little
|
9
|
+
smb2_header :smb2_header
|
10
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 4
|
11
|
+
|
12
|
+
|
13
|
+
def initialize_instance
|
14
|
+
super
|
15
|
+
smb2_header.command = RubySMB::SMB2::Commands::TREE_DISCONNECT
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
module Packet
|
4
|
+
|
5
|
+
# An SMB2 TreeDisconnectResponse Packet as defined in
|
6
|
+
# [2.2.12 SMB2 TREE_DISCONNECT Response](https://msdn.microsoft.com/en-us/library/cc246501.aspx)
|
7
|
+
class TreeDisconnectResponse < RubySMB::GenericPacket
|
8
|
+
endian :little
|
9
|
+
smb2_header :smb2_header
|
10
|
+
uint16 :structure_size, label: 'Structure Size', initial_value: 4
|
11
|
+
|
12
|
+
|
13
|
+
def initialize_instance
|
14
|
+
super
|
15
|
+
smb2_header.command = RubySMB::SMB2::Commands::TREE_DISCONNECT
|
16
|
+
smb2_header.flags.reply = 1
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -11,9 +11,9 @@ module RubySMB
|
|
11
11
|
uint16 :command, label: 'Command'
|
12
12
|
uint16 :credits, label: 'Credit Request/Response'
|
13
13
|
smb2_header_flags :flags, label: 'Flags'
|
14
|
-
uint32 :next_command, label: 'Command Chain Offset',
|
15
|
-
uint64 :message_id, label: 'Message ID'
|
16
|
-
uint32 :process_id, label: 'Process ID',
|
14
|
+
uint32 :next_command, label: 'Command Chain Offset', initial_value: 0
|
15
|
+
uint64 :message_id, label: 'Message ID', initial_value: 0
|
16
|
+
uint32 :process_id, label: 'Process ID', initial_value: 0x0000feff
|
17
17
|
uint32 :tree_id, label: 'Tree ID'
|
18
18
|
uint64 :session_id, label: 'Session ID'
|
19
19
|
string :signature, label: 'Signature', length: 16
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module RubySMB
|
2
|
+
module SMB2
|
3
|
+
|
4
|
+
# An SMB2 connected remote Tree, as returned by a
|
5
|
+
# [RubySMB::SMB2::Packet::TreeConnectRequest]
|
6
|
+
class Tree
|
7
|
+
|
8
|
+
# The client this Tree is connected through
|
9
|
+
# @!attribute [rw] client
|
10
|
+
# @return [RubySMB::Client]
|
11
|
+
attr_accessor :client
|
12
|
+
|
13
|
+
# The current Maximal Share Permissions
|
14
|
+
# @!attribute [rw] permissions
|
15
|
+
# @return [RubySMB::SMB2::BitField::DirectoryAccessMask]
|
16
|
+
attr_accessor :permissions
|
17
|
+
|
18
|
+
# The share path associated with this Tree
|
19
|
+
# @!attribute [rw] share
|
20
|
+
# @return [String]
|
21
|
+
attr_accessor :share
|
22
|
+
|
23
|
+
# The Tree ID for this Tree
|
24
|
+
# @!attribute [rw] id
|
25
|
+
# @return [Integer]
|
26
|
+
attr_accessor :id
|
27
|
+
|
28
|
+
def initialize(client:, share:, response:)
|
29
|
+
@client = client
|
30
|
+
@share = share
|
31
|
+
@id = response.smb2_header.tree_id
|
32
|
+
@permissions = response.maximal_access
|
33
|
+
end
|
34
|
+
|
35
|
+
# Disconnects this Tree from the current session
|
36
|
+
#
|
37
|
+
# @return [WindowsError::ErrorCode] the NTStatus sent back by the server.
|
38
|
+
def disconnect!
|
39
|
+
request = RubySMB::SMB2::Packet::TreeDisconnectRequest.new
|
40
|
+
request.smb2_header.tree_id = self.id
|
41
|
+
request.smb2_header.credit_charge = 1
|
42
|
+
request.smb2_header.credits = 256
|
43
|
+
raw_response = self.client.send_recv(request)
|
44
|
+
response = RubySMB::SMB2::Packet::TreeDisconnectResponse.read(raw_response)
|
45
|
+
response.status_code
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/ruby_smb/version.rb
CHANGED
data/ruby_smb.gemspec
CHANGED
@@ -31,7 +31,7 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_development_dependency 'rake'
|
32
32
|
spec.add_development_dependency 'yard'
|
33
33
|
|
34
|
-
spec.add_runtime_dependency 'rubyntlm'
|
34
|
+
spec.add_runtime_dependency 'rubyntlm'
|
35
35
|
spec.add_runtime_dependency 'bit-struct'
|
36
36
|
spec.add_runtime_dependency 'windows_error'
|
37
37
|
spec.add_runtime_dependency 'bindata'
|
@@ -49,8 +49,8 @@ RSpec.describe RubySMB::Client do
|
|
49
49
|
end
|
50
50
|
|
51
51
|
describe '#send_recv' do
|
52
|
-
let(:smb1_request) { RubySMB::SMB1::Packet::
|
53
|
-
let(:smb2_request) { RubySMB::SMB2::Packet::
|
52
|
+
let(:smb1_request) { RubySMB::SMB1::Packet::TreeConnectRequest.new }
|
53
|
+
let(:smb2_request) { RubySMB::SMB2::Packet::TreeConnectRequest.new }
|
54
54
|
|
55
55
|
before(:each) do
|
56
56
|
expect(dispatcher).to receive(:send_packet).and_return(nil)
|
@@ -570,7 +570,12 @@ RSpec.describe RubySMB::Client do
|
|
570
570
|
|
571
571
|
context 'Signing' do
|
572
572
|
describe '#smb2_sign' do
|
573
|
-
let(:request1) {
|
573
|
+
let(:request1) {
|
574
|
+
packet = RubySMB::SMB2::Packet::SessionSetupRequest.new
|
575
|
+
packet.smb2_header.flags.signed = 1
|
576
|
+
packet.smb2_header.signature = "\x00" * 16
|
577
|
+
packet
|
578
|
+
}
|
574
579
|
let(:fake_hmac) { "\x31\x07\x78\x3e\x35\xd7\x0e\x89\x08\x43\x8a\x18\xcd\x78\x52\x39".force_encoding("ASCII-8BIT") }
|
575
580
|
|
576
581
|
context 'if signing is required and we have a session key' do
|
@@ -610,7 +615,7 @@ RSpec.describe RubySMB::Client do
|
|
610
615
|
smb1_client.signing_required = true
|
611
616
|
raw = request1.to_binary_s
|
612
617
|
adjusted_request = RubySMB::SMB1::Packet::SessionSetupRequest.read(raw)
|
613
|
-
adjusted_request.smb_header.security_features = smb1_client.sequence_counter
|
618
|
+
adjusted_request.smb_header.security_features = [smb1_client.sequence_counter].pack('Q<')
|
614
619
|
expect(OpenSSL::Digest::MD5).to receive(:digest).with(smb1_client.session_key + adjusted_request.to_binary_s).and_return(fake_sig)
|
615
620
|
expect(smb1_client.smb1_sign(request1).smb_header.security_features).to eq fake_sig
|
616
621
|
end
|
@@ -634,5 +639,110 @@ RSpec.describe RubySMB::Client do
|
|
634
639
|
end
|
635
640
|
end
|
636
641
|
|
642
|
+
context '#increment_smb_message_id' do
|
643
|
+
let(:request_packet) { RubySMB::SMB2::Packet::NegotiateRequest.new }
|
637
644
|
|
645
|
+
it 'sets the message_id on the packet header to the client message_id' do
|
646
|
+
id = client.smb2_message_id
|
647
|
+
expect(client.increment_smb_message_id(request_packet).smb2_header.message_id).to eq id
|
648
|
+
end
|
649
|
+
|
650
|
+
it 'increments the client message id' do
|
651
|
+
client.smb2_message_id = 1
|
652
|
+
expect{ client.increment_smb_message_id(request_packet) }.to change{ client.smb2_message_id}.by(1)
|
653
|
+
end
|
654
|
+
end
|
655
|
+
|
656
|
+
context 'connecting to a share' do
|
657
|
+
let(:path) { '\\192.168.1.1\example' }
|
658
|
+
let(:tree_id) { 2049 }
|
659
|
+
context 'with SMB1' do
|
660
|
+
let(:request) { RubySMB::SMB1::Packet::TreeConnectRequest.new }
|
661
|
+
let(:response) {
|
662
|
+
packet = RubySMB::SMB1::Packet::TreeConnectResponse.new
|
663
|
+
packet.smb_header.tid = tree_id
|
664
|
+
packet.parameter_block.access_rights.read("\xff\x01\x1f\x00")
|
665
|
+
packet.data_block.service = 'A:'
|
666
|
+
packet
|
667
|
+
}
|
668
|
+
|
669
|
+
describe '#smb1_tree_connect' do
|
670
|
+
it 'builds and sends a TreeconnectRequest for the supplied share' do
|
671
|
+
allow(RubySMB::SMB1::Packet::TreeConnectRequest).to receive(:new).and_return(request)
|
672
|
+
modified_request = request
|
673
|
+
modified_request.data_block.path = path
|
674
|
+
expect(smb1_client).to receive(:send_recv).with(modified_request).and_return(response.to_binary_s)
|
675
|
+
smb1_client.smb1_tree_connect(path)
|
676
|
+
end
|
677
|
+
|
678
|
+
it 'sends the response to #smb1_tree_from_response' do
|
679
|
+
expect(smb1_client).to receive(:send_recv).and_return(response.to_binary_s)
|
680
|
+
expect(smb1_client).to receive(:smb1_tree_from_response).with(path, response)
|
681
|
+
smb1_client.smb1_tree_connect(path)
|
682
|
+
end
|
683
|
+
end
|
684
|
+
|
685
|
+
describe '#smb1_tree_from_response' do
|
686
|
+
it 'raises an InvalidPacket exception if the command is not TREE_CONNECT' do
|
687
|
+
response.smb_header.command = RubySMB::SMB1::Commands::SMB_COM_NEGOTIATE
|
688
|
+
expect{ smb1_client.smb1_tree_from_response(path,response) }.to raise_error(RubySMB::Error::InvalidPacket)
|
689
|
+
end
|
690
|
+
|
691
|
+
it 'raises an UnexpectedStatusCode exception if we do not get STATUS_SUCCESS' do
|
692
|
+
response.smb_header.nt_status = 0xc0000015
|
693
|
+
expect{ smb1_client.smb1_tree_from_response(path,response) }.to raise_error(RubySMB::Error::UnexpectedStatusCode, 'STATUS_NONEXISTENT_SECTOR')
|
694
|
+
end
|
695
|
+
|
696
|
+
it 'creates a new Tree from itself, the share path, and the response packet' do
|
697
|
+
expect(RubySMB::SMB1::Tree).to receive(:new).with(client:smb1_client, share:path, response:response)
|
698
|
+
smb1_client.smb1_tree_from_response(path,response)
|
699
|
+
end
|
700
|
+
end
|
701
|
+
end
|
702
|
+
|
703
|
+
context 'with SMB2' do
|
704
|
+
let(:request) { RubySMB::SMB2::Packet::TreeConnectRequest.new }
|
705
|
+
let(:response) {
|
706
|
+
packet = RubySMB::SMB2::Packet::TreeConnectResponse.new
|
707
|
+
packet.smb2_header.tree_id = tree_id
|
708
|
+
packet.maximal_access.read("\xff\x01\x1f\x00")
|
709
|
+
packet.share_type = 0x01
|
710
|
+
packet
|
711
|
+
}
|
712
|
+
|
713
|
+
describe '#smb2_tree_connect' do
|
714
|
+
it 'builds and sends a TreeconnectRequest for the supplied share' do
|
715
|
+
allow(RubySMB::SMB2::Packet::TreeConnectRequest).to receive(:new).and_return(request)
|
716
|
+
modified_request = request
|
717
|
+
modified_request.encode_path(path)
|
718
|
+
expect(smb2_client).to receive(:send_recv).with(modified_request).and_return(response.to_binary_s)
|
719
|
+
smb2_client.smb2_tree_connect(path)
|
720
|
+
end
|
721
|
+
|
722
|
+
it 'sends the response to #smb2_tree_from_response' do
|
723
|
+
expect(smb2_client).to receive(:send_recv).and_return(response.to_binary_s)
|
724
|
+
expect(smb2_client).to receive(:smb2_tree_from_response).with(path, response)
|
725
|
+
smb2_client.smb2_tree_connect(path)
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
describe '#smb2_tree_from_response' do
|
730
|
+
it 'raises an InvalidPacket exception if the command is not TREE_CONNECT' do
|
731
|
+
response.smb2_header.command = RubySMB::SMB2::Commands::NEGOTIATE
|
732
|
+
expect{ smb2_client.smb2_tree_from_response(path,response) }.to raise_error(RubySMB::Error::InvalidPacket)
|
733
|
+
end
|
734
|
+
|
735
|
+
it 'raises an UnexpectedStatusCode exception if we do not get STATUS_SUCCESS' do
|
736
|
+
response.smb2_header.nt_status = 0xc0000015
|
737
|
+
expect{ smb2_client.smb2_tree_from_response(path,response) }.to raise_error(RubySMB::Error::UnexpectedStatusCode, 'STATUS_NONEXISTENT_SECTOR')
|
738
|
+
end
|
739
|
+
|
740
|
+
it 'creates a new Tree from itself, the share path, and the response packet' do
|
741
|
+
expect(RubySMB::SMB2::Tree).to receive(:new).with(client:smb2_client, share:path, response:response)
|
742
|
+
smb2_client.smb2_tree_from_response(path,response)
|
743
|
+
end
|
744
|
+
end
|
745
|
+
|
746
|
+
end
|
747
|
+
end
|
638
748
|
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
RSpec.describe RubySMB::SMB1::BitField::DirectoryAccessMask do
|
2
|
+
subject(:flags) { described_class.new }
|
3
|
+
|
4
|
+
it { is_expected.to respond_to :read_attr }
|
5
|
+
it { is_expected.to respond_to :delete_child }
|
6
|
+
it { is_expected.to respond_to :traverse }
|
7
|
+
it { is_expected.to respond_to :write_ea }
|
8
|
+
it { is_expected.to respond_to :read_ea }
|
9
|
+
it { is_expected.to respond_to :add_subdir }
|
10
|
+
it { is_expected.to respond_to :add_file }
|
11
|
+
it { is_expected.to respond_to :list }
|
12
|
+
it { is_expected.to respond_to :write_attr }
|
13
|
+
it { is_expected.to respond_to :synchronize }
|
14
|
+
it { is_expected.to respond_to :write_owner }
|
15
|
+
it { is_expected.to respond_to :write_dac }
|
16
|
+
it { is_expected.to respond_to :read_control }
|
17
|
+
it { is_expected.to respond_to :delete_access }
|
18
|
+
it { is_expected.to respond_to :generic_read }
|
19
|
+
it { is_expected.to respond_to :generic_write }
|
20
|
+
it { is_expected.to respond_to :generic_execute }
|
21
|
+
it { is_expected.to respond_to :generic_all }
|
22
|
+
it { is_expected.to respond_to :maximum }
|
23
|
+
it { is_expected.to respond_to :system_security }
|
24
|
+
|
25
|
+
it 'is little endian' do
|
26
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#list' do
|
30
|
+
it 'should be a 1-bit field per the SMB spec' do
|
31
|
+
expect(flags.list).to be_a BinData::Bit1
|
32
|
+
end
|
33
|
+
|
34
|
+
it_behaves_like 'bit field with one flag set', :list, 'V', 0x00000001
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
describe '#add_file' do
|
39
|
+
it 'should be a 1-bit field per the SMB spec' do
|
40
|
+
expect(flags.add_file).to be_a BinData::Bit1
|
41
|
+
end
|
42
|
+
|
43
|
+
it_behaves_like 'bit field with one flag set', :add_file, 'V', 0x00000002
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#add_subdir' do
|
47
|
+
it 'should be a 1-bit field per the SMB spec' do
|
48
|
+
expect(flags.add_subdir).to be_a BinData::Bit1
|
49
|
+
end
|
50
|
+
|
51
|
+
it_behaves_like 'bit field with one flag set', :add_subdir, 'V', 0x00000004
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#read_ea' do
|
55
|
+
it 'should be a 1-bit field per the SMB spec' do
|
56
|
+
expect(flags.read_ea).to be_a BinData::Bit1
|
57
|
+
end
|
58
|
+
|
59
|
+
it_behaves_like 'bit field with one flag set', :read_ea, 'V', 0x00000008
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#write_ea' do
|
63
|
+
it 'should be a 1-bit field per the SMB spec' do
|
64
|
+
expect(flags.write_ea).to be_a BinData::Bit1
|
65
|
+
end
|
66
|
+
|
67
|
+
it_behaves_like 'bit field with one flag set', :write_ea, 'V', 0x00000010
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#traverse' do
|
71
|
+
it 'should be a 1-bit field per the SMB spec' do
|
72
|
+
expect(flags.traverse).to be_a BinData::Bit1
|
73
|
+
end
|
74
|
+
|
75
|
+
it_behaves_like 'bit field with one flag set', :traverse, 'V', 0x00000020
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#delete_child' do
|
79
|
+
it 'should be a 1-bit field per the SMB spec' do
|
80
|
+
expect(flags.delete_child).to be_a BinData::Bit1
|
81
|
+
end
|
82
|
+
|
83
|
+
it_behaves_like 'bit field with one flag set', :delete_child, 'V', 0x00000040
|
84
|
+
end
|
85
|
+
|
86
|
+
describe '#read_attr' do
|
87
|
+
it 'should be a 1-bit field per the SMB spec' do
|
88
|
+
expect(flags.read_attr).to be_a BinData::Bit1
|
89
|
+
end
|
90
|
+
|
91
|
+
it_behaves_like 'bit field with one flag set', :read_attr, 'V', 0x00000080
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#write_attr' do
|
95
|
+
it 'should be a 1-bit field per the SMB spec' do
|
96
|
+
expect(flags.write_attr).to be_a BinData::Bit1
|
97
|
+
end
|
98
|
+
|
99
|
+
it_behaves_like 'bit field with one flag set', :write_attr, 'V', 0x00000100
|
100
|
+
end
|
101
|
+
|
102
|
+
describe '#delete_access' do
|
103
|
+
it 'should be a 1-bit field per the SMB spec' do
|
104
|
+
expect(flags.delete_access).to be_a BinData::Bit1
|
105
|
+
end
|
106
|
+
|
107
|
+
it_behaves_like 'bit field with one flag set', :delete_access, 'V', 0x00010000
|
108
|
+
end
|
109
|
+
|
110
|
+
describe '#read_control' do
|
111
|
+
it 'should be a 1-bit field per the SMB spec' do
|
112
|
+
expect(flags.read_control).to be_a BinData::Bit1
|
113
|
+
end
|
114
|
+
|
115
|
+
it_behaves_like 'bit field with one flag set', :read_control, 'V', 0x00020000
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#write_dac' do
|
119
|
+
it 'should be a 1-bit field per the SMB spec' do
|
120
|
+
expect(flags.write_dac).to be_a BinData::Bit1
|
121
|
+
end
|
122
|
+
|
123
|
+
it_behaves_like 'bit field with one flag set', :write_dac, 'V', 0x00040000
|
124
|
+
end
|
125
|
+
|
126
|
+
describe '#write_owner' do
|
127
|
+
it 'should be a 1-bit field per the SMB spec' do
|
128
|
+
expect(flags.write_owner).to be_a BinData::Bit1
|
129
|
+
end
|
130
|
+
|
131
|
+
it_behaves_like 'bit field with one flag set', :write_owner, 'V', 0x00080000
|
132
|
+
end
|
133
|
+
|
134
|
+
describe '#synchronize' do
|
135
|
+
it 'should be a 1-bit field per the SMB spec' do
|
136
|
+
expect(flags.synchronize).to be_a BinData::Bit1
|
137
|
+
end
|
138
|
+
|
139
|
+
it_behaves_like 'bit field with one flag set', :synchronize, 'V', 0x00100000
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '#system_security' do
|
143
|
+
it 'should be a 1-bit field per the SMB spec' do
|
144
|
+
expect(flags.system_security).to be_a BinData::Bit1
|
145
|
+
end
|
146
|
+
|
147
|
+
it_behaves_like 'bit field with one flag set', :system_security, 'V', 0x01000000
|
148
|
+
end
|
149
|
+
|
150
|
+
describe '#maximum' do
|
151
|
+
it 'should be a 1-bit field per the SMB spec' do
|
152
|
+
expect(flags.maximum).to be_a BinData::Bit1
|
153
|
+
end
|
154
|
+
|
155
|
+
it_behaves_like 'bit field with one flag set', :maximum, 'V', 0x02000000
|
156
|
+
end
|
157
|
+
|
158
|
+
describe '#generic_all' do
|
159
|
+
it 'should be a 1-bit field per the SMB spec' do
|
160
|
+
expect(flags.generic_all).to be_a BinData::Bit1
|
161
|
+
end
|
162
|
+
|
163
|
+
it_behaves_like 'bit field with one flag set', :generic_all, 'V', 0x10000000
|
164
|
+
end
|
165
|
+
|
166
|
+
describe '#generic_execute' do
|
167
|
+
it 'should be a 1-bit field per the SMB spec' do
|
168
|
+
expect(flags.generic_execute).to be_a BinData::Bit1
|
169
|
+
end
|
170
|
+
|
171
|
+
it_behaves_like 'bit field with one flag set', :generic_execute, 'V', 0x20000000
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '#generic_write' do
|
175
|
+
it 'should be a 1-bit field per the SMB spec' do
|
176
|
+
expect(flags.generic_write).to be_a BinData::Bit1
|
177
|
+
end
|
178
|
+
|
179
|
+
it_behaves_like 'bit field with one flag set', :generic_write, 'V', 0x40000000
|
180
|
+
end
|
181
|
+
|
182
|
+
describe '#generic_read' do
|
183
|
+
it 'should be a 1-bit field per the SMB spec' do
|
184
|
+
expect(flags.generic_read).to be_a BinData::Bit1
|
185
|
+
end
|
186
|
+
|
187
|
+
it_behaves_like 'bit field with one flag set', :generic_read, 'V', 0x80000000
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|