ruby_smb 3.0.0 → 3.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/examples/anonymous_auth.rb +29 -6
  4. data/examples/auth_capture.rb +28 -0
  5. data/examples/file_server.rb +76 -0
  6. data/examples/read_file.rb +51 -10
  7. data/examples/tree_connect.rb +49 -8
  8. data/lib/ruby_smb/client/authentication.rb +11 -3
  9. data/lib/ruby_smb/client.rb +16 -2
  10. data/lib/ruby_smb/create_actions.rb +21 -0
  11. data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_request.rb +20 -0
  12. data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response.rb +20 -0
  13. data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request.rb +21 -0
  14. data/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response.rb +21 -0
  15. data/lib/ruby_smb/dcerpc/encrypting_file_system.rb +44 -0
  16. data/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_request.rb +22 -0
  17. data/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_response.rb +20 -0
  18. data/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_request.rb +24 -0
  19. data/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_response.rb +23 -0
  20. data/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_request.rb +24 -0
  21. data/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_response.rb +22 -0
  22. data/lib/ruby_smb/dcerpc/print_system.rb +69 -0
  23. data/lib/ruby_smb/dcerpc.rb +2 -2
  24. data/lib/ruby_smb/field/nt_status.rb +20 -1
  25. data/lib/ruby_smb/fscc/file_information/file_ea_information.rb +14 -0
  26. data/lib/ruby_smb/fscc/file_information/file_network_open_information.rb +22 -0
  27. data/lib/ruby_smb/fscc/file_information/file_stream_information.rb +16 -0
  28. data/lib/ruby_smb/fscc/file_information.rb +29 -0
  29. data/lib/ruby_smb/fscc/file_system_information/file_fs_attribute_information.rb +46 -0
  30. data/lib/ruby_smb/fscc/file_system_information/file_fs_volume_information.rb +19 -0
  31. data/lib/ruby_smb/fscc/file_system_information.rb +22 -0
  32. data/lib/ruby_smb/fscc.rb +1 -0
  33. data/lib/ruby_smb/generic_packet.rb +6 -0
  34. data/lib/ruby_smb/gss/provider/authenticator.rb +4 -0
  35. data/lib/ruby_smb/gss/provider/ntlm.rb +13 -3
  36. data/lib/ruby_smb/server/server_client/negotiation.rb +0 -2
  37. data/lib/ruby_smb/server/server_client/session_setup.rb +43 -32
  38. data/lib/ruby_smb/server/server_client/share_io.rb +28 -0
  39. data/lib/ruby_smb/server/server_client/tree_connect.rb +60 -0
  40. data/lib/ruby_smb/server/server_client.rb +214 -24
  41. data/lib/ruby_smb/server/session.rb +71 -0
  42. data/lib/ruby_smb/server/share/provider/disk.rb +437 -0
  43. data/lib/ruby_smb/server/share/provider/pipe.rb +27 -0
  44. data/lib/ruby_smb/server/share/provider/processor.rb +76 -0
  45. data/lib/ruby_smb/server/share/provider.rb +38 -0
  46. data/lib/ruby_smb/server/share.rb +11 -0
  47. data/lib/ruby_smb/server.rb +35 -3
  48. data/lib/ruby_smb/signing.rb +37 -11
  49. data/lib/ruby_smb/smb1/commands.rb +4 -0
  50. data/lib/ruby_smb/smb1/tree.rb +87 -79
  51. data/lib/ruby_smb/smb1.rb +0 -1
  52. data/lib/ruby_smb/smb2/bit_field/smb2_header_flags.rb +2 -1
  53. data/lib/ruby_smb/smb2/commands.rb +4 -0
  54. data/lib/ruby_smb/smb2/create_context/request.rb +64 -0
  55. data/lib/ruby_smb/smb2/create_context/response.rb +62 -0
  56. data/lib/ruby_smb/smb2/create_context.rb +74 -22
  57. data/lib/ruby_smb/smb2/packet/create_request.rb +44 -11
  58. data/lib/ruby_smb/smb2/packet/create_response.rb +17 -3
  59. data/lib/ruby_smb/smb2/packet/query_directory_request.rb +1 -1
  60. data/lib/ruby_smb/smb2/packet/query_directory_response.rb +2 -2
  61. data/lib/ruby_smb/smb2/packet/query_info_request.rb +43 -0
  62. data/lib/ruby_smb/smb2/packet/query_info_response.rb +23 -0
  63. data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +1 -1
  64. data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +1 -0
  65. data/lib/ruby_smb/smb2/packet.rb +2 -0
  66. data/lib/ruby_smb/smb2/tree.rb +80 -70
  67. data/lib/ruby_smb/smb2.rb +11 -0
  68. data/lib/ruby_smb/smb_error.rb +110 -0
  69. data/lib/ruby_smb/version.rb +1 -1
  70. data/lib/ruby_smb.rb +2 -0
  71. data/ruby_smb.gemspec +1 -1
  72. data/spec/lib/ruby_smb/client_spec.rb +10 -0
  73. data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_request_spec.rb +30 -0
  74. data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_encrypt_file_srv_response_spec.rb +30 -0
  75. data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_request_spec.rb +38 -0
  76. data/spec/lib/ruby_smb/dcerpc/encrypting_file_system/efs_rpc_open_file_raw_response_spec.rb +38 -0
  77. data/spec/lib/ruby_smb/dcerpc/print_system/driver_container_spec.rb +41 -0
  78. data/spec/lib/ruby_smb/dcerpc/print_system/driver_info2_spec.rb +64 -0
  79. data/spec/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_request_spec.rb +59 -0
  80. data/spec/lib/ruby_smb/dcerpc/print_system/rpc_add_printer_driver_ex_response_spec.rb +30 -0
  81. data/spec/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_request_spec.rb +62 -0
  82. data/spec/lib/ruby_smb/dcerpc/print_system/rpc_enum_printer_drivers_response_spec.rb +54 -0
  83. data/spec/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_request_spec.rb +62 -0
  84. data/spec/lib/ruby_smb/dcerpc/print_system/rpc_get_printer_driver_directory_response_spec.rb +46 -0
  85. data/spec/lib/ruby_smb/field/nt_status_spec.rb +6 -2
  86. data/spec/lib/ruby_smb/gss/provider/ntlm/authenticator_spec.rb +4 -0
  87. data/spec/lib/ruby_smb/server/server_client_spec.rb +36 -53
  88. data/spec/lib/ruby_smb/server/session_spec.rb +38 -0
  89. data/spec/lib/ruby_smb/server/share/provider/disk_spec.rb +61 -0
  90. data/spec/lib/ruby_smb/server/share/provider/pipe_spec.rb +31 -0
  91. data/spec/lib/ruby_smb/server/share/provider_spec.rb +13 -0
  92. data/spec/lib/ruby_smb/smb1/tree_spec.rb +3 -3
  93. data/spec/lib/ruby_smb/smb2/bit_field/header_flags_spec.rb +8 -2
  94. data/spec/lib/ruby_smb/smb2/{create_context_spec.rb → create_context/create_context_request_spec.rb} +1 -1
  95. data/spec/lib/ruby_smb/smb2/packet/create_request_spec.rb +5 -5
  96. data/spec/lib/ruby_smb/smb2/packet/create_response_spec.rb +9 -5
  97. data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +3 -2
  98. data/spec/lib/ruby_smb/smb2/tree_spec.rb +3 -3
  99. data.tar.gz.sig +0 -0
  100. metadata +71 -7
  101. metadata.gz.sig +0 -0
  102. data/lib/ruby_smb/smb1/create_actions.rb +0 -20
