ruby_smb 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|