ruby_smb 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/.travis.yml +4 -1
- data/README.md +35 -47
- data/examples/enum_registry_key.rb +28 -0
- data/examples/enum_registry_values.rb +30 -0
- data/examples/pipes.rb +2 -1
- data/examples/read_registry_key_value.rb +32 -0
- data/lib/ruby_smb/client/authentication.rb +43 -25
- data/lib/ruby_smb/client/echo.rb +20 -2
- data/lib/ruby_smb/client/negotiation.rb +27 -12
- data/lib/ruby_smb/client/tree_connect.rb +20 -14
- data/lib/ruby_smb/client/utils.rb +2 -2
- data/lib/ruby_smb/client/winreg.rb +46 -0
- data/lib/ruby_smb/client.rb +28 -4
- data/lib/ruby_smb/dcerpc/bind.rb +2 -2
- data/lib/ruby_smb/dcerpc/bind_ack.rb +2 -2
- data/lib/ruby_smb/dcerpc/error.rb +3 -0
- data/lib/ruby_smb/dcerpc/ndr.rb +95 -16
- data/lib/ruby_smb/dcerpc/pdu_header.rb +1 -1
- data/lib/ruby_smb/dcerpc/request.rb +28 -9
- data/lib/ruby_smb/dcerpc/rrp_unicode_string.rb +35 -0
- data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +9 -0
- data/lib/ruby_smb/dcerpc/srvsvc.rb +10 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_request.rb +24 -0
- data/lib/ruby_smb/dcerpc/winreg/close_key_response.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_request.rb +45 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_key_response.rb +42 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/enum_value_response.rb +36 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_request.rb +34 -0
- data/lib/ruby_smb/dcerpc/winreg/open_key_response.rb +25 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_request.rb +43 -0
- data/lib/ruby_smb/dcerpc/winreg/open_root_key_response.rb +35 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_request.rb +27 -0
- data/lib/ruby_smb/dcerpc/winreg/query_info_key_response.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_request.rb +39 -0
- data/lib/ruby_smb/dcerpc/winreg/query_value_response.rb +57 -0
- data/lib/ruby_smb/dcerpc/winreg/regsam.rb +40 -0
- data/lib/ruby_smb/dcerpc/winreg.rb +340 -0
- data/lib/ruby_smb/dcerpc.rb +38 -0
- data/lib/ruby_smb/dispatcher/socket.rb +3 -1
- data/lib/ruby_smb/error.rb +40 -1
- data/lib/ruby_smb/generic_packet.rb +33 -4
- data/lib/ruby_smb/smb1/file.rb +67 -11
- data/lib/ruby_smb/smb1/packet/close_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/empty_packet.rb +10 -1
- data/lib/ruby_smb/smb1/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/negotiate_response.rb +3 -7
- data/lib/ruby_smb/smb1/packet/negotiate_response_extended.rb +4 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_create_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/create_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/nt_trans/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/nt_trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/read_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/read_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_legacy_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_request.rb +0 -1
- data/lib/ruby_smb/smb1/packet/trans/peek_nmpipe_response.rb +3 -2
- data/lib/ruby_smb/smb1/packet/trans/request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/trans/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +1 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_first2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/find_next2_response.rb +8 -2
- data/lib/ruby_smb/smb1/packet/trans2/open2_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/open2_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/request_secondary.rb +2 -4
- data/lib/ruby_smb/smb1/packet/trans2/response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_request.rb +2 -1
- data/lib/ruby_smb/smb1/packet/trans2/set_file_information_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/tree_connect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_connect_response.rb +13 -3
- data/lib/ruby_smb/smb1/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb1/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb1/packet/write_andx_request.rb +2 -5
- data/lib/ruby_smb/smb1/packet/write_andx_response.rb +2 -1
- data/lib/ruby_smb/smb1/pipe.rb +86 -5
- data/lib/ruby_smb/smb1/tree.rb +40 -2
- data/lib/ruby_smb/smb2/file.rb +97 -1
- data/lib/ruby_smb/smb2/packet/close_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/close_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/create_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/create_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/echo_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/echo_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/error_packet.rb +15 -3
- data/lib/ruby_smb/smb2/packet/ioctl_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/ioctl_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/logoff_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/logoff_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/negotiate_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/negotiate_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/query_directory_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/query_directory_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/read_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/read_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/session_setup_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/session_setup_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/set_info_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/set_info_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/tree_connect_request.rb +2 -5
- data/lib/ruby_smb/smb2/packet/tree_connect_response.rb +8 -2
- data/lib/ruby_smb/smb2/packet/tree_disconnect_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/tree_disconnect_response.rb +2 -1
- data/lib/ruby_smb/smb2/packet/write_request.rb +2 -4
- data/lib/ruby_smb/smb2/packet/write_response.rb +2 -1
- data/lib/ruby_smb/smb2/pipe.rb +98 -11
- data/lib/ruby_smb/smb2/tree.rb +44 -6
- data/lib/ruby_smb/version.rb +1 -1
- data/lib/ruby_smb.rb +0 -1
- data/ruby_smb.gemspec +3 -3
- data/spec/lib/ruby_smb/client_spec.rb +271 -11
- data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +2 -2
- data/spec/lib/ruby_smb/dcerpc/ndr_spec.rb +410 -0
- data/spec/lib/ruby_smb/dcerpc/request_spec.rb +50 -7
- data/spec/lib/ruby_smb/dcerpc/rrp_unicode_string_spec.rb +98 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +13 -0
- data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +60 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_request_spec.rb +28 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/close_key_response_spec.rb +36 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_request_spec.rb +108 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_key_response_spec.rb +97 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_request_spec.rb +94 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/enum_value_response_spec.rb +82 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_request_spec.rb +74 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_key_response_spec.rb +35 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_request_spec.rb +90 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/open_root_key_response_spec.rb +38 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_request_spec.rb +39 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_info_key_response_spec.rb +113 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_request_spec.rb +88 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/query_value_response_spec.rb +150 -0
- data/spec/lib/ruby_smb/dcerpc/winreg/regsam_spec.rb +32 -0
- data/spec/lib/ruby_smb/dcerpc/winreg_spec.rb +710 -0
- data/spec/lib/ruby_smb/dcerpc_spec.rb +81 -0
- data/spec/lib/ruby_smb/dispatcher/socket_spec.rb +3 -1
- data/spec/lib/ruby_smb/generic_packet_spec.rb +52 -4
- data/spec/lib/ruby_smb/smb1/file_spec.rb +191 -2
- data/spec/lib/ruby_smb/smb1/packet/empty_packet_spec.rb +68 -0
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_first2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/trans2/find_next2_response_spec.rb +11 -2
- data/spec/lib/ruby_smb/smb1/packet/tree_connect_response_spec.rb +40 -0
- data/spec/lib/ruby_smb/smb1/pipe_spec.rb +272 -149
- data/spec/lib/ruby_smb/smb1/tree_spec.rb +44 -7
- data/spec/lib/ruby_smb/smb2/file_spec.rb +295 -2
- data/spec/lib/ruby_smb/smb2/packet/error_packet_spec.rb +78 -0
- data/spec/lib/ruby_smb/smb2/packet/query_directory_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/packet/tree_connect_response_spec.rb +8 -0
- data/spec/lib/ruby_smb/smb2/pipe_spec.rb +322 -145
- data/spec/lib/ruby_smb/smb2/tree_spec.rb +214 -0
- data.tar.gz.sig +0 -0
- metadata +70 -11
- metadata.gz.sig +0 -0
- data/lib/ruby_smb/smb1/dcerpc.rb +0 -67
- data/lib/ruby_smb/smb2/dcerpc.rb +0 -70
- data/spec/lib/ruby_smb/smb1/packet/error_packet_spec.rb +0 -37
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
module RubySMB
|
|
2
|
+
module Dcerpc
|
|
3
|
+
module Winreg
|
|
4
|
+
|
|
5
|
+
UUID = '338CD001-2244-31F1-AAAA-900038001003'
|
|
6
|
+
VER_MAJOR = 1
|
|
7
|
+
VER_MINOR = 0
|
|
8
|
+
|
|
9
|
+
# Operation numbers
|
|
10
|
+
OPEN_HKCR = 0x00
|
|
11
|
+
OPEN_HKCU = 0x01
|
|
12
|
+
OPEN_HKLM = 0x02
|
|
13
|
+
OPEN_HKPD = 0x03
|
|
14
|
+
OPEN_HKU = 0x04
|
|
15
|
+
REG_CLOSE_KEY = 0x05
|
|
16
|
+
REG_ENUM_KEY = 0x09
|
|
17
|
+
REG_ENUM_VALUE = 0x0a
|
|
18
|
+
REG_OPEN_KEY = 0x0f
|
|
19
|
+
REG_QUERY_INFO_KEY = 0x10
|
|
20
|
+
REG_QUERY_VALUE = 0x11
|
|
21
|
+
OPEN_HKCC = 0x1b
|
|
22
|
+
OPEN_HKPT = 0x20
|
|
23
|
+
OPEN_HKPN = 0x21
|
|
24
|
+
|
|
25
|
+
require 'ruby_smb/dcerpc/winreg/regsam'
|
|
26
|
+
require 'ruby_smb/dcerpc/winreg/open_root_key_request'
|
|
27
|
+
require 'ruby_smb/dcerpc/winreg/open_root_key_response'
|
|
28
|
+
require 'ruby_smb/dcerpc/winreg/close_key_request'
|
|
29
|
+
require 'ruby_smb/dcerpc/winreg/close_key_response'
|
|
30
|
+
require 'ruby_smb/dcerpc/winreg/enum_key_request'
|
|
31
|
+
require 'ruby_smb/dcerpc/winreg/enum_key_response'
|
|
32
|
+
require 'ruby_smb/dcerpc/winreg/enum_value_request'
|
|
33
|
+
require 'ruby_smb/dcerpc/winreg/enum_value_response'
|
|
34
|
+
require 'ruby_smb/dcerpc/winreg/open_key_request'
|
|
35
|
+
require 'ruby_smb/dcerpc/winreg/open_key_response'
|
|
36
|
+
require 'ruby_smb/dcerpc/winreg/query_info_key_request'
|
|
37
|
+
require 'ruby_smb/dcerpc/winreg/query_info_key_response'
|
|
38
|
+
require 'ruby_smb/dcerpc/winreg/query_value_request'
|
|
39
|
+
require 'ruby_smb/dcerpc/winreg/query_value_response'
|
|
40
|
+
|
|
41
|
+
ROOT_KEY_MAP = {
|
|
42
|
+
"HKEY_CLASSES_ROOT" => OPEN_HKCR,
|
|
43
|
+
"HKCR" => OPEN_HKCR,
|
|
44
|
+
"HKEY_CURRENT_USER" => OPEN_HKCU,
|
|
45
|
+
"HKCU" => OPEN_HKCU,
|
|
46
|
+
"HKEY_LOCAL_MACHINE" => OPEN_HKLM,
|
|
47
|
+
"HKLM" => OPEN_HKLM,
|
|
48
|
+
"HKEY_PERFORMANCE_DATA" => OPEN_HKPD,
|
|
49
|
+
"HKPD" => OPEN_HKPD,
|
|
50
|
+
"HKEY_USERS" => OPEN_HKU,
|
|
51
|
+
"HKU" => OPEN_HKU,
|
|
52
|
+
"HKEY_CURRENT_CONFIG" => OPEN_HKCC,
|
|
53
|
+
"HKCC" => OPEN_HKCC,
|
|
54
|
+
"HKEY_PERFORMANCE_TEXT" => OPEN_HKPT,
|
|
55
|
+
"HKPT" => OPEN_HKPT,
|
|
56
|
+
"HKEY_PERFORMANCE_NLS_TEXT" => OPEN_HKPN,
|
|
57
|
+
"HKPN" => OPEN_HKPN
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# Open the registry root key and return a handle for it. The key can be
|
|
61
|
+
# either a long format (e.g. HKEY_LOCAL_MACHINE) or a short format
|
|
62
|
+
# (e.g. HKLM)
|
|
63
|
+
#
|
|
64
|
+
# @param root_key [String] the root key to open
|
|
65
|
+
# @return [Ndr::NdrContextHandle] the RPC context handle for the root key
|
|
66
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenRootKeyResponse packet
|
|
67
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
|
68
|
+
def open_root_key(root_key)
|
|
69
|
+
root_key_opnum = RubySMB::Dcerpc::Winreg::ROOT_KEY_MAP[root_key]
|
|
70
|
+
raise ArgumentError, "Unknown Root Key: #{root_key}" unless root_key_opnum
|
|
71
|
+
|
|
72
|
+
root_key_request_packet = OpenRootKeyRequest.new(opnum: root_key_opnum)
|
|
73
|
+
response = dcerpc_request(root_key_request_packet)
|
|
74
|
+
|
|
75
|
+
begin
|
|
76
|
+
root_key_response_packet = OpenRootKeyResponse.read(response)
|
|
77
|
+
rescue IOError
|
|
78
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket,
|
|
79
|
+
"Error reading OpenRootKeyResponse (command = #{root_key_opnum})"
|
|
80
|
+
end
|
|
81
|
+
unless root_key_response_packet.error_status == WindowsError::Win32::ERROR_SUCCESS
|
|
82
|
+
raise RubySMB::Dcerpc::Error::WinregError,
|
|
83
|
+
"Error returned when opening root key #{root_key}: "\
|
|
84
|
+
"#{WindowsError::Win32.find_by_retval(root_key_response_packet.error_status.value).join(',')}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
root_key_response_packet.ph_key
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Open the registry key specified by a root key handle (previously open
|
|
91
|
+
# with #open_root_key) and a subkey. It returns a handle for the key.
|
|
92
|
+
#
|
|
93
|
+
# @param handle [Ndr::NdrContextHandle] the handle for the root key
|
|
94
|
+
# @param sub_key [String] the subkey to open
|
|
95
|
+
# @return [Ndr::NdrContextHandle] the RPC context handle for the key
|
|
96
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a OpenKeyResponse packet
|
|
97
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
|
98
|
+
def open_key(handle, sub_key)
|
|
99
|
+
openkey_request_packet = RubySMB::Dcerpc::Winreg::OpenKeyRequest.new(hkey: handle, lp_sub_key: sub_key)
|
|
100
|
+
openkey_request_packet.sam_desired.read_control = 1
|
|
101
|
+
openkey_request_packet.sam_desired.key_query_value = 1
|
|
102
|
+
openkey_request_packet.sam_desired.key_enumerate_sub_keys = 1
|
|
103
|
+
openkey_request_packet.sam_desired.key_notify = 1
|
|
104
|
+
response = dcerpc_request(openkey_request_packet)
|
|
105
|
+
begin
|
|
106
|
+
open_key_response = RubySMB::Dcerpc::Winreg::OpenKeyResponse.read(response)
|
|
107
|
+
rescue IOError
|
|
108
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the OpenKey response"
|
|
109
|
+
end
|
|
110
|
+
unless open_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
|
111
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when opening subkey #{sub_key}: "\
|
|
112
|
+
"#{WindowsError::Win32.find_by_retval(open_key_response.error_status.value).join(',')}"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
open_key_response.phk_result
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Retrieve the data associated with the named value of a specified
|
|
119
|
+
# registry open key.
|
|
120
|
+
#
|
|
121
|
+
# @param handle [Ndr::NdrContextHandle] the handle for the key
|
|
122
|
+
# @param value_name [String] the name of the value
|
|
123
|
+
# @return [String] the data of the value entry
|
|
124
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryValueResponse packet
|
|
125
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
|
126
|
+
def query_value(handle, value_name)
|
|
127
|
+
query_value_request_packet = RubySMB::Dcerpc::Winreg::QueryValueRequest.new(hkey: handle, lp_value_name: value_name)
|
|
128
|
+
query_value_request_packet.lp_data.referent_identifier = 0
|
|
129
|
+
response = dcerpc_request(query_value_request_packet)
|
|
130
|
+
begin
|
|
131
|
+
query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
|
|
132
|
+
rescue IOError
|
|
133
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the QueryValue response"
|
|
134
|
+
end
|
|
135
|
+
unless query_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
|
136
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when reading value #{value_name}: "\
|
|
137
|
+
"#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
query_value_request_packet = RubySMB::Dcerpc::Winreg::QueryValueRequest.new(hkey: handle, lp_value_name: value_name)
|
|
141
|
+
query_value_request_packet.lpcb_data = query_value_response.lpcb_data
|
|
142
|
+
query_value_request_packet.lp_data.max_count = query_value_response.lpcb_data.referent
|
|
143
|
+
response = dcerpc_request(query_value_request_packet)
|
|
144
|
+
begin
|
|
145
|
+
query_value_response = RubySMB::Dcerpc::Winreg::QueryValueResponse.read(response)
|
|
146
|
+
rescue IOError
|
|
147
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the QueryValue response"
|
|
148
|
+
end
|
|
149
|
+
unless query_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
|
150
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when reading value #{value_name}: "\
|
|
151
|
+
"#{WindowsError::Win32.find_by_retval(query_value_response.error_status.value).join(',')}"
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
query_value_response.data
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Close the handle to the registry key.
|
|
158
|
+
#
|
|
159
|
+
# @param handle [Ndr::NdrContextHandle] the handle for the key
|
|
160
|
+
# @return [WindowsError::Win32] the response error status
|
|
161
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a CloseKeyResponse packet
|
|
162
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
|
163
|
+
def close_key(handle)
|
|
164
|
+
close_key_request_packet = RubySMB::Dcerpc::Winreg::CloseKeyRequest.new(hkey: handle)
|
|
165
|
+
response = dcerpc_request(close_key_request_packet)
|
|
166
|
+
begin
|
|
167
|
+
close_key_response = RubySMB::Dcerpc::Winreg::CloseKeyResponse.read(response)
|
|
168
|
+
rescue IOError
|
|
169
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the CloseKey response"
|
|
170
|
+
end
|
|
171
|
+
unless close_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
|
172
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when closing the key: "\
|
|
173
|
+
"#{WindowsError::Win32.find_by_retval(close_key_response.error_status.value).join(',')}"
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
close_key_response.error_status
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
# Retrive relevant information on the key that corresponds to the
|
|
180
|
+
# specified key handle.
|
|
181
|
+
#
|
|
182
|
+
# @param handle [Ndr::NdrContextHandle] the handle for the key
|
|
183
|
+
# @return [RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse] the QueryInfoKeyResponse packet
|
|
184
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a QueryInfoKeyResponse packet
|
|
185
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
|
186
|
+
def query_info_key(handle)
|
|
187
|
+
query_info_key_request_packet = RubySMB::Dcerpc::Winreg::QueryInfoKeyRequest.new(hkey: handle)
|
|
188
|
+
response = dcerpc_request(query_info_key_request_packet)
|
|
189
|
+
begin
|
|
190
|
+
query_info_key_response = RubySMB::Dcerpc::Winreg::QueryInfoKeyResponse.read(response)
|
|
191
|
+
rescue IOError
|
|
192
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the query_infoKey response"
|
|
193
|
+
end
|
|
194
|
+
unless query_info_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
|
195
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when querying information: "\
|
|
196
|
+
"#{WindowsError::Win32.find_by_retval(query_info_key_response.error_status.value).join(',')}"
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
query_info_key_response
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
# Enumerate the subkey at the specified index.
|
|
203
|
+
#
|
|
204
|
+
# @param handle [Ndr::NdrContextHandle] the handle for the key
|
|
205
|
+
# @param index [Numeric] the index of the subkey
|
|
206
|
+
# @return [String] the subkey name
|
|
207
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a EnumKeyResponse packet
|
|
208
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
|
209
|
+
def enum_key(handle, index)
|
|
210
|
+
enum_key_request_packet = RubySMB::Dcerpc::Winreg::EnumKeyRequest.new(hkey: handle, dw_index: index)
|
|
211
|
+
enum_key_request_packet.lpft_last_write_time = 0
|
|
212
|
+
enum_key_request_packet.lp_class.referent.buffer = 0
|
|
213
|
+
enum_key_request_packet.lp_name.buffer.referent.max_count = 256
|
|
214
|
+
response = dcerpc_request(enum_key_request_packet)
|
|
215
|
+
begin
|
|
216
|
+
enum_key_response = RubySMB::Dcerpc::Winreg::EnumKeyResponse.read(response)
|
|
217
|
+
rescue IOError
|
|
218
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the EnumKey response"
|
|
219
|
+
end
|
|
220
|
+
unless enum_key_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
|
221
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when enumerating the key: "\
|
|
222
|
+
"#{WindowsError::Win32.find_by_retval(enum_key_response.error_status.value).join(',')}"
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
enum_key_response.lp_name.to_s
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Enumerate the value at the specified index for the specified registry key.
|
|
229
|
+
#
|
|
230
|
+
# @param handle [Ndr::NdrContextHandle] the handle for the key
|
|
231
|
+
# @param index [Numeric] the index of the subkey
|
|
232
|
+
# @return [String] the data of the value entry
|
|
233
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if the response is not a EnumValueResponse packet
|
|
234
|
+
# @raise [RubySMB::Dcerpc::Error::WinregError] if the response error status is not ERROR_SUCCESS
|
|
235
|
+
def enum_value(handle, index)
|
|
236
|
+
enum_value_request_packet = RubySMB::Dcerpc::Winreg::EnumValueRequest.new(hkey: handle, dw_index: index)
|
|
237
|
+
enum_value_request_packet.lp_data.referent_identifier = 0
|
|
238
|
+
enum_value_request_packet.lp_value_name.buffer.referent.max_count = 256
|
|
239
|
+
response = dcerpc_request(enum_value_request_packet)
|
|
240
|
+
begin
|
|
241
|
+
enum_value_response = RubySMB::Dcerpc::Winreg::EnumValueResponse.read(response)
|
|
242
|
+
rescue IOError
|
|
243
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the Enumvalue response"
|
|
244
|
+
end
|
|
245
|
+
unless enum_value_response.error_status == WindowsError::Win32::ERROR_SUCCESS
|
|
246
|
+
raise RubySMB::Dcerpc::Error::WinregError, "Error returned when enumerating values: "\
|
|
247
|
+
"#{WindowsError::Win32.find_by_retval(enum_value_response.error_status.value).join(',')}"
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
enum_value_response.lp_value_name.to_s
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Checks if the specified registry key exists. It returns true if it
|
|
254
|
+
# exists, false otherwise.
|
|
255
|
+
#
|
|
256
|
+
# @param key [String] the registry key to check
|
|
257
|
+
# @return [Boolean]
|
|
258
|
+
def has_registry_key?(key)
|
|
259
|
+
bind(endpoint: RubySMB::Dcerpc::Winreg)
|
|
260
|
+
|
|
261
|
+
root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
|
|
262
|
+
begin
|
|
263
|
+
root_key_handle = open_root_key(root_key)
|
|
264
|
+
subkey_handle = open_key(root_key_handle, sub_key)
|
|
265
|
+
rescue RubySMB::Dcerpc::Error::WinregError
|
|
266
|
+
return false
|
|
267
|
+
end
|
|
268
|
+
close_key(subkey_handle)
|
|
269
|
+
return true
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
# Retrieve the data associated with the named value of a specified
|
|
273
|
+
# registry key.
|
|
274
|
+
#
|
|
275
|
+
# @param key [String] the registry key
|
|
276
|
+
# @param value_name [String] the name of the value to read
|
|
277
|
+
# @return [String] the data of the value entry
|
|
278
|
+
def read_registry_key_value(key, value_name)
|
|
279
|
+
bind(endpoint: RubySMB::Dcerpc::Winreg)
|
|
280
|
+
|
|
281
|
+
root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
|
|
282
|
+
root_key_handle = open_root_key(root_key)
|
|
283
|
+
subkey_handle = open_key(root_key_handle, sub_key)
|
|
284
|
+
value = query_value(subkey_handle, value_name)
|
|
285
|
+
close_key(subkey_handle)
|
|
286
|
+
value
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# Enumerate the subkeys of a specified registry key. If only a root key
|
|
290
|
+
# is provided, it enumerates its subkeys.
|
|
291
|
+
#
|
|
292
|
+
# @param key [String] the registry key
|
|
293
|
+
# @return [Array<String>] the subkeys
|
|
294
|
+
def enum_registry_key(key)
|
|
295
|
+
bind(endpoint: RubySMB::Dcerpc::Winreg)
|
|
296
|
+
|
|
297
|
+
root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
|
|
298
|
+
root_key_handle = open_root_key(root_key)
|
|
299
|
+
subkey_handle = if sub_key.nil? || sub_key.empty?
|
|
300
|
+
root_key_handle
|
|
301
|
+
else
|
|
302
|
+
open_key(root_key_handle, sub_key)
|
|
303
|
+
end
|
|
304
|
+
query_info_key_response = query_info_key(subkey_handle)
|
|
305
|
+
key_count = query_info_key_response.lpc_sub_keys.to_i
|
|
306
|
+
enum_result = []
|
|
307
|
+
key_count.times do |i|
|
|
308
|
+
enum_result << enum_key(subkey_handle, i)
|
|
309
|
+
end
|
|
310
|
+
close_key(subkey_handle)
|
|
311
|
+
enum_result
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Enumerate the values for the specified registry key.
|
|
315
|
+
#
|
|
316
|
+
# @param key [String] the registry key
|
|
317
|
+
# @return [Array<String>] the values
|
|
318
|
+
def enum_registry_values(key)
|
|
319
|
+
bind(endpoint: RubySMB::Dcerpc::Winreg)
|
|
320
|
+
|
|
321
|
+
root_key, sub_key = key.gsub(/\//, '\\').split('\\', 2)
|
|
322
|
+
root_key_handle = open_root_key(root_key)
|
|
323
|
+
subkey_handle = if sub_key.nil? || sub_key.empty?
|
|
324
|
+
root_key_handle
|
|
325
|
+
else
|
|
326
|
+
open_key(root_key_handle, sub_key)
|
|
327
|
+
end
|
|
328
|
+
query_info_key_response = query_info_key(subkey_handle)
|
|
329
|
+
value_count = query_info_key_response.lpc_values.to_i
|
|
330
|
+
enum_result = []
|
|
331
|
+
value_count.times do |i|
|
|
332
|
+
enum_result << enum_value(subkey_handle, i)
|
|
333
|
+
end
|
|
334
|
+
close_key(subkey_handle)
|
|
335
|
+
enum_result
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
end
|
data/lib/ruby_smb/dcerpc.rb
CHANGED
|
@@ -1,15 +1,53 @@
|
|
|
1
1
|
module RubySMB
|
|
2
2
|
module Dcerpc
|
|
3
|
+
MAX_XMIT_FRAG = 4280
|
|
4
|
+
MAX_RECV_FRAG = 4280
|
|
5
|
+
|
|
6
|
+
require 'windows_error/win32'
|
|
3
7
|
require 'ruby_smb/dcerpc/error'
|
|
4
8
|
require 'ruby_smb/dcerpc/uuid'
|
|
5
9
|
require 'ruby_smb/dcerpc/ndr'
|
|
6
10
|
require 'ruby_smb/dcerpc/ptypes'
|
|
7
11
|
require 'ruby_smb/dcerpc/p_syntax_id_t'
|
|
12
|
+
require 'ruby_smb/dcerpc/rrp_unicode_string'
|
|
8
13
|
require 'ruby_smb/dcerpc/pdu_header'
|
|
9
14
|
require 'ruby_smb/dcerpc/srvsvc'
|
|
15
|
+
require 'ruby_smb/dcerpc/winreg'
|
|
10
16
|
require 'ruby_smb/dcerpc/request'
|
|
11
17
|
require 'ruby_smb/dcerpc/response'
|
|
12
18
|
require 'ruby_smb/dcerpc/bind'
|
|
13
19
|
require 'ruby_smb/dcerpc/bind_ack'
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
# Bind to the remote server interface endpoint.
|
|
23
|
+
#
|
|
24
|
+
# @param options [Hash] the options to pass to the Bind request packet. At least, :endpoint must but provided with an existing Dcerpc class
|
|
25
|
+
# @return [RubySMB::Dcerpc::BindAck] the BindAck response packet
|
|
26
|
+
# @raise [RubySMB::Dcerpc::Error::InvalidPacket] if an invalid packet is received
|
|
27
|
+
# @raise [RubySMB::Dcerpc::Error::BindError] if the response is not a BindAck packet or if the Bind result code is not ACCEPTANCE
|
|
28
|
+
def bind(options={})
|
|
29
|
+
bind_req = RubySMB::Dcerpc::Bind.new(options)
|
|
30
|
+
write(data: bind_req.to_binary_s)
|
|
31
|
+
@size = 1024
|
|
32
|
+
dcerpc_raw_response = read()
|
|
33
|
+
begin
|
|
34
|
+
dcerpc_response = RubySMB::Dcerpc::BindAck.read(dcerpc_raw_response)
|
|
35
|
+
rescue IOError
|
|
36
|
+
raise RubySMB::Dcerpc::Error::InvalidPacket, "Error reading the DCERPC response"
|
|
37
|
+
end
|
|
38
|
+
unless dcerpc_response.pdu_header.ptype == RubySMB::Dcerpc::PTypes::BIND_ACK
|
|
39
|
+
raise RubySMB::Dcerpc::Error::BindError, "Not a BindAck packet"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
res_list = dcerpc_response.p_result_list
|
|
43
|
+
if res_list.n_results == 0 ||
|
|
44
|
+
res_list.p_results[0].result != RubySMB::Dcerpc::BindAck::ACCEPTANCE
|
|
45
|
+
raise RubySMB::Dcerpc::Error::BindError,
|
|
46
|
+
"Bind Failed (Result: #{res_list.p_results[0].result}, Reason: #{res_list.p_results[0].reason})"
|
|
47
|
+
end
|
|
48
|
+
@tree.client.max_buffer_size = dcerpc_response.max_xmit_frag
|
|
49
|
+
dcerpc_response
|
|
50
|
+
end
|
|
51
|
+
|
|
14
52
|
end
|
|
15
53
|
end
|
|
@@ -66,7 +66,9 @@ module RubySMB
|
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
begin
|
|
69
|
-
|
|
69
|
+
nbss_data = @tcp_socket.read(4)
|
|
70
|
+
raise IOError if nbss_data.nil?
|
|
71
|
+
nbss_header = RubySMB::Nbss::SessionHeader.read(nbss_data)
|
|
70
72
|
rescue IOError
|
|
71
73
|
raise ::RubySMB::Error::NetBiosSessionService, 'NBSS Header is missing'
|
|
72
74
|
end
|
data/lib/ruby_smb/error.rb
CHANGED
|
@@ -15,7 +15,42 @@ module RubySMB
|
|
|
15
15
|
|
|
16
16
|
# Raised when trying to parse raw binary into a Packet and the data
|
|
17
17
|
# is invalid.
|
|
18
|
-
class InvalidPacket < RubySMBError
|
|
18
|
+
class InvalidPacket < RubySMBError
|
|
19
|
+
def initialize(args = nil)
|
|
20
|
+
if args.nil?
|
|
21
|
+
super
|
|
22
|
+
elsif args.is_a? String
|
|
23
|
+
super(args)
|
|
24
|
+
elsif args.is_a? Hash
|
|
25
|
+
expected_proto = args[:expected_proto] ? translate_protocol(args[:expected_proto]) : "???"
|
|
26
|
+
expected_cmd = args[:expected_cmd] || "???"
|
|
27
|
+
received_proto = args[:received_proto] ? translate_protocol(args[:received_proto]) : "???"
|
|
28
|
+
received_cmd = args[:received_cmd] || "???"
|
|
29
|
+
super(
|
|
30
|
+
"Expecting #{expected_proto} protocol "\
|
|
31
|
+
"with command=#{expected_cmd}"\
|
|
32
|
+
"#{(" (" + args[:expected_custom] + ")") if args[:expected_custom]}, "\
|
|
33
|
+
"got #{received_proto} protocol "\
|
|
34
|
+
"with command=#{received_cmd}"\
|
|
35
|
+
"#{(" (" + args[:received_custom] + ")") if args[:received_custom]}"
|
|
36
|
+
)
|
|
37
|
+
else
|
|
38
|
+
raise ArgumentError, "InvalidPacket expects a String or a Hash, got a #{args.class}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def translate_protocol(proto)
|
|
43
|
+
case proto
|
|
44
|
+
when RubySMB::SMB1::SMB_PROTOCOL_ID
|
|
45
|
+
'SMB1'
|
|
46
|
+
when RubySMB::SMB2::SMB2_PROTOCOL_ID
|
|
47
|
+
'SMB2'
|
|
48
|
+
else
|
|
49
|
+
raise ArgumentError, 'Unknown SMB protocol'
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
private :translate_protocol
|
|
53
|
+
end
|
|
19
54
|
|
|
20
55
|
# Raised when a response packet has a NTStatus code that was unexpected.
|
|
21
56
|
class UnexpectedStatusCode < RubySMBError; end
|
|
@@ -26,5 +61,9 @@ module RubySMB
|
|
|
26
61
|
# Raised when Protocol Negotiation fails, possibly due to an
|
|
27
62
|
# unsupported protocol.
|
|
28
63
|
class NegotiationFailure < RubySMBError; end
|
|
64
|
+
|
|
65
|
+
# Raised when trying to parse raw binary into a BitField and the data
|
|
66
|
+
# is invalid.
|
|
67
|
+
class InvalidBitField < RubySMBError; end
|
|
29
68
|
end
|
|
30
69
|
end
|
|
@@ -45,14 +45,16 @@ module RubySMB
|
|
|
45
45
|
rescue IOError => e
|
|
46
46
|
case self.to_s
|
|
47
47
|
when /EmptyPacket|ErrorPacket/
|
|
48
|
-
raise
|
|
48
|
+
raise RubySMB::Error::InvalidPacket, 'Not a valid SMB packet'
|
|
49
49
|
when /SMB1/
|
|
50
|
-
RubySMB::SMB1::Packet::EmptyPacket.read(val)
|
|
50
|
+
packet = RubySMB::SMB1::Packet::EmptyPacket.read(val)
|
|
51
51
|
when /SMB2/
|
|
52
|
-
RubySMB::SMB2::Packet::ErrorPacket.read(val)
|
|
52
|
+
packet = RubySMB::SMB2::Packet::ErrorPacket.read(val)
|
|
53
53
|
else
|
|
54
|
-
raise
|
|
54
|
+
raise RubySMB::Error::InvalidPacket, 'Not a valid SMB packet'
|
|
55
55
|
end
|
|
56
|
+
packet.original_command = self::COMMAND
|
|
57
|
+
packet
|
|
56
58
|
end
|
|
57
59
|
end
|
|
58
60
|
|
|
@@ -72,6 +74,33 @@ module RubySMB
|
|
|
72
74
|
status_code
|
|
73
75
|
end
|
|
74
76
|
|
|
77
|
+
# Validates the packet protocol ID and the SMB command
|
|
78
|
+
#
|
|
79
|
+
# @return [TrueClass, FalseClass] true if the packet is valid, false otherwise
|
|
80
|
+
def valid?
|
|
81
|
+
case packet_smb_version
|
|
82
|
+
when 'SMB1'
|
|
83
|
+
return smb_header.protocol == RubySMB::SMB1::SMB_PROTOCOL_ID &&
|
|
84
|
+
smb_header.command == self.class::COMMAND
|
|
85
|
+
when 'SMB2'
|
|
86
|
+
return smb2_header.protocol == RubySMB::SMB2::SMB2_PROTOCOL_ID &&
|
|
87
|
+
smb2_header.command == self.class::COMMAND
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def initialize_instance
|
|
92
|
+
super
|
|
93
|
+
|
|
94
|
+
unless [RubySMB::SMB1::Packet::EmptyPacket, RubySMB::SMB2::Packet::ErrorPacket].any? {|klass| self.is_a? klass}
|
|
95
|
+
case packet_smb_version
|
|
96
|
+
when 'SMB1'
|
|
97
|
+
smb_header.command = self.class::COMMAND
|
|
98
|
+
when 'SMB2'
|
|
99
|
+
smb2_header.command = self.class::COMMAND
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
75
104
|
# Returns an array of hashes representing the
|
|
76
105
|
# fields for this record.
|
|
77
106
|
#
|
data/lib/ruby_smb/smb1/file.rb
CHANGED
|
@@ -76,14 +76,19 @@ module RubySMB
|
|
|
76
76
|
# Closes the handle to the remote file.
|
|
77
77
|
#
|
|
78
78
|
# @return [WindowsError::ErrorCode] the NTStatus code returned by the operation
|
|
79
|
-
# @raise [RubySMB::Error::InvalidPacket] if the response
|
|
79
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
|
|
80
80
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
|
81
81
|
def close
|
|
82
82
|
close_request = set_header_fields(RubySMB::SMB1::Packet::CloseRequest.new)
|
|
83
83
|
raw_response = @tree.client.send_recv(close_request)
|
|
84
84
|
response = RubySMB::SMB1::Packet::CloseResponse.read(raw_response)
|
|
85
|
-
unless response.
|
|
86
|
-
raise RubySMB::Error::InvalidPacket
|
|
85
|
+
unless response.valid?
|
|
86
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
87
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
88
|
+
expected_cmd: RubySMB::SMB1::Packet::CloseResponse::COMMAND,
|
|
89
|
+
received_proto: response.smb_header.protocol,
|
|
90
|
+
received_cmd: response.smb_header.command
|
|
91
|
+
)
|
|
87
92
|
end
|
|
88
93
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
89
94
|
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
|
@@ -98,7 +103,7 @@ module RubySMB
|
|
|
98
103
|
# @param bytes [Integer] the number of bytes to read
|
|
99
104
|
# @param offset [Integer] the byte offset in the file to start reading from
|
|
100
105
|
# @return [String] the data read from the file
|
|
101
|
-
# @raise [RubySMB::Error::InvalidPacket] if the response
|
|
106
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
|
|
102
107
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
|
103
108
|
def read(bytes: @size, offset: 0)
|
|
104
109
|
atomic_read_size = if bytes > @tree.client.max_buffer_size
|
|
@@ -113,8 +118,13 @@ module RubySMB
|
|
|
113
118
|
read_request = read_packet(read_length: atomic_read_size, offset: offset)
|
|
114
119
|
raw_response = @tree.client.send_recv(read_request)
|
|
115
120
|
response = RubySMB::SMB1::Packet::ReadAndxResponse.read(raw_response)
|
|
116
|
-
unless response.
|
|
117
|
-
raise RubySMB::Error::InvalidPacket
|
|
121
|
+
unless response.valid?
|
|
122
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
123
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
124
|
+
expected_cmd: RubySMB::SMB1::Packet::ReadAndxResponse::COMMAND,
|
|
125
|
+
received_proto: response.smb_header.protocol,
|
|
126
|
+
received_cmd: response.smb_header.command
|
|
127
|
+
)
|
|
118
128
|
end
|
|
119
129
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
120
130
|
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
|
@@ -146,23 +156,47 @@ module RubySMB
|
|
|
146
156
|
def read_packet(read_length: 0, offset: 0)
|
|
147
157
|
read_request = set_header_fields(RubySMB::SMB1::Packet::ReadAndxRequest.new)
|
|
148
158
|
read_request.parameter_block.max_count_of_bytes_to_return = read_length
|
|
159
|
+
read_request.parameter_block.min_count_of_bytes_to_return = read_length
|
|
160
|
+
read_request.parameter_block.remaining = read_length
|
|
149
161
|
read_request.parameter_block.offset = offset
|
|
150
162
|
read_request
|
|
151
163
|
end
|
|
152
|
-
|
|
164
|
+
|
|
153
165
|
def send_recv_read(read_length: 0, offset: 0)
|
|
154
166
|
read_request = read_packet(read_length: read_length, offset: offset)
|
|
155
167
|
raw_response = tree.client.send_recv(read_request)
|
|
168
|
+
|
|
156
169
|
response = RubySMB::SMB1::Packet::ReadAndxResponse.read(raw_response)
|
|
170
|
+
unless response.valid?
|
|
171
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
172
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
173
|
+
expected_cmd: RubySMB::SMB1::Packet::ReadAndxResponse::COMMAND,
|
|
174
|
+
received_proto: response.smb_header.protocol,
|
|
175
|
+
received_cmd: response.smb_header.command
|
|
176
|
+
)
|
|
177
|
+
end
|
|
178
|
+
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
179
|
+
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
|
180
|
+
end
|
|
181
|
+
|
|
157
182
|
response.data_block.data.to_binary_s
|
|
158
183
|
end
|
|
159
184
|
|
|
160
185
|
# Delete a file on close
|
|
161
186
|
#
|
|
162
187
|
# @return [WindowsError::ErrorCode] the NTStatus Response code
|
|
188
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
|
|
163
189
|
def delete
|
|
164
190
|
raw_response = @tree.client.send_recv(delete_packet)
|
|
165
191
|
response = RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse.read(raw_response)
|
|
192
|
+
unless response.valid?
|
|
193
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
194
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
195
|
+
expected_cmd: RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse::COMMAND,
|
|
196
|
+
received_proto: response.smb_header.protocol,
|
|
197
|
+
received_cmd: response.smb_header.command
|
|
198
|
+
)
|
|
199
|
+
end
|
|
166
200
|
response.status_code
|
|
167
201
|
end
|
|
168
202
|
|
|
@@ -185,7 +219,7 @@ module RubySMB
|
|
|
185
219
|
# @param data [String] the data to write to the file
|
|
186
220
|
# @param offset [Integer] the offset in the file to start writing from
|
|
187
221
|
# @return [Integer] the count of bytes written
|
|
188
|
-
# @raise [RubySMB::Error::InvalidPacket] if the response
|
|
222
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
|
|
189
223
|
# @raise [RubySMB::Error::UnexpectedStatusCode] if the response NTStatus is not STATUS_SUCCESS
|
|
190
224
|
def write(data:, offset: 0)
|
|
191
225
|
buffer = data.dup
|
|
@@ -201,8 +235,13 @@ module RubySMB
|
|
|
201
235
|
write_request = write_packet(data: buffer.slice!(0, atomic_write_size), offset: offset)
|
|
202
236
|
raw_response = @tree.client.send_recv(write_request)
|
|
203
237
|
response = RubySMB::SMB1::Packet::WriteAndxResponse.read(raw_response)
|
|
204
|
-
unless response.
|
|
205
|
-
raise RubySMB::Error::InvalidPacket
|
|
238
|
+
unless response.valid?
|
|
239
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
240
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
241
|
+
expected_cmd: RubySMB::SMB1::Packet::WriteAndxResponse::COMMAND,
|
|
242
|
+
received_proto: response.smb_header.protocol,
|
|
243
|
+
received_cmd: response.smb_header.command
|
|
244
|
+
)
|
|
206
245
|
end
|
|
207
246
|
unless response.status_code == WindowsError::NTStatus::STATUS_SUCCESS
|
|
208
247
|
raise RubySMB::Error::UnexpectedStatusCode, response.status_code.name
|
|
@@ -230,12 +269,20 @@ module RubySMB
|
|
|
230
269
|
write_request.parameter_block.remaining = write_request.parameter_block.data_length
|
|
231
270
|
write_request
|
|
232
271
|
end
|
|
233
|
-
|
|
272
|
+
|
|
234
273
|
def send_recv_write(data:'', offset: 0)
|
|
235
274
|
pkt = write_packet(data: data, offset: offset)
|
|
236
275
|
pkt.set_64_bit_offset(true)
|
|
237
276
|
raw_response = @tree.client.send_recv(pkt)
|
|
238
277
|
response = RubySMB::SMB1::Packet::WriteAndxResponse.read(raw_response)
|
|
278
|
+
unless response.valid?
|
|
279
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
280
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
281
|
+
expected_cmd: RubySMB::SMB1::Packet::WriteAndxResponse::COMMAND,
|
|
282
|
+
received_proto: response.smb_header.protocol,
|
|
283
|
+
received_cmd: response.smb_header.command
|
|
284
|
+
)
|
|
285
|
+
end
|
|
239
286
|
response.parameter_block.count_low
|
|
240
287
|
end
|
|
241
288
|
|
|
@@ -243,9 +290,18 @@ module RubySMB
|
|
|
243
290
|
#
|
|
244
291
|
# @param new_file_name [String] the new name
|
|
245
292
|
# @return [WindowsError::ErrorCode] the NTStatus Response code
|
|
293
|
+
# @raise [RubySMB::Error::InvalidPacket] if the response packet is not valid
|
|
246
294
|
def rename(new_file_name)
|
|
247
295
|
raw_response = tree.client.send_recv(rename_packet(new_file_name))
|
|
248
296
|
response = RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse.read(raw_response)
|
|
297
|
+
unless response.valid?
|
|
298
|
+
raise RubySMB::Error::InvalidPacket.new(
|
|
299
|
+
expected_proto: RubySMB::SMB1::SMB_PROTOCOL_ID,
|
|
300
|
+
expected_cmd: RubySMB::SMB1::Packet::Trans2::SetFileInformationResponse::COMMAND,
|
|
301
|
+
received_proto: response.smb_header.protocol,
|
|
302
|
+
received_cmd: response.smb_header.command
|
|
303
|
+
)
|
|
304
|
+
end
|
|
249
305
|
response.status_code
|
|
250
306
|
end
|
|
251
307
|
|