@@ -9,8 +9,8 @@ module RubySMB
9
9
  endian :little
10
10
  smb2_header :smb2_header
11
11
  uint16 :structure_size, label: 'Structure Size', initial_value: 9
12
- uint16 :buffer_offset, label: 'Output Buffer Offset', initial_value: -> { buffer.abs_offset }
13
- uint32 :buffer_length, label: 'Output Buffer Length', initial_value: -> { buffer.do_num_bytes }
12
+ uint16 :buffer_offset, label: 'Output Buffer Offset', initial_value: -> { buffer.empty? ? 0 : buffer.abs_offset }
13
+ uint32 :buffer_length, label: 'Output Buffer Length', initial_value: -> { buffer.empty? ? 0 : buffer.do_num_bytes }
14
14
  string :buffer, read_length: -> { buffer_length }
15
15
 
16
16
  def initialize_instance
@@ -0,0 +1,43 @@
1
+ module RubySMB
2
+ module SMB2
3
+ module Packet
4
+ # An SMB2 Query Info Request Packet as defined in
5
+ # [2.2.37 SMB2 QUERY_INFO Request](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/d623b2f7-a5cd-4639-8cc9-71fa7d9f9ba9)
6
+ class QueryInfoRequest < RubySMB::GenericPacket
7
+ COMMAND = RubySMB::SMB2::Commands::QUERY_INFO
8
+
9
+ endian :little
10
+ smb2_header :smb2_header
11
+ uint16 :structure_size, label: 'Structure Size', initial_value: 41
12
+ uint8 :info_type, label: 'Information Type'
13
+ uint8 :file_information_class, label: 'File Information Class'
14
+ uint32 :output_buffer_length, label: 'Output Buffer Length'
15
+ uint16 :input_buffer_offset, label: 'Input Buffer Offset'
16
+ uint16 :reserved, label: 'Reserved Space'
17
+ uint32 :input_buffer_length, label: 'Input Buffer Length'
18
+ struct :additional_information do
19
+ bit1 :reserved1
20
+ bit1 :scope_security_information, label: 'Scope Security Information'
21
+ bit1 :attribute_security_information, label: 'Attribute Security Information'
22
+ bit1 :label_security_information, label: 'Label Security Information'
23
+ bit1 :sacl_security_information, label: 'SACL Security Information'
24
+ bit1 :dacl_security_information, label: 'DACL Security Information'
25
+ bit1 :group_security_information, label: 'Group Security Information'
26
+ bit1 :owner_security_information, label: 'Owner Security Information'
27
+ bit7 :reserved2
28
+ bit1 :backup_security_information, label: 'Backup Security Information'
29
+ skip length: 2
30
+ end
31
+ struct :flags do
32
+ bit5 :reserved
33
+ bit1 :sl_index_specified, label: 'Index Specified'
34
+ bit1 :sl_return_single_entry, label: 'Return Single Entry'
35
+ bit1 :sl_restart_scan, label: 'Restart Scan'
36
+ skip length: 3
37
+ end
38
+ smb2_fileid :file_id, label: 'File ID'
39
+ string :buffer, label: 'Buffer'
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,23 @@
1
+ module RubySMB
2
+ module SMB2
3
+ module Packet
4
+ # An SMB2 Query Info Response Packet as defined in
5
+ # [2.2.38 SMB2 QUERY_INFO Response](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/3b1b3598-a898-44ca-bfac-2dcae065247f)
6
+ class QueryInfoResponse < RubySMB::GenericPacket
7
+ COMMAND = RubySMB::SMB2::Commands::QUERY_INFO
8
+
9
+ endian :little
10
+ smb2_header :smb2_header
11
+ uint16 :structure_size, label: 'Structure Size', initial_value: 9
12
+ uint16 :buffer_offset, label: 'Output Buffer Offset', initial_value: -> { buffer.empty? ? 0 : buffer.abs_offset }
13
+ uint32 :buffer_length, label: 'Output Buffer Length', initial_value: -> { buffer.empty? ? 0 : buffer.do_num_bytes }
14
+ string :buffer, read_length: -> { buffer_length }
15
+
16
+ def initialize_instance
17
+ super
18
+ smb2_header.flags.reply = 1
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -21,7 +21,7 @@ module RubySMB
21
21
  uint8 :reserved, label: 'Reserved Space', initial_value: 0x00
