ruby_smb 3.3.19 → 3.3.21

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.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/examples/anonymous_auth.rb +5 -0
  3. data/examples/append_file.rb +57 -14
  4. data/examples/authenticate.rb +64 -16
  5. data/examples/delete_file.rb +53 -11
  6. data/examples/dump_secrets_from_sid.rb +43 -8
  7. data/examples/enum_domain_users.rb +51 -8
  8. data/examples/enum_registry_key.rb +51 -7
  9. data/examples/enum_registry_values.rb +51 -9
  10. data/examples/get_computer_info.rb +48 -8
  11. data/examples/list_directory.rb +54 -12
  12. data/examples/negotiate.rb +54 -42
  13. data/examples/negotiate_with_netbios_service.rb +55 -16
  14. data/examples/net_share_enum_all.rb +47 -8
  15. data/examples/pipes.rb +51 -7
  16. data/examples/query_service_status.rb +51 -8
  17. data/examples/read_file_encryption.rb +71 -26
  18. data/examples/read_registry_key_value.rb +54 -9
  19. data/examples/rename_file.rb +58 -15
  20. data/examples/write_file.rb +58 -15
  21. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_cifs_unix_info.rb +31 -0
  22. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_level.rb +4 -0
  23. data/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request.rb +12 -4
  24. data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_level.rb +28 -0
  25. data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request.rb +90 -0
  26. data/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response.rb +56 -0
  27. data/lib/ruby_smb/smb1/packet/trans2/set_information_level.rb +35 -0
  28. data/lib/ruby_smb/smb1/packet/trans2/set_path_information_request.rb +75 -0
  29. data/lib/ruby_smb/smb1/packet/trans2/set_path_information_response.rb +51 -0
  30. data/lib/ruby_smb/smb1/packet/trans2.rb +8 -0
  31. data/lib/ruby_smb/smb1/tree.rb +124 -0
  32. data/lib/ruby_smb/version.rb +1 -1
  33. data/spec/lib/ruby_smb/smb1/packet/trans2/query_fs_information_request_spec.rb +6 -1
  34. data/spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_request_spec.rb +52 -0
  35. data/spec/lib/ruby_smb/smb1/packet/trans2/set_fs_information_response_spec.rb +29 -0
  36. data/spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_request_spec.rb +114 -0
  37. data/spec/lib/ruby_smb/smb1/packet/trans2/set_path_information_response_spec.rb +54 -0
  38. data/spec/lib/ruby_smb/smb1/tree_spec.rb +124 -0
  39. metadata +17 -2
@@ -1,24 +1,11 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- # This example script is used for testing the reading of a file.
3
+ # This example script is used for testing the reading of a file with SMBv3 encryption.
4
4
  # It will attempt to connect to a specific share and then read a specified file.
5
- # Example usage: ruby read_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE short.txt
5
+ # Example usage: ruby read_file_encryption.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE short.txt
6
6
  # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
7
7
  # and read the file short.txt
8
8
 
9
- require 'bundler/setup'
10
- require 'ruby_smb'
11
-
12
- address = ARGV[0]
13
- username = ARGV[1]
14
- password = ARGV[2]
15
- share = ARGV[3]
16
- filename = ARGV[4]
17
- path = "\\\\#{address}\\#{share}"
18
-
19
- sock = TCPSocket.new address, 445
20
- dispatcher = RubySMB::Dispatcher::Socket.new(sock)
21
-
22
9
  # To require encryption on the server, run this in an elevated Powershell:
23
10
  # C:\> Set-SmbServerConfiguration -EncryptData $true
24
11
 
@@ -26,20 +13,78 @@ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
26
13
  # C:\ Set-SmbServerConfiguration -EncryptData $false
27
14
  # C:\ Set-SmbShare -Name <share name> -EncryptData 1
28
15
 
