ruby_smb 3.1.1 → 3.1.4
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 +1 -2
- data/examples/file_server.rb +6 -61
- data/examples/virtual_file_server.rb +91 -0
- data/lib/ruby_smb/client/authentication.rb +12 -2
- data/lib/ruby_smb/client/negotiation.rb +2 -0
- data/lib/ruby_smb/client.rb +8 -2
- data/lib/ruby_smb/error.rb +4 -0
- data/lib/ruby_smb/fscc/file_information/file_access_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_alignment_information.rb +45 -0
- data/lib/ruby_smb/fscc/file_information/file_all_information.rb +23 -0
- data/lib/ruby_smb/fscc/file_information/file_basic_information.rb +20 -0
- data/lib/ruby_smb/fscc/file_information/file_both_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_ea_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_information/file_full_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_id_both_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_id_full_directory_information.rb +3 -3
- data/lib/ruby_smb/fscc/file_information/file_internal_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_mode_information.rb +29 -0
- data/lib/ruby_smb/fscc/file_information/file_name_information.rb +16 -0
- data/lib/ruby_smb/fscc/file_information/file_names_information.rb +1 -1
- data/lib/ruby_smb/fscc/file_information/file_normalized_name_information.rb +16 -0
- data/lib/ruby_smb/fscc/file_information/file_position_information.rb +15 -0
- data/lib/ruby_smb/fscc/file_information/file_rename_information.rb +1 -1
- data/lib/ruby_smb/fscc/file_information/file_standard_information.rb +20 -0
- data/lib/ruby_smb/fscc/file_information/file_stream_information.rb +3 -0
- data/lib/ruby_smb/fscc/file_information.rb +41 -8
- data/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information.rb +1 -0
- data/lib/ruby_smb/fscc/file_system_information.rb +4 -0
- data/lib/ruby_smb/gss/provider/ntlm.rb +16 -3
- data/lib/ruby_smb/gss/provider.rb +10 -1
- data/lib/ruby_smb/gss.rb +1 -0
- data/lib/ruby_smb/ntlm/client.rb +74 -0
- data/lib/ruby_smb/ntlm.rb +1 -0
- data/lib/ruby_smb/server/cli.rb +121 -0
- data/lib/ruby_smb/server/server_client/session_setup.rb +4 -2
- data/lib/ruby_smb/server/server_client.rb +9 -1
- data/lib/ruby_smb/server/session.rb +5 -1
- data/lib/ruby_smb/server/share/provider/disk/processor/close.rb +9 -5
- data/lib/ruby_smb/server/share/provider/disk/processor/create.rb +2 -2
- data/lib/ruby_smb/server/share/provider/disk/processor/query.rb +2 -2
- data/lib/ruby_smb/server/share/provider/disk/processor/read.rb +15 -14
- data/lib/ruby_smb/server/share/provider/disk/processor.rb +76 -12
- data/lib/ruby_smb/server/share/provider/disk.rb +8 -2
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_file.rb +85 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_pathname.rb +196 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk/virtual_stat.rb +175 -0
- data/lib/ruby_smb/server/share/provider/virtual_disk.rb +116 -0
- data/lib/ruby_smb/server/share/provider.rb +1 -0
- data/lib/ruby_smb/server.rb +14 -3
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +11 -0
- data/lib/ruby_smb/smb2/tree.rb +1 -0
- data/lib/ruby_smb/version.rb +1 -1
- data/spec/lib/ruby_smb/fscc/file_information/file_access_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_alignment_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_all_information_spec.rb +61 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_basic_information_spec.rb +41 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_both_directory_information_spec.rb +59 -10
- data/spec/lib/ruby_smb/fscc/file_information/file_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_ea_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_full_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_id_both_directory_information_spec.rb +63 -10
- data/spec/lib/ruby_smb/fscc/file_information/file_id_full_directory_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_internal_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_mode_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_name_information_spec.rb +44 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_names_information_spec.rb +30 -12
- data/spec/lib/ruby_smb/fscc/file_information/file_network_open_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_normalized_name_information_spec.rb +44 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_position_information_spec.rb +21 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_rename_information_spec.rb +1 -1
- data/spec/lib/ruby_smb/fscc/file_information/file_standard_information_spec.rb +41 -0
- data/spec/lib/ruby_smb/fscc/file_information/file_stream_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_information_spec.rb +14 -0
- data/spec/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information_spec.rb +46 -0
- data/spec/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information_spec.rb +51 -0
- data/spec/lib/ruby_smb/fscc/file_system_information_spec.rb +14 -0
- data/spec/lib/ruby_smb/ntlm/client/session_spec.rb +114 -0
- data/spec/lib/ruby_smb/ntlm/client_spec.rb +36 -0
- data/spec/lib/ruby_smb/server/server_client_spec.rb +15 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk/virtual_pathname_spec.rb +581 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk/virtual_stat_spec.rb +207 -0
- data/spec/lib/ruby_smb/server/share/provider/virtual_disk_spec.rb +122 -0
- data.tar.gz.sig +0 -0
- metadata +63 -2
- metadata.gz.sig +0 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
require 'ruby_smb/server/share/provider/disk'
|
|
2
|
+
require 'ruby_smb/server/share/provider/virtual_disk/virtual_file'
|
|
3
|
+
require 'ruby_smb/server/share/provider/virtual_disk/virtual_pathname'
|
|
4
|
+
require 'ruby_smb/server/share/provider/virtual_disk/virtual_stat'
|
|
5
|
+
|
|
6
|
+
module RubySMB
|
|
7
|
+
class Server
|
|
8
|
+
module Share
|
|
9
|
+
module Provider
|
|
10
|
+
# This is a share provider that exposes a virtual file system whose entries do not exist on disk.
|
|
11
|
+
# @since 3.1.1
|
|
12
|
+
class VirtualDisk < Disk
|
|
13
|
+
HASH_METHODS = %i[ [] each each_key each_value keys length values ]
|
|
14
|
+
private_constant :HASH_METHODS
|
|
15
|
+
|
|
16
|
+
# @param [String] name The name of this share.
|
|
17
|
+
def initialize(name)
|
|
18
|
+
@vfs = {}
|
|
19
|
+
super(name, add(VirtualPathname.new(self, File::SEPARATOR)))
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Add a dynamic file to the virtual file system. A dynamic file is one whose contents are generated by the
|
|
23
|
+
# specified block. The contents are generated when the share is opened.
|
|
24
|
+
#
|
|
25
|
+
# @param [String] path The path of the file to add, relative to the share root.
|
|
26
|
+
# @param [File::Stat] stat An explicit stat object describing the file.
|
|
27
|
+
# @yield The content generation routine.
|
|
28
|
+
# @yieldreturn [String] The generated file content.
|
|
29
|
+
def add_dynamic_file(path, stat: nil, &block)
|
|
30
|
+
raise ArgumentError.new('a block must be specified for dynamic files') unless block_given?
|
|
31
|
+
path = VirtualPathname.cleanpath(path)
|
|
32
|
+
path = File::SEPARATOR + path unless path.start_with?(File::SEPARATOR)
|
|
33
|
+
raise ArgumentError.new('must be a file') if stat && !stat.file?
|
|
34
|
+
|
|
35
|
+
vf = VirtualDynamicFile.new(self, path, stat: stat, &block)
|
|
36
|
+
add(vf)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Add a mapped file to the virtual file system. A mapped file is one who is backed by an entry on
|
|
40
|
+
# disk. The path need not be present, but if it does exist, it must be a file.
|
|
41
|
+
#
|
|
42
|
+
# @param [String] path The path of the file to add, relative to the share root.
|
|
43
|
+
# @param [String, Pathname] mapped_path The path on the local file system to map into the virtual file system.
|
|
44
|
+
def add_mapped_file(path, mapped_path)
|
|
45
|
+
path = VirtualPathname.cleanpath(path)
|
|
46
|
+
path = File::SEPARATOR + path unless path.start_with?(File::SEPARATOR)
|
|
47
|
+
|
|
48
|
+
vf = VirtualMappedFile.new(self, path, mapped_path)
|
|
49
|
+
add(vf)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# Add a static file to the virtual file system. A static file is one whose contents are known at creation time
|
|
53
|
+
# and do not change. If *content* is a file-like object that responds to #read, the data will be read using
|
|
54
|
+
# that method. Likewise, if *content* has a #stat attribute and *stat* was not specified, then the value of
|
|
55
|
+
# content's #stat attribute will be used.
|
|
56
|
+
#
|
|
57
|
+
# @param [String] path The path of the file to add, relative to the share root.
|
|
58
|
+
# @param [String, #read, #stat] content The static content to add.
|
|
59
|
+
# @param [File::Stat] stat An explicit stat object describing the file.
|
|
60
|
+
def add_static_file(path, content, stat: nil)
|
|
61
|
+
path = VirtualPathname.cleanpath(path)
|
|
62
|
+
path = File::SEPARATOR + path unless path.start_with?(File::SEPARATOR)
|
|
63
|
+
raise ArgumentError.new('must be a file') if stat && !stat.file?
|
|
64
|
+
|
|
65
|
+
stat = content.stat if content.respond_to?(:stat) && stat.nil?
|
|
66
|
+
content = content.read if content.respond_to?(:read)
|
|
67
|
+
vf = VirtualStaticFile.new(self, path, content, stat: stat)
|
|
68
|
+
add(vf)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def add(virtual_pathname)
|
|
72
|
+
raise ArgumentError.new('paths must be absolute') unless virtual_pathname.absolute?
|
|
73
|
+
|
|
74
|
+
path = virtual_pathname.to_s
|
|
75
|
+
raise ArgumentError.new('paths must be normalized') unless VirtualPathname.cleanpath(path) == path
|
|
76
|
+
|
|
77
|
+
path_parts = path.split(VirtualPathname::SEPARATOR)
|
|
78
|
+
2.upto(path_parts.length - 1) do |idx|
|
|
79
|
+
ancestor = path_parts[0...idx].join(path[VirtualPathname::SEPARATOR])
|
|
80
|
+
next if @vfs[ancestor]&.directory?
|
|
81
|
+
|
|
82
|
+
@vfs[ancestor] = VirtualPathname.new(self, ancestor, stat: VirtualStat.new(directory?: true))
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
@vfs[path] = virtual_pathname
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def new_processor(server_client, session)
|
|
89
|
+
scoped_virtual_disk = self.class.new(@name)
|
|
90
|
+
@vfs.each_value do |path|
|
|
91
|
+
path = path.dup
|
|
92
|
+
path.virtual_disk = scoped_virtual_disk if path.is_a?(VirtualPathname)
|
|
93
|
+
path = path.generate(server_client, session) if path.is_a?(VirtualDynamicFile)
|
|
94
|
+
scoped_virtual_disk.add(path)
|
|
95
|
+
end
|
|
96
|
+
self.class::Processor.new(scoped_virtual_disk, server_client, session)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
private
|
|
100
|
+
|
|
101
|
+
def method_missing(symbol, *args)
|
|
102
|
+
if HASH_METHODS.include?(symbol)
|
|
103
|
+
return @vfs.send(symbol, *args)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
raise NoMethodError, "undefined method `#{symbol}' for #{self.class}"
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def respond_to_missing?(symbol, include_private = false)
|
|
110
|
+
HASH_METHODS.include?(symbol)
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
data/lib/ruby_smb/server.rb
CHANGED
|
@@ -6,6 +6,7 @@ module RubySMB
|
|
|
6
6
|
# Currently, the server only supports negotiating and authenticating requests. No other server functionality is
|
|
7
7
|
# available at this time. The negotiating and authentication is supported for SMB versions 1 through 3.1.1.
|
|
8
8
|
class Server
|
|
9
|
+
require 'ruby_smb/server/cli'
|
|
9
10
|
require 'ruby_smb/server/server_client'
|
|
10
11
|
require 'ruby_smb/server/session'
|
|
11
12
|
require 'ruby_smb/server/share'
|
|
@@ -14,8 +15,10 @@ module RubySMB
|
|
|
14
15
|
Connection = Struct.new(:client, :thread)
|
|
15
16
|
|
|
16
17
|
# @param server_sock the socket on which the server should listen
|
|
17
|
-
# @param [Gss::Provider] the authentication provider
|
|
18
|
-
|
|
18
|
+
# @param [Gss::Provider] gss_provider the authentication provider
|
|
19
|
+
# @param [::Logger] logger the logger to use for diagnostic messages
|
|
20
|
+
# @param thread_factory a block to create threads for serving clients
|
|
21
|
+
def initialize(server_sock: nil, gss_provider: nil, logger: nil, thread_factory: nil)
|
|
19
22
|
server_sock = ::TCPServer.new(445) if server_sock.nil?
|
|
20
23
|
|
|
21
24
|
@guid = Random.new.bytes(16)
|
|
@@ -36,6 +39,14 @@ module RubySMB
|
|
|
36
39
|
@logger = logger
|
|
37
40
|
end
|
|
38
41
|
|
|
42
|
+
if thread_factory.nil?
|
|
43
|
+
# the default thread factory uses Ruby's standard Thread#new
|
|
44
|
+
thread_factory = Proc.new do |_server_client, &block|
|
|
45
|
+
Thread.new(&block)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
@thread_factory = thread_factory
|
|
49
|
+
|
|
39
50
|
# share name => provider instance
|
|
40
51
|
@shares = {
|
|
41
52
|
'IPC$' => Share::Provider::IpcPipe.new
|
|
@@ -53,7 +64,7 @@ module RubySMB
|
|
|
53
64
|
loop do
|
|
54
65
|
sock = @socket.accept
|
|
55
66
|
server_client = ServerClient.new(self, RubySMB::Dispatcher::Socket.new(sock, read_timeout: nil))
|
|
56
|
-
@connections << Connection.new(server_client,
|
|
67
|
+
@connections << Connection.new(server_client, @thread_factory.call(server_client) { server_client.run })
|
|
57
68
|
|
|
58
69
|
break unless block.nil? || block.call(server_client)
|
|
59
70
|
end
|
|
@@ -40,6 +40,17 @@ module RubySMB
|
|
|
40
40
|
parameter_block :parameter_block
|
|
41
41
|
data_block :data_block
|
|
42
42
|
|
|
43
|
+
# Takes the specified security buffer string and sets it in the {RubySMB::SMB1::Packet::SessionSetupRequest::DataBlock#security_blob}
|
|
44
|
+
# field. It also automatically sets the length in
|
|
45
|
+
# {RubySMB::SMB1::Packet::SessionSetupRequest::ParameterBlock#security_blob_length}
|
|
46
|
+
#
|
|
47
|
+
# @param buffer [String] the security buffer
|
|
48
|
+
# @return [void]
|
|
49
|
+
def set_security_buffer(buffer)
|
|
50
|
+
parameter_block.security_blob_length = buffer.length
|
|
51
|
+
data_block.security_blob = buffer
|
|
52
|
+
end
|
|
53
|
+
|
|
43
54
|
# Takes an NTLM Type 1 Message and creates the GSS Security Blob
|
|
44
55
|
# for it and sets it in the {RubySMB::SMB1::Packet::SessionSetupRequest::DataBlock#security_blob}
|
|
45
56
|
# field. It also automatically sets the length in
|
data/lib/ruby_smb/smb2/tree.rb
CHANGED
data/lib/ruby_smb/version.rb
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileAccessInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_ACCESS_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :access_flags }
|
|
12
|
+
|
|
13
|
+
it 'is little endian' do
|
|
14
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'tracks the access flags in a Uint32 field' do
|
|
18
|
+
expect(struct.access_flags).to be_a BinData::Uint32le
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileAlignmentInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_ALIGNMENT_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :alignment_requirement }
|
|
12
|
+
|
|
13
|
+
it 'is little endian' do
|
|
14
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'tracks the alignment requirement in a Uint32 field' do
|
|
18
|
+
expect(struct.alignment_requirement).to be_a BinData::Uint32le
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileAllInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_ALL_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :basic_information }
|
|
12
|
+
it { should respond_to :standard_information }
|
|
13
|
+
it { should respond_to :internal_information }
|
|
14
|
+
it { should respond_to :ea_information }
|
|
15
|
+
it { should respond_to :access_information }
|
|
16
|
+
it { should respond_to :position_information }
|
|
17
|
+
it { should respond_to :mode_information }
|
|
18
|
+
it { should respond_to :alignment_information }
|
|
19
|
+
it { should respond_to :name_information }
|
|
20
|
+
|
|
21
|
+
it 'is little endian' do
|
|
22
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'tracks the basic information in a FileBasicInformation field' do
|
|
26
|
+
expect(struct.basic_information).to be_a RubySMB::Fscc::FileInformation::FileBasicInformation
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'tracks the standard information in a FileStandardInformation field' do
|
|
30
|
+
expect(struct.standard_information).to be_a RubySMB::Fscc::FileInformation::FileStandardInformation
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'tracks the internal information in a FileInternalInformation field' do
|
|
34
|
+
expect(struct.internal_information).to be_a RubySMB::Fscc::FileInformation::FileInternalInformation
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'tracks the ea information in a FileEaInformation field' do
|
|
38
|
+
expect(struct.ea_information).to be_a RubySMB::Fscc::FileInformation::FileEaInformation
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it 'tracks the access information in a FileAccessInformation field' do
|
|
42
|
+
expect(struct.access_information).to be_a RubySMB::Fscc::FileInformation::FileAccessInformation
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it 'tracks the position information in a FilePositionInformation field' do
|
|
46
|
+
expect(struct.position_information).to be_a RubySMB::Fscc::FileInformation::FilePositionInformation
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'tracks the mode information in a FileModeInformation field' do
|
|
50
|
+
expect(struct.mode_information).to be_a RubySMB::Fscc::FileInformation::FileModeInformation
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
it 'tracks the alignment information in a FileAlignmentInformation field' do
|
|
54
|
+
expect(struct.alignment_information).to be_a RubySMB::Fscc::FileInformation::FileAlignmentInformation
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it 'tracks the name information in a FileNameInformation field' do
|
|
58
|
+
expect(struct.name_information).to be_a RubySMB::Fscc::FileInformation::FileNameInformation
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileBasicInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_BASIC_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :create_time }
|
|
12
|
+
it { should respond_to :last_access }
|
|
13
|
+
it { should respond_to :last_write }
|
|
14
|
+
it { should respond_to :last_change }
|
|
15
|
+
it { should respond_to :file_attributes }
|
|
16
|
+
|
|
17
|
+
it 'is little endian' do
|
|
18
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it 'tracks the create time in a FileTime field' do
|
|
22
|
+
expect(struct.create_time).to be_a RubySMB::Field::FileTime
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it 'tracks the last access time in a FileTime field' do
|
|
26
|
+
expect(struct.last_access).to be_a RubySMB::Field::FileTime
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'tracks the last write time in a FileTime field' do
|
|
30
|
+
expect(struct.last_write).to be_a RubySMB::Field::FileTime
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it 'tracks the last modified time in a FileTime field' do
|
|
34
|
+
expect(struct.last_change).to be_a RubySMB::Field::FileTime
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'tracks the file attributes in a FileAttributes field' do
|
|
38
|
+
expect(struct.file_attributes).to be_a RubySMB::Fscc::FileAttributes
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
end
|
|
@@ -27,6 +27,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileBothDirectoryInformation do
|
|
|
27
27
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
it 'tracks the next offset in a Uint32 field' do
|
|
31
|
+
expect(struct.next_offset).to be_a BinData::Uint32le
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it 'tracks the file index in a Uint32 field' do
|
|
35
|
+
expect(struct.file_index).to be_a BinData::Uint32le
|
|
36
|
+
end
|
|
37
|
+
|
|
30
38
|
it 'tracks the creation time in a Filetime field' do
|
|
31
39
|
expect(struct.create_time).to be_a RubySMB::Field::FileTime
|
|
32
40
|
end
|
|
@@ -43,6 +51,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileBothDirectoryInformation do
|
|
|
43
51
|
expect(struct.last_change).to be_a RubySMB::Field::FileTime
|
|
44
52
|
end
|
|
45
53
|
|
|
54
|
+
it 'tracks the file size in a Int64 field' do
|
|
55
|
+
expect(struct.end_of_file).to be_a BinData::Int64le
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it 'tracks the allocation size in a Int64 field' do
|
|
59
|
+
expect(struct.allocation_size).to be_a BinData::Int64le
|
|
60
|
+
end
|
|
61
|
+
|
|
46
62
|
it 'contains the file attributes of the file' do
|
|
47
63
|
expect(struct.file_attributes).to be_a RubySMB::Fscc::FileAttributes
|
|
48
64
|
end
|
|
@@ -52,20 +68,53 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileBothDirectoryInformation do
|
|
|
52
68
|
expect(struct.file_name_length).to eq struct.file_name.do_num_bytes
|
|
53
69
|
end
|
|
54
70
|
|
|
55
|
-
it '
|
|
56
|
-
|
|
57
|
-
struct.file_name = name
|
|
58
|
-
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
71
|
+
it 'tracks the extended attributes size in a Uint32 field' do
|
|
72
|
+
expect(struct.ea_size).to be_a BinData::Uint32le
|
|
59
73
|
end
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
|
|
75
|
+
it 'tracks the short name length in a Uint8 field' do
|
|
76
|
+
expect(struct.short_name_length).to be_a BinData::Uint8
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
it 'tracks the short name in a String16 field' do
|
|
80
|
+
expect(struct.short_name).to be_a RubySMB::Field::String16
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
it 'tracks the file name in a String16 field' do
|
|
84
|
+
expect(struct.file_name).to be_a RubySMB::Field::String16
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe '#short_name' do
|
|
88
|
+
it 'automatically encodes the short name in UTF-16LE' do
|
|
89
|
+
name = 'Hello_world.'
|
|
90
|
+
struct.short_name = name
|
|
91
|
+
expect(struct.short_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
it 'is always exactly 24 bytes in length' do
|
|
95
|
+
struct.short_name = ''
|
|
96
|
+
expect(struct.short_name.num_bytes).to eq 24
|
|
97
|
+
struct.short_name = 'Hello_world.'
|
|
98
|
+
expect(struct.short_name.num_bytes).to eq 24
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe '#file_name' do
|
|
103
|
+
it 'automatically encodes the file name in UTF-16LE' do
|
|
63
104
|
name = 'Hello_world.txt'
|
|
64
105
|
struct.file_name = name
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
106
|
+
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe 'reading in from a blob' do
|
|
110
|
+
it 'uses the file_name_length to know when to stop reading' do
|
|
111
|
+
name = 'Hello_world.txt'
|
|
112
|
+
struct.file_name = name
|
|
113
|
+
blob = struct.to_binary_s
|
|
114
|
+
blob << 'AAAA'
|
|
115
|
+
new_from_blob = described_class.read(blob)
|
|
116
|
+
expect(new_from_blob.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
117
|
+
end
|
|
69
118
|
end
|
|
70
119
|
end
|
|
71
120
|
end
|
|
@@ -24,6 +24,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileDirectoryInformation do
|
|
|
24
24
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
25
25
|
end
|
|
26
26
|
|
|
27
|
+
it 'tracks the next offset in a Uint32 field' do
|
|
28
|
+
expect(struct.next_offset).to be_a BinData::Uint32le
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'tracks the file index in a Uint32 field' do
|
|
32
|
+
expect(struct.file_index).to be_a BinData::Uint32le
|
|
33
|
+
end
|
|
34
|
+
|
|
27
35
|
it 'tracks the creation time in a Filetime field' do
|
|
28
36
|
expect(struct.create_time).to be_a RubySMB::Field::FileTime
|
|
29
37
|
end
|
|
@@ -40,6 +48,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileDirectoryInformation do
|
|
|
40
48
|
expect(struct.last_change).to be_a RubySMB::Field::FileTime
|
|
41
49
|
end
|
|
42
50
|
|
|
51
|
+
it 'tracks the file size in a Int64 field' do
|
|
52
|
+
expect(struct.end_of_file).to be_a BinData::Int64le
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'tracks the allocation size in a Int64 field' do
|
|
56
|
+
expect(struct.allocation_size).to be_a BinData::Int64le
|
|
57
|
+
end
|
|
58
|
+
|
|
43
59
|
it 'contains the file attributes of the file' do
|
|
44
60
|
expect(struct.file_attributes).to be_a RubySMB::Fscc::FileAttributes
|
|
45
61
|
end
|
|
@@ -49,20 +65,22 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileDirectoryInformation do
|
|
|
49
65
|
expect(struct.file_name_length).to eq struct.file_name.do_num_bytes
|
|
50
66
|
end
|
|
51
67
|
|
|
52
|
-
|
|
53
|
-
name
|
|
54
|
-
struct.file_name = name
|
|
55
|
-
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
describe 'reading in from a blob' do
|
|
59
|
-
it 'uses the file_name_length to know when to stop reading' do
|
|
68
|
+
describe '#file_name' do
|
|
69
|
+
it 'automatically encodes the file name in UTF-16LE' do
|
|
60
70
|
name = 'Hello_world.txt'
|
|
61
71
|
struct.file_name = name
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
describe 'reading in from a blob' do
|
|
76
|
+
it 'uses the file_name_length to know when to stop reading' do
|
|
77
|
+
name = 'Hello_world.txt'
|
|
78
|
+
struct.file_name = name
|
|
79
|
+
blob = struct.to_binary_s
|
|
80
|
+
blob << 'AAAA'
|
|
81
|
+
new_from_blob = described_class.read(blob)
|
|
82
|
+
expect(new_from_blob.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
83
|
+
end
|
|
66
84
|
end
|
|
67
85
|
end
|
|
68
86
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe RubySMB::Fscc::FileInformation::FileEaInformation do
|
|
4
|
+
it 'references the correct class level' do
|
|
5
|
+
expect(described_class).to be_const_defined(:CLASS_LEVEL)
|
|
6
|
+
expect(described_class::CLASS_LEVEL).to be RubySMB::Fscc::FileInformation::FILE_EA_INFORMATION
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
subject(:struct) { described_class.new }
|
|
10
|
+
|
|
11
|
+
it { should respond_to :ea_size }
|
|
12
|
+
|
|
13
|
+
it 'is little endian' do
|
|
14
|
+
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'tracks the extended attributes size in a Uint32 field' do
|
|
18
|
+
expect(struct.ea_size).to be_a BinData::Uint32le
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -25,6 +25,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileFullDirectoryInformation do
|
|
|
25
25
|
expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
it 'tracks the next offset in a Uint32 field' do
|
|
29
|
+
expect(struct.next_offset).to be_a BinData::Uint32le
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it 'tracks the file index in a Uint32 field' do
|
|
33
|
+
expect(struct.file_index).to be_a BinData::Uint32le
|
|
34
|
+
end
|
|
35
|
+
|
|
28
36
|
it 'tracks the creation time in a Filetime field' do
|
|
29
37
|
expect(struct.create_time).to be_a RubySMB::Field::FileTime
|
|
30
38
|
end
|
|
@@ -41,6 +49,14 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileFullDirectoryInformation do
|
|
|
41
49
|
expect(struct.last_change).to be_a RubySMB::Field::FileTime
|
|
42
50
|
end
|
|
43
51
|
|
|
52
|
+
it 'tracks the file size in a Int64 field' do
|
|
53
|
+
expect(struct.end_of_file).to be_a BinData::Int64le
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it 'tracks the allocation size in a Int64 field' do
|
|
57
|
+
expect(struct.allocation_size).to be_a BinData::Int64le
|
|
58
|
+
end
|
|
59
|
+
|
|
44
60
|
it 'contains the file attributes of the file' do
|
|
45
61
|
expect(struct.file_attributes).to be_a RubySMB::Fscc::FileAttributes
|
|
46
62
|
end
|
|
@@ -50,20 +66,22 @@ RSpec.describe RubySMB::Fscc::FileInformation::FileFullDirectoryInformation do
|
|
|
50
66
|
expect(struct.file_name_length).to eq struct.file_name.do_num_bytes
|
|
51
67
|
end
|
|
52
68
|
|
|
53
|
-
|
|
54
|
-
name
|
|
55
|
-
struct.file_name = name
|
|
56
|
-
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
describe 'reading in from a blob' do
|
|
60
|
-
it 'uses the file_name_length to know when to stop reading' do
|
|
69
|
+
describe '#file_name' do
|
|
70
|
+
it 'automatically encodes the file name in UTF-16LE' do
|
|
61
71
|
name = 'Hello_world.txt'
|
|
62
72
|
struct.file_name = name
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
73
|
+
expect(struct.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe 'reading in from a blob' do
|
|
77
|
+
it 'uses the file_name_length to know when to stop reading' do
|
|
78
|
+
name = 'Hello_world.txt'
|
|
79
|
+
struct.file_name = name
|
|
80
|
+
blob = struct.to_binary_s
|
|
81
|
+
blob << 'AAAA'
|
|
82
|
+
new_from_blob = described_class.read(blob)
|
|
83
|
+
expect(new_from_blob.file_name.force_encoding('utf-16le')).to eq name.encode('utf-16le')
|
|
84
|
+
end
|
|
67
85
|
end
|
|
68
86
|
end
|
|
69
87
|
end
|