22
22
  share_flags :share_flags
23
23
  share_capabilities :capabilities
24
- directory_access_mask :maximal_access, label: 'Maximal Access'
24
+ file_access_mask :maximal_access, label: 'Maximal Access'
25
25
 
26
26
  def initialize_instance
27
27
  super
@@ -9,6 +9,7 @@ module RubySMB
9
9
  endian :little
10
10
  smb2_header :smb2_header
11
11
  uint16 :structure_size, label: 'Structure Size', initial_value: 4
12
+ uint16 :reserved, label: 'Reserved', initial_value: 0
12
13
 
13
14
  def initialize_instance
14
15
  super
@@ -32,6 +32,8 @@ module RubySMB
32
32
  require 'ruby_smb/smb2/packet/ioctl_response'
33
33
  require 'ruby_smb/smb2/packet/transform_header'
34
34
  require 'ruby_smb/smb2/packet/compression_transform_header'
35
+ require 'ruby_smb/smb2/packet/query_info_request'
36
+ require 'ruby_smb/smb2/packet/query_info_response'
35
37
  end
36
38
  end
37
39
  end
@@ -60,78 +60,16 @@ module RubySMB
60
60
  # Make sure we don't modify the caller's hash options
61
61
  opts = opts.dup
62
62
  opts[:filename] = opts[:filename].dup
63
- opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with? '\\'
64
- open_file(**opts)
63
+ opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with?('\\'.encode(opts[:filename].encoding))
64
+ _open(**opts)
65
65
  end
66
66
 