29
- # For this encryption to work, it has to be SMBv3. By only setting smb3 to true,
30
- # we make sure the server will negotiate this version, if it supports it
31
- opts = {
32
- smb1: false,
33
- smb2: false,
34
- smb3: true,
35
- username: username,
36
- password: password,
16
+ # For this encryption to work, it has to be SMBv3. By default, SMBv1 and SMBv2
17
+ # are disabled here so the server will negotiate SMBv3 if it supports it.
18
+
19
+ require 'bundler/setup'
20
+ require 'optparse'
21
+ require 'ruby_smb'
22
+
23
+ args = ARGV.dup
24
+ options = {
25
+ domain: '.',
26
+ username: '',
27
+ password: '',
28
+ smbv1: false,
29
+ smbv2: false,
30
+ smbv3: true,
31
+ target: nil,
32
+ share: nil,
33
+ file: nil
37
34
  }
35
+ options[:file] = args.pop
36
+ options[:share] = args.pop
37
+ options[:target] = args.pop
38
+ optparser = OptionParser.new do |opts|
39
+ opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file"
40
+ opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
41
+ options[:smbv1] = smbv1
42
+ end
43
+ opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
44
+ options[:smbv2] = smbv2
45
+ end
46
+ opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
47
+ options[:smbv3] = smbv3
48
+ end
49
+ opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
50
+ if username.include?('\\')
51
+ options[:domain], options[:username] = username.split('\\', 2)
52
+ else
53
+ options[:username] = username
54
+ end
55
+ end
56
+ opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
57
+ options[:password] = password
58
+ end
59
+ end
60
+ optparser.parse!(args)
61
+
62
+ if [options[:target], options[:share], options[:file]].any? { |a| a == '-h' || a == '--help' }
63
+ puts optparser.help
64
+ exit
65
+ end
66
+
67
+ if options[:target].nil? || options[:share].nil? || options[:file].nil?
68
+ abort(optparser.help)
69
+ end
70
+
71
+ path = "\\\\#{options[:target]}\\#{options[:share]}"
72
+
73
+ sock = TCPSocket.new options[:target], 445
74
+ dispatcher = RubySMB::Dispatcher::Socket.new(sock)
38
75
 
39
76
  # By default, the client uses encryption even if it is not required by the server. Disable this by setting always_encrypt to false
40
- #opts[:always_encrypt] = false
77
+ client_opts = {
78
+ smb1: options[:smbv1],
79
+ smb2: options[:smbv2],
80
+ smb3: options[:smbv3],
81
+ username: options[:username],
82
+ password: options[:password],
83
+ domain: options[:domain]
84
+ }
85
+ #client_opts[:always_encrypt] = false
41
86
 
42
- client = RubySMB::Client.new(dispatcher, opts)
87
+ client = RubySMB::Client.new(dispatcher, **client_opts)
43
88
  protocol = client.negotiate
44
89
  status = client.authenticate
45
90
 
@@ -49,7 +94,7 @@ rescue StandardError => e
49
94
  puts "Failed to connect to #{path}: #{e.message}"
50
95
  end
51
96
 
52
- file = tree.open_file(filename: filename)
97
+ file = tree.open_file(filename: options[:file])
53
98
 
54
99
  data = file.read
55
100
  puts data
@@ -2,23 +2,69 @@
2
2
 
3
3
  # This example script is used for testing the Winreg registry key value read functionality.
4
4
  # It will attempt to connect to a host and reads the value of a specified registry key.
5
- # Example usage: ruby enum_registry_key.rb 192.168.172.138 msfadmin msfadmin HKLM\\My\\Key ValueName
5
+ # Example usage: ruby read_registry_key_value.rb --username msfadmin --password msfadmin 192.168.172.138 HKLM\\My\\Key ValueName
6
6
  # This will try to connect to \\192.168.172.138 with the msfadmin:msfadmin credentialas and reads the ValueName data corresponding to the HKLM\\My\\Key registry key.
7
7
 
8
8
  require 'bundler/setup'
9
+ require 'optparse'
9
10
  require 'ruby_smb'
10
11
 
11
- address = ARGV[0]
12
- username = ARGV[1]
13
- password = ARGV[2]
14
- registry_key = ARGV[3]
15
- value_name = ARGV[4]
16
- smb_versions = ARGV[5]&.split(',') || ['1','2','3']
12
+ args = ARGV.dup
13
+ options = {
14
+ domain: '.',
15
+ username: '',
16
+ password: '',
17
+ smbv1: true,
18
+ smbv2: true,
19
+ smbv3: true,
20
+ target: nil,
21
+ registry_key: nil,
22
+ value_name: nil
23
+ }
24
+ options[:value_name] = args.pop
25
+ options[:registry_key] = args.pop
26
+ options[:target] = args.pop
27
+ optparser = OptionParser.new do |opts|
28
+ opts.banner = "Usage: #{File.basename(__FILE__)} [options] target registry_key value_name"
29
+ opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
30
+ options[:smbv1] = smbv1
31
+ end
32
+ opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
33
+ options[:smbv2] = smbv2
34
+ end
35
+ opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
36
+ options[:smbv3] = smbv3
37
+ end
38
+ opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
39
+ if username.include?('\\')
40
+ options[:domain], options[:username] = username.split('\\', 2)
41
+ else
42
+ options[:username] = username
43
+ end
44
+ end
45
+ opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
46
+ options[:password] = password
47
+ end
48
+ end
49
+ optparser.parse!(args)
50
+
51
+ if [options[:target], options[:registry_key], options[:value_name]].any? { |a| a == '-h' || a == '--help' }
52
+ puts optparser.help
53
+ exit
54
+ end
55
+
56
+ if options[:target].nil? || options[:registry_key].nil? || options[:value_name].nil?
57
+ abort(optparser.help)
58
+ end
59
+
60
+ address = options[:target]
61
+ registry_key = options[:registry_key]
62
+ value_name = options[:value_name]
17
63
 
18
64
  sock = TCPSocket.new address, 445
19
65
  dispatcher = RubySMB::Dispatcher::Socket.new(sock, read_timeout: 60)
20
66
 
21
- client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password)
67
+ client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
22
68
  protocol = client.negotiate
23
69
  status = client.authenticate
24
70
 
@@ -30,4 +76,3 @@ key_value = client.read_registry_key_value(address, registry_key, value_name)
30
76
  puts key_value
31
77
 
32
78
  client.disconnect!
33
-
@@ -1,28 +1,71 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- # This example script is used for testing the deleting of a file.
3
+ # This example script is used for testing the renaming of a file.
4
4
  # It will attempt to connect to a specific share and then rename a specified file.
5
- # Example usage: ruby rename_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE short.txt shortrenamed.txt
5
+ # Example usage: ruby rename_file.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE short.txt shortrenamed.txt
6
6
  # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
7
- # and rename the file short.txt
7
+ # and rename the file short.txt to shortrenamed.txt
8
8
 
9
9
  require 'bundler/setup'
10
+ require 'optparse'
10
11
  require 'ruby_smb'
11
12
 
12
- address = ARGV[0]
13
- username = ARGV[1]
14
- password = ARGV[2]
15
- share = ARGV[3]
16
- file = ARGV[4]
17
- new_name = ARGV[5]
18
- smb_versions = ARGV[6]&.split(',') || ['1','2','3']
13
+ args = ARGV.dup
14
+ options = {
15
+ domain: '.',
16
+ username: '',
17
+ password: '',
18
+ smbv1: true,
19
+ smbv2: true,
20
+ smbv3: true,
21
+ target: nil,
22
+ share: nil,
23
+ file: nil,
24
+ new_name: nil
25
+ }
26
+ options[:new_name] = args.pop
27
+ options[:file] = args.pop
28
+ options[:share] = args.pop
29
+ options[:target] = args.pop
30
+ optparser = OptionParser.new do |opts|
31
+ opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file new_name"
32
+ opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
33
+ options[:smbv1] = smbv1
34
+ end
35
+ opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
36
+ options[:smbv2] = smbv2
37
+ end
38
+ opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
39
+ options[:smbv3] = smbv3
40
+ end
41
+ opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
42
+ if username.include?('\\')
43
+ options[:domain], options[:username] = username.split('\\', 2)
44
+ else
45
+ options[:username] = username
46
+ end
47
+ end
48
+ opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
49
+ options[:password] = password
50
+ end
51
+ end
52
+ optparser.parse!(args)
53
+
54
+ if [options[:target], options[:share], options[:file], options[:new_name]].any? { |a| a == '-h' || a == '--help' }
55
+ puts optparser.help
56
+ exit
57
+ end
58
+
59
+ if options[:target].nil? || options[:share].nil? || options[:file].nil? || options[:new_name].nil?
60
+ abort(optparser.help)
61
+ end
19
62
 
20
- path = "\\\\#{address}\\#{share}"
63
+ path = "\\\\#{options[:target]}\\#{options[:share]}"
21
64
 
22
- sock = TCPSocket.new address, 445
65
+ sock = TCPSocket.new options[:target], 445
23
66
  dispatcher = RubySMB::Dispatcher::Socket.new(sock)