67
- def open_file(filename:, attributes: nil, options: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
68
- impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE, read: true, write: false, delete: false)
69
-
70
- create_request = RubySMB::SMB2::Packet::CreateRequest.new
71
- create_request = set_header_fields(create_request)
72
-
73
- # If the user supplied file attributes, use those, otherwise set some
74
- # sane defaults.
75
- if attributes
76
- create_request.file_attributes = attributes
77
- else
78
- create_request.file_attributes.directory = 0
79
- create_request.file_attributes.normal = 1
80
- end
81
-
82
- # If the user supplied Create Options, use those, otherwise set some
83
- # sane defaults.
84
- if options
85
- create_request.create_options = options
86
- else
87
- create_request.create_options.directory_file = 0
88
- create_request.create_options.non_directory_file = 1
89
- end
90
-
91
- if read
92
- create_request.share_access.read_access = 1
93
- create_request.desired_access.read_data = 1
94
- end
95
-
96
- if write
97
- create_request.share_access.write_access = 1
98
- create_request.desired_access.write_data = 1
99
- create_request.desired_access.append_data = 1
100
- end
101
-
102
- if delete
103
- create_request.share_access.delete_access = 1
104
- create_request.desired_access.delete_access = 1
105
- end
106
-
107
- create_request.requested_oplock = 0xff
108
- create_request.impersonation_level = impersonation
109
- create_request.create_disposition = disposition
110
- create_request.name = filename
111
-
112
- raw_response = client.send_recv(create_request, encrypt: @tree_connect_encrypt_data)
113
- response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
114
- unless response.valid?
115
- raise RubySMB::Error::InvalidPacket.new(
116
- expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
117
- expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
118
- packet: response
119
- )
120
- end
121
- unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
122
- raise RubySMB::Error::UnexpectedStatusCode, response.status_code
123
- end
124
-
125
- case @share_type
126
- when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_DISK
127
- RubySMB::SMB2::File.new(name: filename, tree: self, response: response, encrypt: @tree_connect_encrypt_data)
128
- when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_PIPE
129
- RubySMB::SMB2::Pipe.new(name: filename, tree: self, response: response)
130
- # when RubySMB::SMB2::TreeConnectResponse::SMB2_SHARE_TYPE_PRINT
131
- # it's a printer!
132
- else
133
- raise RubySMB::Error::RubySMBError, 'Unsupported share type'
134
- end
67
+ def open_file(opts)
68
+ # Make sure we don't modify the caller's hash options
69
+ opts = opts.dup
70
+ opts[:filename] = opts[:filename].dup
71
+ opts[:filename] = opts[:filename][1..-1] if opts[:filename].start_with?('\\'.encode(opts[:filename].encoding))
72
+ _open(**opts)
135
73
  end
136
74
 
137
75
  # List `directory` on the remote share.
@@ -270,6 +208,78 @@ module RubySMB
270
208
  request.smb2_header.credits = 256
271
209
  request
272
210
  end
211
+
212
+ private
213
+
214
+ def _open(filename:, attributes: nil, options: nil, disposition: RubySMB::Dispositions::FILE_OPEN,
215
+ impersonation: RubySMB::ImpersonationLevels::SEC_IMPERSONATE, read: true, write: false, delete: false)
216
+
217
+ create_request = RubySMB::SMB2::Packet::CreateRequest.new
218
+ create_request = set_header_fields(create_request)
219
+
220
+ # If the user supplied file attributes, use those, otherwise set some
221
+ # sane defaults.
222
+ if attributes
223
+ create_request.file_attributes = attributes
224
+ else
225
+ create_request.file_attributes.directory = 0
226
+ create_request.file_attributes.normal = 1
227
+ end
228
+
229
+ # If the user supplied Create Options, use those, otherwise set some
230
+ # sane defaults.
231
+ if options
232
+ create_request.create_options = options
233
+ else
234
+ create_request.create_options.directory_file = 0
235
+ create_request.create_options.non_directory_file = 1
236
+ end
237
+
238
+ if read
239
+ create_request.share_access.read_access = 1
240
+ create_request.desired_access.read_data = 1
241
+ end
242
+
243
+ if write
244
+ create_request.share_access.write_access = 1
245
+ create_request.desired_access.write_data = 1
246
+ create_request.desired_access.append_data = 1
247
+ end
248
+
249
+ if delete
250
+ create_request.share_access.delete_access = 1
251
+ create_request.desired_access.delete_access = 1
252
+ end
253
+
254
+ create_request.requested_oplock = 0xff
255
+ create_request.impersonation_level = impersonation
256
+ create_request.create_disposition = disposition
257
+ create_request.name = filename
258
+
259
+ raw_response = client.send_recv(create_request, encrypt: @tree_connect_encrypt_data)
260
+ response = RubySMB::SMB2::Packet::CreateResponse.read(raw_response)
261
+ unless response.valid?
262
+ raise RubySMB::Error::InvalidPacket.new(
263
+ expected_proto: RubySMB::SMB2::SMB2_PROTOCOL_ID,
264
+ expected_cmd: RubySMB::SMB2::Packet::CreateResponse::COMMAND,
265
+ packet: response
266
+ )
267
+ end
268
+ unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
269
+ raise RubySMB::Error::UnexpectedStatusCode, response.status_code
270
+ end
271
+
272
+ case @share_type
273
+ when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_DISK
274
+ RubySMB::SMB2::File.new(name: filename, tree: self, response: response, encrypt: @tree_connect_encrypt_data)
275
+ when RubySMB::SMB2::Packet::TreeConnectResponse::SMB2_SHARE_TYPE_PIPE
276
+ RubySMB::SMB2::Pipe.new(name: filename, tree: self, response: response)
277
+ # when RubySMB::SMB2::TreeConnectResponse::SMB2_SHARE_TYPE_PRINT
278
+ # it's a printer!
279
+ else
280
+ raise RubySMB::Error::RubySMBError, 'Unsupported share type'
281
+ end
282
+ end
273
283
  end
274
284
  end
275
285
  end
data/lib/ruby_smb/smb2.rb CHANGED
@@ -8,6 +8,17 @@ module RubySMB
8
8
  # Wildcard revision, see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/63abf97c-0d09-47e2-88d6-6bfa552949a5
9
9
  SMB2_WILDCARD_REVISION = 0x02ff