24
67
 
25
- client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password)
68
+ client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
26
69
 
27
70
  protocol = client.negotiate
28
71
  status = client.authenticate
@@ -36,8 +79,8 @@ rescue StandardError => e
36
79
  puts "Failed to connect to #{path}: #{e.message}"
37
80
  end
38
81
 
39
- file = tree.open_file(filename: file, write: true, delete: true)
82
+ file = tree.open_file(filename: options[:file], write: true, delete: true)
40
83
 
41
- data = file.rename(new_name)
84
+ data = file.rename(options[:new_name])
42
85
  puts data
43
86
  file.close
@@ -2,27 +2,70 @@
2
2
 
3
3
  # This example script is used for testing the writing to a file.
4
4
  # It will attempt to connect to a specific share and then write to a specified file.
5
- # Example usage: ruby write_file.rb 192.168.172.138 msfadmin msfadmin TEST_SHARE test.txt "data to write"
5
+ # Example usage: ruby write_file.rb --username msfadmin --password msfadmin 192.168.172.138 TEST_SHARE test.txt "data to write"
6
6
  # This will try to connect to \\192.168.172.138\TEST_SHARE with the msfadmin:msfadmin credentials
7
- # and write "data to write" the file test.txt
7
+ # and write "data to write" to the file test.txt
8
8
 
9
9
  require 'bundler/setup'
10
+ require 'optparse'
10
11
  require 'ruby_smb'
11
12
 
12
- address = ARGV[0]
13
- username = ARGV[1]
14
- password = ARGV[2]
15
- share = ARGV[3]
16
- file = ARGV[4]
17
- data = ARGV[5]
18
- smb_versions = ARGV[6]&.split(',') || ['1','2','3']
13
+ args = ARGV.dup
14
+ options = {
15
+ domain: '.',
16
+ username: '',
17
+ password: '',
18
+ smbv1: true,
19
+ smbv2: true,
20
+ smbv3: true,
21
+ target: nil,
22
+ share: nil,
23
+ file: nil,
24
+ data: nil
25
+ }
26
+ options[:data] = args.pop
27
+ options[:file] = args.pop
28
+ options[:share] = args.pop
29
+ options[:target] = args.pop
30
+ optparser = OptionParser.new do |opts|
31
+ opts.banner = "Usage: #{File.basename(__FILE__)} [options] target share file data"
32
+ opts.on("--[no-]smbv1", "Enable or disable SMBv1 (default: #{options[:smbv1] ? 'Enabled' : 'Disabled'})") do |smbv1|
33
+ options[:smbv1] = smbv1
34
+ end
35
+ opts.on("--[no-]smbv2", "Enable or disable SMBv2 (default: #{options[:smbv2] ? 'Enabled' : 'Disabled'})") do |smbv2|
36
+ options[:smbv2] = smbv2
37
+ end
38
+ opts.on("--[no-]smbv3", "Enable or disable SMBv3 (default: #{options[:smbv3] ? 'Enabled' : 'Disabled'})") do |smbv3|
39
+ options[:smbv3] = smbv3
40
+ end
41
+ opts.on("--username USERNAME", "The account's username (default: #{options[:username]})") do |username|
42
+ if username.include?('\\')
43
+ options[:domain], options[:username] = username.split('\\', 2)
44
+ else
45
+ options[:username] = username
46
+ end
47
+ end
48
+ opts.on("--password PASSWORD", "The account's password (default: #{options[:password]})") do |password|
49
+ options[:password] = password
50
+ end
51
+ end
52
+ optparser.parse!(args)
53
+
54
+ if [options[:target], options[:share], options[:file], options[:data]].any? { |a| a == '-h' || a == '--help' }
55
+ puts optparser.help
56
+ exit
57
+ end
58
+
59
+ if options[:target].nil? || options[:share].nil? || options[:file].nil? || options[:data].nil?
60
+ abort(optparser.help)
61
+ end
19
62
 
20
- path = "\\\\#{address}\\#{share}"
63
+ path = "\\\\#{options[:target]}\\#{options[:share]}"
21
64
 
22
- sock = TCPSocket.new address, 445
65
+ sock = TCPSocket.new options[:target], 445
23
66
  dispatcher = RubySMB::Dispatcher::Socket.new(sock)
24
67
 
25
- client = RubySMB::Client.new(dispatcher, smb1: smb_versions.include?('1'), smb2: smb_versions.include?('2'), smb3: smb_versions.include?('3'), username: username, password: password)
68
+ client = RubySMB::Client.new(dispatcher, smb1: options[:smbv1], smb2: options[:smbv2], smb3: options[:smbv3], username: options[:username], password: options[:password], domain: options[:domain])
26
69
  protocol = client.negotiate
27
70
  status = client.authenticate
28
71
 
@@ -32,11 +75,11 @@ begin
32
75
  tree = client.tree_connect(path)
33
76
  puts "Connected to #{path} successfully!"
34
77
  rescue StandardError => e
35
- puts "Failed to connect to #{path}: #{e.message}"
78
+ abort("Failed to connect to #{path}: #{e.message}")
36
79
  end
37
80
 
38
- file = tree.open_file(filename: file, write: true, disposition: RubySMB::Dispositions::FILE_OVERWRITE_IF)
81
+ file = tree.open_file(filename: options[:file], write: true, disposition: RubySMB::Dispositions::FILE_OVERWRITE_IF)
39
82
 
40
- result = file.write(data: data)
83
+ result = file.write(data: options[:data])
41
84
  puts result.to_s
42
85
  file.close
@@ -0,0 +1,31 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+ module Trans2
5
+ module QueryFsInformationLevel
6
+ # Response data for SMB_QUERY_CIFS_UNIX_INFO (0x0200) from the
7
+ # CIFS UNIX Extensions. 12 bytes: major/minor version pair plus
8
+ # a 64-bit capability bitfield that the client echoes back in
9
+ # SMB_SET_CIFS_UNIX_INFO to enable UNIX extensions for the session.
10
+ #
11
+ # Outside of MS-CIFS; wire format defined by the CIFS UNIX
12
+ # Extensions draft maintained by the Samba team. The parent
13
+ # subcommand is documented at
14
+ # [MS-CIFS 2.2.6.4 TRANS2_QUERY_FS_INFORMATION (0x0003)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/a96c1c03-cade-4a4a-81a9-b00674d23d93).
15
+ # The on-disk layout matches Samba's server-side `unix_info`
16
+ # struct at
17
+ # [source3/smbd/globals.h:419-424](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/globals.h#L419-L424),
18
+ # populated by `call_trans2qfsinfo` at
19
+ # [source3/smbd/smb1_trans2.c:1633-1703](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1633-L1703).
20
+ class QueryFsCifsUnixInfo < BinData::Record
21
+ endian :little
22
+
23
+ uint16 :major_version, label: 'Major Version'
24
+ uint16 :minor_version, label: 'Minor Version'
25
+ uint64 :capabilities, label: 'Capabilities'
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -28,11 +28,15 @@ module RubySMB
28
28
  # [NT LANMAN] Query file system attributes.
29
29
  SMB_QUERY_FS_ATTRIBUTE_INFO = 0x0105 # 261
30
30
 
31
+ # [CIFS UNIX Extensions] Query server UNIX extension capabilities.
32
+ SMB_QUERY_CIFS_UNIX_INFO = 0x0200 # 512
33
+
31
34
  def self.name(value)
32
35
  constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
33
36
  end
34
37
 
35
38
  require 'ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_attribute_info'
39
+ require 'ruby_smb/smb1/packet/trans2/query_fs_information_level/query_fs_cifs_unix_info'
36
40
  end
37
41
  end
38
42
  end
@@ -2,7 +2,9 @@ module RubySMB
2
2
  module SMB1
3
3
  module Packet
4
4
  module Trans2
5
- # The Trans2 Parameter Block for this particular Subcommand
5
+ # The Trans2 Parameter Block for a QUERY_FS_INFORMATION request as
6
+ # defined in
7
+ # [MS-CIFS 2.2.6.4.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cfa23a11-0e80-43bd-bbd4-e9cfb99b5dce).
6
8
  class QueryFsInformationRequestTrans2Parameters < BinData::Record
7
9
  endian :little
8
10
 
@@ -15,16 +17,22 @@ module RubySMB
15
17
  end
16
18
  end
17
19
 