10
10
 
11
+ # Channel types, see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/320f04f3-1b28-45cd-aaa1-9e5aed810dca
12
+ SMB2_CHANNEL_NONE = 0
13
+ SMB2_CHANNEL_RDMA_V1 = 1
14
+ SMB2_CHANNEL_RDMA_V1_INVALIDATE = 2
15
+
16
+ # Information types, see: https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb2/d623b2f7-a5cd-4639-8cc9-71fa7d9f9ba9
17
+ SMB2_INFO_FILE = 1
18
+ SMB2_INFO_FILESYSTEM = 2
19
+ SMB2_INFO_SECURITY = 3
20
+ SMB2_INFO_QUOTA = 4
21
+
11
22
  require 'ruby_smb/smb2/info_type'
12
23
  require 'ruby_smb/smb2/commands'
13
24
  require 'ruby_smb/smb2/create_context'
@@ -0,0 +1,110 @@
1
+ require 'windows_error'
2
+
3
+ module RubySMB
4
+ # SMB Error codes as defined in
5
+ # [2.2.2.4 SMB Error Classes and Codes](https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-smb/6ab6ca20-b404-41fd-b91a-2ed39e3762ea)
6
+ module SMBError
7
+ # Returns all the {WindowsError::ErrorCode} objects that match
8
+ # the return value supplied.
9
+ #
10
+ # @param [Integer] retval the return value you want the error code for
11
+ # @raise [ArgumentError] if something other than a Integer is supplied
12
+ # @return [Array<WindowsError::ErrorCode>] all Win32 ErrorCodes that matched
13
+ def self.find_by_retval(retval)
14
+ raise ArgumentError, "Invalid Return Code!" unless retval.kind_of? Integer
15
+ error_codes = []
16
+ self.constants.each do |constant_name|
17
+ error_code = self.const_get(constant_name)
18
+ if error_code == retval
19
+ error_codes << error_code
20
+ end
21
+ end
22
+ error_codes
23
+ end
24
+
25
+ #
26
+ # CONSTANTS
27
+ #
28
+
29
+ # (0x00000000) The client request is successful.
30
+ STATUS_SUCCESS = WindowsError::ErrorCode.new('STATUS_SUCCESS', 0x00000000, 'The client request is successful.')
31
+
32
+ # (0x00010002) An invalid SMB client request is received by the server.
33
+ STATUS_INVALID_SMB = WindowsError::ErrorCode.new('STATUS_INVALID_SMB', 0x00010002, 'An invalid SMB client request is received by the server.')
34
+
35
+ # (0x00050002) The client request received by the server contains an invalid TID value.
36
+ STATUS_SMB_BAD_TID = WindowsError::ErrorCode.new('STATUS_SMB_BAD_TID', 0x00050002, 'The client request received by the server contains an invalid TID value.')
37
+
38
+ # (0x00160002) The client request received by the server contains an unknown SMB command code.
39
+ STATUS_SMB_BAD_COMMAND = WindowsError::ErrorCode.new('STATUS_SMB_BAD_COMMAND', 0x00160002, 'The client request received by the server contains an unknown SMB command code.')
40
+
41
+ # (0x005B0002) The client request to the server contains an invalid UID value.
42
+ STATUS_SMB_BAD_UID = WindowsError::ErrorCode.new('STATUS_SMB_BAD_UID', 0x005B0002, 'The client request to the server contains an invalid UID value.')
43
+
44
+ # (0x00FB0002) The client request received by the server is for a non-standard SMB operation (for example, an SMB_COM_READ_MPX request on a non-disk share). The client SHOULD send another request with a different SMB command to perform this operation.
45
+ STATUS_SMB_USE_STANDARD = WindowsError::ErrorCode.new('STATUS_SMB_USE_STANDARD', 0x00FB0002, 'The client request received by the server is for a non-standard SMB operation (for example, an SMB_COM_READ_MPX request on a non-disk share). The client SHOULD send another request with a different SMB command to perform this operation.')
46
+
47
+ # (0x80000005) The data was too large to fit into the specified buffer.
48
+ STATUS_BUFFER_OVERFLOW = WindowsError::ErrorCode.new('STATUS_BUFFER_OVERFLOW', 0x80000005, 'The data was too large to fit into the specified buffer.')
49
+
50
+ # (0x80000006) No more files were found that match the file specification.
51
+ STATUS_NO_MORE_FILES = WindowsError::ErrorCode.new('STATUS_NO_MORE_FILES', 0x80000006, 'No more files were found that match the file specification.')
52
+
53
+ # (0x8000002D) The create operation stopped after reaching a symbolic link.
54
+ STATUS_STOPPED_ON_SYMLINK = WindowsError::ErrorCode.new('STATUS_STOPPED_ON_SYMLINK', 0x8000002D, 'The create operation stopped after reaching a symbolic link.')
55
+
56
+ # (0xC0000002) The requested operation is not implemented.
57
+ STATUS_NOT_IMPLEMENTED = WindowsError::ErrorCode.new('STATUS_NOT_IMPLEMENTED', 0xC0000002, 'The requested operation is not implemented.')
58
+
59
+ # (0xC000000D) The parameter specified in the request is not valid.
60
+ STATUS_INVALID_PARAMETER = WindowsError::ErrorCode.new('STATUS_INVALID_PARAMETER', 0xC000000D, 'The parameter specified in the request is not valid.')
61
+
62
+ # (0xC000000E) A device that does not exist was specified.
63
+ STATUS_NO_SUCH_DEVICE = WindowsError::ErrorCode.new('STATUS_NO_SUCH_DEVICE', 0xC000000E, 'A device that does not exist was specified.')
64
+
65
+ # (0xC0000010) The specified request is not a valid operation for the target device.
66
+ STATUS_INVALID_DEVICE_REQUEST = WindowsError::ErrorCode.new('STATUS_INVALID_DEVICE_REQUEST', 0xC0000010, 'The specified request is not a valid operation for the target device.')
67
+
68
+ # (0xC0000016) If extended security has been negotiated, then this error code can be returned in the SMB_COM_SESSION_SETUP_ANDX response from the server to indicate that additional authentication information is to be exchanged. See section 2.2.4.6 for details.
69
+ STATUS_MORE_PROCESSING_REQUIRED = WindowsError::ErrorCode.new('STATUS_MORE_PROCESSING_REQUIRED', 0xC0000016, 'If extended security has been negotiated, then this error code can be returned in the SMB_COM_SESSION_SETUP_ANDX response from the server to indicate that additional authentication information is to be exchanged. See section 2.2.4.6 for details.')
70
+
71
+ # (0xC0000022) The client did not have the required permission needed for the operation.
72
+ STATUS_ACCESS_DENIED = WindowsError::ErrorCode.new('STATUS_ACCESS_DENIED', 0xC0000022, 'The client did not have the required permission needed for the operation.')
73
+
74
+ # (0xC0000023) The buffer is too small to contain the entry. No information has been written to the buffer.
75
+ STATUS_BUFFER_TOO_SMALL = WindowsError::ErrorCode.new('STATUS_BUFFER_TOO_SMALL', 0xC0000023, 'The buffer is too small to contain the entry. No information has been written to the buffer.')
76
+
77
+ # (0xC0000034) The object name is not found.
78
+ STATUS_OBJECT_NAME_NOT_FOUND = WindowsError::ErrorCode.new('STATUS_OBJECT_NAME_NOT_FOUND', 0xC0000034, 'The object name is not found.')
79
+
80
+ # (0xC0000035) The object name already exists.
81
+ STATUS_OBJECT_NAME_COLLISION = WindowsError::ErrorCode.new('STATUS_OBJECT_NAME_COLLISION', 0xC0000035, 'The object name already exists.')
82
+
83
+ # (0xC000003A) The path to the directory specified was not found. This error is also returned on a create request if the operation requires the creation of more than one new directory level for the path specified.
84
+ STATUS_OBJECT_PATH_NOT_FOUND = WindowsError::ErrorCode.new('STATUS_OBJECT_PATH_NOT_FOUND', 0xC000003A, 'The path to the directory specified was not found. This error is also returned on a create request if the operation requires the creation of more than one new directory level for the path specified.')
85
+
86
+ # (0xC00000A5) A specified impersonation level is invalid. This error is also used to indicate that a required impersonation level was not provided.
87
+ STATUS_BAD_IMPERSONATION_LEVEL = WindowsError::ErrorCode.new('STATUS_BAD_IMPERSONATION_LEVEL', 0xC00000A5, 'A specified impersonation level is invalid. This error is also used to indicate that a required impersonation level was not provided.')
88
+
89
+ # (0xC00000B5) The specified I/O operation was not completed before the time-out period expired.
90
+ STATUS_IO_TIMEOUT = WindowsError::ErrorCode.new('STATUS_IO_TIMEOUT', 0xC00000B5, 'The specified I/O operation was not completed before the time-out period expired.')
91
+
92
+ # (0xC00000BA) The file that was specified as a target is a directory and the caller specified that it could be anything but a directory.
93
+ STATUS_FILE_IS_A_DIRECTORY = WindowsError::ErrorCode.new('STATUS_FILE_IS_A_DIRECTORY', 0xC00000BA, 'The file that was specified as a target is a directory and the caller specified that it could be anything but a directory.')
94
+
95
+ # (0xC00000BB) The client request is not supported.
96
+ STATUS_NOT_SUPPORTED = WindowsError::ErrorCode.new('STATUS_NOT_SUPPORTED', 0xC00000BB, 'The client request is not supported.')
97
+
98
+ # (0xC00000C9) The network name specified by the client has been deleted on the server. This error is returned if the client specifies an incorrect TID or the share on the server represented by the TID was deleted.
99
+ STATUS_NETWORK_NAME_DELETED = WindowsError::ErrorCode.new('STATUS_NETWORK_NAME_DELETED', 0xC00000C9, 'The network name specified by the client has been deleted on the server. This error is returned if the client specifies an incorrect TID or the share on the server represented by the TID was deleted.')
100
+
101
+ # (0xC0000203) The user session specified by the client has been deleted on the server. This error is returned by the server if the client sends an incorrect UID.
102
+ STATUS_USER_SESSION_DELETED = WindowsError::ErrorCode.new('STATUS_USER_SESSION_DELETED', 0xC0000203, 'The user session specified by the client has been deleted on the server. This error is returned by the server if the client sends an incorrect UID.')
103
+
104
+ # (0xC000035C) The client's session has expired; therefore, the client MUST re-authenticate to continue accessing remote resources.
105
+ STATUS_NETWORK_SESSION_EXPIRED = WindowsError::ErrorCode.new('STATUS_NETWORK_SESSION_EXPIRED', 0xC000035C, 'The client\'s session has expired; therefore, the client MUST re-authenticate to continue accessing remote resources.')
106
+
107
+ # (0xC000205A) The client has requested too many UID values from the server or the client already has an SMB session setup with this UID value.
108
+ STATUS_SMB_TOO_MANY_UIDS = WindowsError::ErrorCode.new('STATUS_SMB_TOO_MANY_UIDS', 0xC000205A, 'The client has requested too many UID values from the server or the client already has an SMB session setup with this UID value.')
109
+ end
110
+ end
@@ -1,3 +1,3 @@
1
1
  module RubySMB