18
- # The {RubySMB::SMB1::DataBlock} specific to this packet type.
20
+ # The {RubySMB::SMB1::DataBlock} specific to this packet type. See
21
+ # [MS-CIFS 2.2.6.4.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cfa23a11-0e80-43bd-bbd4-e9cfb99b5dce).
22
+ # The request carries no Trans2 data payload, but the generic
23
+ # DataBlock padding helpers require a :trans2_data accessor, so
24
+ # we expose a zero-length string.
19
25
  class QueryFsInformationRequestDataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
20
26
  uint8 :name, label: 'Name', initial_value: 0x00
21
27
  string :pad1, length: -> { pad1_length }
22
28
  query_fs_information_request_trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
23
- # trans2_data: No data is sent by this message.
29
+ string :trans2_data, length: 0, label: 'Trans2 Data'
24
30
  end
25
31
 
26
32
  # A Trans2 QUERY_FS_INFORMATION Request Packet as defined in
27
- # [2.2.6.4.1](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cfa23a11-0e80-43bd-bbd4-e9cfb99b5dce)
33
+ # [MS-CIFS 2.2.6.4.1 Request](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/cfa23a11-0e80-43bd-bbd4-e9cfb99b5dce).
34
+ # See also the subcommand overview at
35
+ # [MS-CIFS 2.2.6.4 TRANS2_QUERY_FS_INFORMATION (0x0003)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/a96c1c03-cade-4a4a-81a9-b00674d23d93).
28
36
  class QueryFsInformationRequest < RubySMB::GenericPacket
29
37
  COMMAND = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
30
38
 
@@ -0,0 +1,28 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+ module Trans2
5
+ # SET_FS Information Levels used in TRANS2_SET_FS_INFORMATION.
6
+ #
7
+ # MS-CIFS marks the parent subcommand
8
+ # [TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
9
+ # as "reserved but not implemented" — the info level codes below are
10
+ # defined by the CIFS UNIX Extensions draft maintained by the Samba
11
+ # team and implemented in
12
+ # [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
13
+ # They sit in the 0x0200–0x02FF range reserved by
14
+ # [MS-CIFS 2.2.2.3 Information Level Codes](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/03c10ab9-d723-4368-b9a6-c72de3244c77)
15
+ # for third-party extensions.
16
+ module SetFsInformationLevel
17
+ # Client advertises / negotiates CIFS UNIX Extensions support.
18
+ # Data block: major:u16, minor:u16, capabilities:u64.
19
+ SMB_SET_CIFS_UNIX_INFO = 0x0200
20
+
21
+ def self.name(value)
22
+ constants.select { |c| c.upcase == c }.find { |c| const_get(c) == value }
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,90 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+ module Trans2
5
+ # The Trans2 Parameter Block for TRANS2_SET_FS_INFORMATION.
6
+ # Observed on the wire (and required by Samba) as a 4-byte block
7
+ # containing a placeholder file handle plus the information level.
8
+ #
9
+ # The parent subcommand
10
+ # [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
11
+ # is marked "reserved but not implemented"; the on-the-wire format
12
+ # used here is defined by the CIFS UNIX Extensions draft and
13
+ # implemented in
14
+ # [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
15
+ class SetFsInformationRequestTrans2Parameters < BinData::Record
16
+ endian :little
17
+
18
+ uint16 :fid, label: 'File ID'
19
+ uint16 :information_level, label: 'Information Level'
20
+
21
+ # Returns the length of the Trans2Parameters struct
22
+ # in number of bytes
23
+ def length
24
+ do_num_bytes
25
+ end
26
+ end
27
+
28
+ # The Trans2 Data Block for TRANS2_SET_FS_INFORMATION.
29
+ #
30
+ # The data layout depends on the Information Level being set, so the
31
+ # block carries an opaque byte buffer that the caller fills in for
32
+ # the target info level. SMB_SET_CIFS_UNIX_INFO (0x0200) for example
33
+ # carries a QueryFsCifsUnixInfo-shaped record (major/minor/caps).
34
+ #
35
+ # Not documented in
36
+ # [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3);
37
+ # per-level layouts are defined by the CIFS UNIX Extensions draft
38
+ # and implemented in
39
+ # [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
40
+ class SetFsInformationRequestTrans2Data < BinData::Record
41
+ string :buffer, read_length: -> { parent.buffer_read_length }
42
+
43
+ # Returns the length of the Trans2Data struct
44
+ # in number of bytes
45
+ def length
46
+ do_num_bytes
47
+ end
48
+ end
49
+
50
+ # The {RubySMB::SMB1::DataBlock} specific to this packet type. The
51
+ # parent subcommand
52
+ # [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
53
+ # is documented as "reserved but not implemented"; this data block
54
+ # is structured for the CIFS UNIX Extensions use in
55
+ # [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
56
+ class SetFsInformationRequestDataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
57
+ uint8 :name, label: 'Name', initial_value: 0x00
58
+ string :pad1, length: -> { pad1_length }
59
+ set_fs_information_request_trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
60
+ string :pad2, length: -> { pad2_length }
61
+ set_fs_information_request_trans2_data :trans2_data, label: 'Trans2 Data'
62
+ end
63
+
64
+ # A Trans2 SET_FS_INFORMATION Request Packet. The on-disk layout
65
+ # described by
66
+ # [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
67
+ # is marked "reserved but not implemented" and does not document the
68
+ # CIFS UNIX Extensions info levels; their wire format is defined by
69
+ # the CIFS UNIX Extensions draft and matched by Samba's
70
+ # `call_trans2setfsinfo` in
71
+ # [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
72
+ class SetFsInformationRequest < RubySMB::GenericPacket
73
+ COMMAND = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
74
+
75
+ class ParameterBlock < RubySMB::SMB1::Packet::Trans2::Request::ParameterBlock
76
+ end
77
+
78
+ smb_header :smb_header
79
+ parameter_block :parameter_block
80
+ set_fs_information_request_data_block :data_block
81
+
82
+ def initialize_instance
83
+ super
84
+ parameter_block.setup << RubySMB::SMB1::Packet::Trans2::Subcommands::SET_FS_INFORMATION
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,56 @@
1
+ module RubySMB
2
+ module SMB1
3
+ module Packet
4
+ module Trans2
5
+ # The Trans2 Parameter Block for a TRANS2_SET_FS_INFORMATION response.
6
+ # The field is intentionally empty — servers return only an NT status
7
+ # in the SMB header to acknowledge the SET.
8
+ #
9
+ # Parent subcommand:
10
+ # [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
11
+ # ("reserved but not implemented"). Response shape observed in the
12
+ # CIFS UNIX Extensions implementation in
13
+ # [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
14
+ class SetFsInformationResponseTrans2Parameters < BinData::Record
15
+ def length
16
+ do_num_bytes
17
+ end
18
+ end
19
+
20
+ # The {RubySMB::SMB1::DataBlock} specific to this packet type.
21
+ # Parent subcommand:
22
+ # [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
23
+ # ("reserved but not implemented"); actual shape used by the CIFS
24
+ # UNIX Extensions implementation in
25
+ # [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
26
+ class SetFsInformationResponseDataBlock < RubySMB::SMB1::Packet::Trans2::DataBlock
27
+ uint8 :name, label: 'Name', initial_value: 0x00
28
+ string :pad1, length: -> { pad1_length }
29
+ set_fs_information_response_trans2_parameters :trans2_parameters, label: 'Trans2 Parameters'
30
+ end
31
+
32
+ # A Trans2 SET_FS_INFORMATION Response Packet. Parent subcommand:
33
+ # [MS-CIFS 2.2.6.5 TRANS2_SET_FS_INFORMATION (0x0004)](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cifs/ac4b00db-6015-416a-89a1-bf5da2503bc3)
34
+ # ("reserved but not implemented"). Response shape is defined by the
35
+ # CIFS UNIX Extensions implementation in
36
+ # [source3/smbd/smb1_trans2.c:1706-1915 (`call_trans2setfsinfo`)](https://github.com/samba-team/samba/blob/33f516c06756e12a9d11f50e2bf309171cdf5c88/source3/smbd/smb1_trans2.c#L1706-L1915).
37
+ class SetFsInformationResponse < RubySMB::GenericPacket
38
+ COMMAND = RubySMB::SMB1::Commands::SMB_COM_TRANSACTION2
39
+
40
+ class ParameterBlock < RubySMB::SMB1::Packet::Trans2::Response::ParameterBlock
41
+ end
42
+
43
+ smb_header :smb_header
44
+ parameter_block :parameter_block
45
+ set_fs_information_response_data_block :data_block
46
+
47
+ def initialize_instance
48
+ super
49
+ parameter_block.setup << RubySMB::SMB1::Packet::Trans2::Subcommands::SET_FS_INFORMATION
50
+ smb_header.flags.reply = 1
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end