2
- VERSION = '3.0.0'.freeze
2
+ VERSION = '3.0.4'.freeze
3
3
  end
data/lib/ruby_smb.rb CHANGED
@@ -12,6 +12,7 @@ require 'windows_error/nt_status'
12
12
  # [[MS-SMB2] Server Message Block (SMB) Protocol Versions 2 and 3](https://msdn.microsoft.com/en-us/library/cc246482.aspx)
13
13
  module RubySMB
14
14
  require 'ruby_smb/error'
15
+ require 'ruby_smb/create_actions'
15
16
  require 'ruby_smb/dispositions'
16
17
  require 'ruby_smb/impersonation_levels'
17
18
  require 'ruby_smb/gss'
@@ -28,4 +29,5 @@ module RubySMB
28
29
  require 'ruby_smb/compression'
29
30
  require 'ruby_smb/server'
30
31
  require 'ruby_smb/dialect'
32
+ require 'ruby_smb/smb_error'
31
33
  end
data/ruby_smb.gemspec CHANGED
@@ -34,7 +34,7 @@ Gem::Specification.new do |spec|
34
34
  spec.add_development_dependency 'yard'
35
35
 
36
36
  spec.add_runtime_dependency 'rubyntlm'
37
- spec.add_runtime_dependency 'windows_error'
37
+ spec.add_runtime_dependency 'windows_error', '>= 0.1.3'
38
38
  spec.add_runtime_dependency 'bindata'
39
39
  spec.add_runtime_dependency 'openssl-ccm'
40
40
  spec.add_runtime_dependency 'openssl-cmac'
@@ -557,6 +557,16 @@ RSpec.describe RubySMB::Client do
557
557
  end
558
558
  end
559
559
 
560
+ describe '#wipe_state!' do
561
+ context 'with SMB1' do
562
+ it { expect { smb1_client.wipe_state! }.to_not raise_error }
563
+ end
564
+
565
+ context 'with SMB2' do
566
+ it { expect { smb2_client.wipe_state! }.to_not raise_error }
567
+ end
568
+ end
569
+
560
570
  describe '#logoff!' do
561
571
  context 'with SMB1' do
562
572
  let(:raw_response) { double('Raw response') }
@@ -0,0 +1,30 @@
1
+ RSpec.describe RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcEncryptFileSrvRequest do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :file_name }
5
+
6
+ it 'is little endian' do
7
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
8
+ end
9
+
10
+ describe '#file_name' do
11
+ it 'is a NdrConfVarWideStringz' do
12
+ expect(packet.file_name).to be_a RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz
13
+ end
14
+ end
15
+
16
+ describe '#initialize_instance' do
17
+ it 'sets #opnum to EFS_RPC_ENCRYPT_FILE_SRV constant' do
18
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::EncryptingFileSystem::EFS_RPC_ENCRYPT_FILE_SRV)
19
+ end
20
+ end
21
+
22
+ it 'reads its own binary representation and outputs the same packet' do
23
+ packet = described_class.new(
24
+ file_name: 'file_name'
25
+ )
26
+ binary = packet.to_binary_s
27
+ expect(described_class.read(binary)).to eq(packet)
28
+ end
29
+ end
30
+
@@ -0,0 +1,30 @@
1
+ RSpec.describe RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcEncryptFileSrvResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :error_status }
5
+
6
+ it 'is little endian' do
7
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
8
+ end
9
+
10
+ describe '#error_status' do
11
+ it 'is a NdrUint32' do
12
+ expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
13
+ end
14
+ end
15
+
16
+ describe '#initialize_instance' do
17
+ it 'sets #opnum to EFS_RPC_ENCRYPT_FILE_SRV constant' do
18
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::EncryptingFileSystem::EFS_RPC_ENCRYPT_FILE_SRV)
19
+ end
20
+ end
21
+
22
+ it 'reads its own binary representation and outputs the same packet' do
23
+ packet = described_class.new(
24
+ error_status: 0
25
+ )
26
+ binary = packet.to_binary_s
27
+ expect(described_class.read(binary)).to eq(packet)
28
+ end
29
+ end
30
+
@@ -0,0 +1,38 @@
1
+ RSpec.describe RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcOpenFileRawRequest do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :file_name }
5
+ it { is_expected.to respond_to :flags }
6
+
7
+ it 'is little endian' do
8
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
9
+ end
10
+
11
+ describe '#file_name' do
12
+ it 'is a NdrConfVarWideStringz' do
13
+ expect(packet.file_name).to be_a RubySMB::Dcerpc::Ndr::NdrConfVarWideStringz
14
+ end
15
+ end
16
+
17
+ describe '#flags' do
18
+ it 'is a NdrUint32' do
19
+ expect(packet.flags).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
20
+ end
21
+ end
22
+
23
+ describe '#initialize_instance' do
24
+ it 'sets #opnum to EFS_RPC_OPEN_FILE_RAW constant' do
25
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::EncryptingFileSystem::EFS_RPC_OPEN_FILE_RAW)
26
+ end
27
+ end
28
+
29
+ it 'reads its own binary representation and outputs the same packet' do
30
+ packet = described_class.new(
31
+ file_name: 'file_name',
32
+ flags: 0
33
+ )
34
+ binary = packet.to_binary_s
35
+ expect(described_class.read(binary)).to eq(packet)
36
+ end
37
+ end
38
+
@@ -0,0 +1,38 @@
1
+ RSpec.describe RubySMB::Dcerpc::EncryptingFileSystem::EfsRpcOpenFileRawResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :h_context }
5
+ it { is_expected.to respond_to :error_status }
6
+
7
+ it 'is little endian' do
8
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
9
+ end
10
+
11
+ describe '#h_context' do
12
+ it 'is a NdrContextHandle' do
13
+ expect(packet.h_context).to be_a RubySMB::Dcerpc::Ndr::NdrContextHandle
14
+ end
15
+ end
16
+
17
+ describe '#error_status' do
18
+ it 'is a NdrUint32' do
19
+ expect(packet.error_status).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
20
+ end
21
+ end
22
+
23
+ describe '#initialize_instance' do
24
+ it 'sets #opnum to EFS_RPC_OPEN_FILE_RAW constant' do
25
+ expect(packet.opnum).to eq(RubySMB::Dcerpc::EncryptingFileSystem::EFS_RPC_OPEN_FILE_RAW)
26
+ end
27
+ end
28
+
29
+ it 'reads its own binary representation and outputs the same packet' do
30
+ packet = described_class.new(
31
+ h_context: RubySMB::Dcerpc::Ndr::NdrContextHandle.new,
32
+ error_status: 0
33
+ )
34
+ binary = packet.to_binary_s
35
+ expect(described_class.read(binary)).to eq(packet)
36
+ end
37
+ end
38
+
@@ -0,0 +1,41 @@
1
+ RSpec.describe RubySMB::Dcerpc::PrintSystem::DriverContainer do
2
+ subject(:struct) { described_class.new }
3
+
4
+ it { is_expected.to respond_to :level }
5
+ it { is_expected.to respond_to :tag }
6
+ it { is_expected.to respond_to :driver_info }
7
+
8
+ it 'is little endian' do
9
+ expect(described_class.fields.instance_variable_get(:@hints)[:endian]).to eq :little
10
+ end
11
+
12
+ describe '#level' do
13
+ it 'is a NdrUint32' do
14
+ expect(struct.level).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
15
+ end
16
+ end
17
+
18
+ describe '#tag' do
19
+ it 'is a NdrUint32' do
20
+ expect(struct.tag).to be_a RubySMB::Dcerpc::Ndr::NdrUint32
21
+ end
22
+ end
23
+
24
+ it 'reads its own binary representation and outputs the same struct' do
25
+ struct = described_class.new(
26
+ level: 2,
27
+ tag: 0,
28
+ driver_info: RubySMB::Dcerpc::PrintSystem::DriverInfo2.new(
29
+ c_version: 0,
30
+ p_name: 'p_name',
31
+ p_environment: 'p_environment',
32
+ p_driver_path: 'p_driver_path',
33
+ p_data_file: 'p_data_file',
34
+ p_config_file: 'p_config_file'
35
+ )
36
+ )
37
+ binary = struct.to_binary_s
38
+ expect(described_class.read(binary)).to eq(struct)
39
+ end
40
+ end
41
+