ruby_smb 0.0.21 → 0.0.22

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 (62) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/examples/net_share_enum_all.rb +5 -2
  5. data/lib/ruby_smb.rb +1 -1
  6. data/lib/ruby_smb/client.rb +4 -35
  7. data/lib/ruby_smb/dcerpc.rb +7 -22
  8. data/lib/ruby_smb/dcerpc/bind.rb +30 -36
  9. data/lib/ruby_smb/dcerpc/bind_ack.rb +72 -0
  10. data/lib/ruby_smb/dcerpc/error.rb +15 -0
  11. data/lib/ruby_smb/dcerpc/ndr.rb +31 -30
  12. data/lib/ruby_smb/dcerpc/p_syntax_id_t.rb +11 -0
  13. data/lib/ruby_smb/dcerpc/pdu_header.rb +29 -0
  14. data/lib/ruby_smb/dcerpc/ptypes.rb +26 -0
  15. data/lib/ruby_smb/dcerpc/request.rb +17 -30
  16. data/lib/ruby_smb/dcerpc/response.rb +15 -34
  17. data/lib/ruby_smb/dcerpc/srvsvc.rb +5 -7
  18. data/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all.rb +8 -4
  19. data/lib/ruby_smb/dcerpc/uuid.rb +31 -13
  20. data/lib/ruby_smb/smb1/bit_field.rb +0 -1
  21. data/lib/ruby_smb/smb1/bit_field/trans_flags.rb +3 -2
  22. data/lib/ruby_smb/smb1/data_block.rb +5 -0
  23. data/lib/ruby_smb/smb1/dcerpc.rb +67 -0
  24. data/lib/ruby_smb/smb1/packet.rb +1 -0
  25. data/lib/ruby_smb/smb1/packet/trans.rb +7 -1
  26. data/lib/ruby_smb/smb1/packet/trans/data_block.rb +19 -7
  27. data/lib/ruby_smb/smb1/packet/trans/request.rb +36 -25
  28. data/lib/ruby_smb/smb1/packet/trans/response.rb +22 -21
  29. data/lib/ruby_smb/smb1/packet/trans/subcommands.rb +1 -0
  30. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request.rb +61 -0
  31. data/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response.rb +44 -0
  32. data/lib/ruby_smb/smb1/packet/trans2/request.rb +1 -1
  33. data/lib/ruby_smb/smb1/pipe.rb +3 -0
  34. data/lib/ruby_smb/smb2/dcerpc.rb +68 -0
  35. data/lib/ruby_smb/smb2/pipe.rb +3 -0
  36. data/lib/ruby_smb/version.rb +1 -1
  37. data/spec/lib/ruby_smb/client_spec.rb +53 -6
  38. data/spec/lib/ruby_smb/dcerpc/bind_ack_spec.rb +224 -0
  39. data/spec/lib/ruby_smb/dcerpc/bind_spec.rb +255 -7
  40. data/spec/lib/ruby_smb/dcerpc/p_syntax_id_t_spec.rb +31 -0
  41. data/spec/lib/ruby_smb/dcerpc/pdu_header_spec.rb +84 -0
  42. data/spec/lib/ruby_smb/dcerpc/request_spec.rb +106 -13
  43. data/spec/lib/ruby_smb/dcerpc/response_spec.rb +89 -8
  44. data/spec/lib/ruby_smb/dcerpc/srvsvc/net_share_enum_all_spec.rb +176 -0
  45. data/spec/lib/ruby_smb/dcerpc/uuid_spec.rb +97 -1
  46. data/spec/lib/ruby_smb/smb1/data_block_spec.rb +43 -3
  47. data/spec/lib/ruby_smb/smb1/packet/trans/data_block_spec.rb +137 -0
  48. data/spec/lib/ruby_smb/smb1/packet/trans/request_spec.rb +239 -13
  49. data/spec/lib/ruby_smb/smb1/packet/trans/response_spec.rb +122 -13
  50. data/spec/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_request_spec.rb +254 -0
  51. data/spec/lib/ruby_smb/smb1/packet/trans/transact_nmpipe_response_spec.rb +122 -0
  52. data/spec/lib/ruby_smb/smb1/packet/trans2/request_spec.rb +2 -2
  53. data/spec/lib/ruby_smb/smb1/pipe_spec.rb +199 -1
  54. data/spec/lib/ruby_smb/smb2/file_spec.rb +2 -1
  55. data/spec/lib/ruby_smb/smb2/pipe_spec.rb +196 -1
  56. metadata +25 -10
  57. metadata.gz.sig +0 -0
  58. data/lib/ruby_smb/dcerpc/handle.rb +0 -60
  59. data/lib/ruby_smb/smb1/bit_field/trans2_flags.rb +0 -15
  60. data/spec/lib/ruby_smb/dcerpc/handle_spec.rb +0 -31
  61. data/spec/lib/ruby_smb/dcerpc/srvsvc_spec.rb +0 -13
  62. data/spec/lib/ruby_smb/smb1/bit_field/trans2_flags_spec.rb +0 -26
@@ -0,0 +1,254 @@
1
+ RSpec.describe RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest do
2
+ subject(:packet) { described_class.new }
3
+
4
+ describe '#smb_header' do
5
+ subject(:header) { packet.smb_header }
6
+
7
+ it 'is a standard SMB Header' do
8
+ expect(header).to be_a RubySMB::SMB1::SMBHeader
9
+ end
10
+
11
+ it 'should have the command set to SMB_COM_TRANSACTION' do
12
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
13
+ end
14
+
15
+ it 'should not have the response flag set' do
16
+ expect(header.flags.reply).to eq 0
17
+ end
18
+ end
19
+
20
+ describe '#parameter_block' do
21
+ subject(:parameter_block) { packet.parameter_block }
22
+
23
+ it 'is a Packet Trans Request ParameterBlock' do
24
+ expect(parameter_block).to be_a RubySMB::SMB1::Packet::Trans::Request::ParameterBlock
25
+ end
26
+
27
+ describe '#total_parameter_count' do
28
+ it 'is set to 0x0000' do
29
+ expect(parameter_block.total_parameter_count).to eq(0x0000)
30
+ end
31
+ end
32
+
33
+ describe '#total_data_count' do
34
+ it 'has a default value equal to #data_count' do
35
+ parameter_block.data_count = 5
36
+ expect(parameter_block.total_data_count).to eq 5
37
+ end
38
+ end
39
+
40
+ describe '#max_parameter_count' do
41
+ it 'is set to 0x0000' do
42
+ expect(parameter_block.max_parameter_count).to eq(0x0000)
43
+ end
44
+ end
45
+
46
+ describe '#max_setup_count' do
47
+ it 'is set to 0x00' do
48
+ expect(parameter_block.max_setup_count).to eq(0x00)
49
+ end
50
+ end
51
+
52
+ describe '#flags' do
53
+ it 'is set to 0x0000' do
54
+ expect(parameter_block.flags.to_binary_s.to_i).to eq(0x0000)
55
+ end
56
+ end
57
+
58
+ describe '#timeout' do
59
+ it 'is set to 0x00000000' do
60
+ expect(parameter_block.timeout).to eq 0x00000000
61
+ end
62
+ end
63
+
64
+ describe '#parameter_count' do
65
+ it 'is set to 0x0000' do
66
+ expect(parameter_block.parameter_count).to eq(0x0000)
67
+ end
68
+ end
69
+
70
+ describe '#data_count' do
71
+ it 'is set to the number of data bytes to be written to the named pipe' do
72
+ packet.data_block.trans_data.write_data = "\x00\x01\x02\x03"
73
+ expect(parameter_block.data_count).to eq 4
74
+ end
75
+ end
76
+
77
+ describe '#setup_count' do
78
+ it 'is set to 2' do
79
+ expect(parameter_block.setup_count).to eq(2)
80
+ end
81
+ end
82
+
83
+ describe '#setup' do
84
+ it 'includes the TRANSACT_NMPIPE subcommand code' do
85
+ expect(parameter_block.setup[0]).to eq(RubySMB::SMB1::Packet::Trans::Subcommands::TRANSACT_NMPIPE)
86
+ end
87
+
88
+ it 'includes the FID set to 0x0000 by default' do
89
+ expect(parameter_block.setup[1]).to eq(0x0000)
90
+ end
91
+ end
92
+ end
93
+
94
+ describe '#data_block' do
95
+ subject(:data_block) { packet.data_block }
96
+
97
+ it 'is a standard DataBlock' do
98
+ expect(data_block).to be_a RubySMB::SMB1::DataBlock
99
+ end
100
+
101
+ it { is_expected.to respond_to :name }
102
+ it { is_expected.to respond_to :trans_parameters }
103
+ it { is_expected.to respond_to :trans_data }
104
+
105
+ describe '#pad_name' do
106
+ context 'when the UNICODE flag is not set in the Flags2 field of the SMB Header' do
107
+ it 'does not exists' do
108
+ expect(data_block).to_not be_pad_name
109
+ end
110
+ end
111
+
112
+ context 'when the UNICODE flag is set in the Flags2 field of the SMB Header' do
113
+ before :example do
114
+ packet.smb_header.flags2.unicode = 1
115
+ end
116
+
117
+ it 'exists' do
118
+ expect(data_block).to be_pad_name
119
+ end
120
+
121
+ it 'is one null byte when #name is not 2-byte aligned' do
122
+ expect(data_block.pad_name).to eq("\x00")
123
+ end
124
+
125
+ it 'should keep #name 2-byte aligned' do
126
+ expect(data_block.name.abs_offset % 2).to eq 0
127
+ end
128
+ end
129
+ end
130
+
131
+ describe '#name' do
132
+ context 'when the UNICODE flag is not set in the Flags2 field of the SMB Header' do
133
+ it 'is a Stringz' do
134
+ expect(data_block.name.current_choice).to be_a BinData::Stringz
135
+ end
136
+
137
+ it 'is ASCII encoded' do
138
+ expect(data_block.name.encoding.name).to eq("ASCII-8BIT")
139
+ end
140
+
141
+ it 'is set to "\\PIPE\\\x00" by default' do
142
+ expect(data_block.name.to_binary_s).to eq("\\PIPE\\\x00")
143
+ end
144
+
145
+ it 'adds a NULL terminator to the string' do
146
+ str = "test"
147
+ data_block.name = str
148
+ expect(data_block.name.to_binary_s).to eq(str + "\x00")
149
+ end
150
+ end
151
+
152
+ context 'when the UNICODE flag is set in the Flags2 field of the SMB Header' do
153
+ before :example do
154
+ packet.smb_header.flags2.unicode = 1
155
+ end
156
+
157
+ it 'is a Stringz16' do
158
+ expect(data_block.name.current_choice).to be_a RubySMB::Field::Stringz16
159
+ end
160
+
161
+ it 'is UTF-16LE encoded' do
162
+ expect(data_block.name.encoding.name).to eq("UTF-16LE")
163
+ end
164
+
165
+ it 'is set to the null terminated unicode string "\\PIPE\\" by default' do
166
+ binary_str = "\\PIPE\\\x00".encode('utf-16le').force_encoding('ASCII')
167
+ expect(data_block.name.to_binary_s).to eq(binary_str)
168
+ end
169
+
170
+ it 'adds a NULL terminator to the string' do
171
+ str = "test"
172
+ data_block.name = str
173
+ binary_str = (str + "\x00").encode('utf-16le').force_encoding('ASCII')
174
+ expect(data_block.name.to_binary_s).to eq(binary_str)
175
+ end
176
+ end
177
+
178
+ context 'when switching from ASCII to UNICODE' do
179
+ it 'encodes the same string to UNICODE' do
180
+ packet = RubySMB::SMB1::Packet::Trans::Request.new
181
+ data_block = packet.data_block
182
+
183
+ str = "test"
184
+ data_block.name = str
185
+ expect(data_block.name.to_binary_s).to eq(str + "\x00")
186
+ packet.smb_header.flags2.unicode = 1
187
+ binary_str = (str + "\x00").encode('utf-16le').force_encoding('ASCII')
188
+ expect(data_block.name.to_binary_s).to eq(binary_str)
189
+ end
190
+ end
191
+ end
192
+
193
+ describe '#trans_parameters' do
194
+ it 'is a String' do
195
+ expect(data_block.trans_parameters).to be_a BinData::String
196
+ end
197
+
198
+ it 'reads the number of bytes specified in parameter_block parameter_count field' do
199
+ packet.parameter_block.parameter_count = 3
200
+ data_block.trans_parameters.read("ABCDEF")
201
+ expect(data_block.trans_parameters).to eq("ABC")
202
+ end
203
+ end
204
+
205
+ describe '#trans_data' do
206
+ subject(:data) { data_block.trans_data }
207
+
208
+ it { is_expected.to respond_to :write_data }
209
+
210
+ describe '#write_data' do
211
+ it 'is a String' do
212
+ expect(data.write_data).to be_a BinData::String
213
+ end
214
+
215
+ it 'reads the number of bytes specified in parameter_block parameter_count field' do
216
+ packet.parameter_block.data_count = 3
217
+ data.write_data.read("ABCDEF")
218
+ expect(data.write_data).to eq("ABC")
219
+ end
220
+ end
221
+ end
222
+
223
+ describe '#pad1' do
224
+ it 'should keep #trans_parameters 4-byte aligned' do
225
+ expect(data_block.trans_parameters.abs_offset % 4).to eq 0
226
+ end
227
+ end
228
+
229
+ describe '#pad2' do
230
+ it 'should keep #trans_data 4-byte aligned' do
231
+ data_block.trans_parameters = 'a'
232
+ expect(data_block.trans_data.abs_offset % 4).to eq 0
233
+ end
234
+ end
235
+ end
236
+
237
+ describe '#set_fid' do
238
+ it 'sets the FID in the parameter_block #setup field' do
239
+ fid = 0xAABB
240
+ packet.set_fid(fid)
241
+ expect(packet.parameter_block.setup[1]).to eq(fid)
242
+ end
243
+ end
244
+
245
+ it 'reads its own binary representation and output the same packet' do
246
+ # Adding some data to the ParameterBlock and DataBlock to make sure
247
+ # paddings and lengths are handled correctly
248
+ packet.set_fid(0xAABB)
249
+ packet.data_block.trans_data.write_data = 'a'
250
+ binary = packet.to_binary_s
251
+ expect(described_class.read(binary)).to eq(packet)
252
+ end
253
+ end
254
+
@@ -0,0 +1,122 @@
1
+ RSpec.describe RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse do
2
+ subject(:packet) { described_class.new }
3
+
4
+ describe '#smb_header' do
5
+ subject(:header) { packet.smb_header }
6
+
7
+ it 'is a standard SMB Header' do
8
+ expect(header).to be_a RubySMB::SMB1::SMBHeader
9
+ end
10
+
11
+ it 'should have the command set to SMB_COM_TRANSACTION' do
12
+ expect(header.command).to eq RubySMB::SMB1::Commands::SMB_COM_TRANSACTION
13
+ end
14
+
15
+ it 'should have the response flag set' do
16
+ expect(header.flags.reply).to eq 1
17
+ end
18
+ end
19
+
20
+ describe '#parameter_block' do
21
+ subject(:parameter_block) { packet.parameter_block }
22
+
23
+ it 'is a Packet Trans Response ParameterBlock' do
24
+ expect(parameter_block).to be_a RubySMB::SMB1::Packet::Trans::Response::ParameterBlock
25
+ end
26
+
27
+ describe '#total_parameter_count' do
28
+ it 'is set to 0x0000' do
29
+ expect(parameter_block.total_parameter_count).to eq(0x0000)
30
+ end
31
+ end
32
+
33
+ describe '#total_data_count' do
34
+ it 'has a default value equal to #data_count' do
35
+ parameter_block.data_count = 5
36
+ expect(parameter_block.total_data_count).to eq 5
37
+ end
38
+ end
39
+
40
+ describe '#parameter_count' do
41
+ it 'is set to 0x0000' do
42
+ expect(parameter_block.parameter_count).to eq(0x0000)
43
+ end
44
+ end
45
+
46
+ describe '#data_count' do
47
+ it 'is set to the number of data bytes read from the named pipe' do
48
+ packet.data_block.trans_data.read_data = "\x00\x01\x02\x03"
49
+ expect(parameter_block.data_count).to eq 4
50
+ end
51
+ end
52
+
53
+ describe '#setup_count' do
54
+ it 'is set to 0' do
55
+ expect(parameter_block.setup_count).to eq(0)
56
+ end
57
+ end
58
+ end
59
+
60
+ describe '#data_block' do
61
+ subject(:data_block) { packet.data_block }
62
+
63
+ it 'is a standard DataBlock' do
64
+ expect(data_block).to be_a RubySMB::SMB1::DataBlock
65
+ end
66
+
67
+ it { is_expected.to respond_to :trans_parameters }
68
+ it { is_expected.to respond_to :trans_data }
69
+
70
+ describe '#trans_parameters' do
71
+ it 'is a String' do
72
+ expect(data_block.trans_parameters).to be_a BinData::String
73
+ end
74
+
75
+ it 'reads the number of bytes specified in parameter_block parameter_count field' do
76
+ packet.parameter_block.parameter_count = 3
77
+ data_block.trans_parameters.read("ABCDEF")
78
+ expect(data_block.trans_parameters).to eq("ABC")
79
+ end
80
+ end
81
+
82
+ describe '#trans_data' do
83
+ subject(:data) { data_block.trans_data }
84
+
85
+ it { is_expected.to respond_to :read_data }
86
+
87
+ describe '#read_data' do
88
+ it 'is a String' do
89
+ expect(data.read_data).to be_a BinData::String
90
+ end
91
+
92
+ it 'reads the number of bytes specified in parameter_block parameter_count field' do
93
+ packet.parameter_block.data_count = 3
94
+ data.read_data.read("ABCDEF")
95
+ expect(data.read_data).to eq("ABC")
96
+ end
97
+ end
98
+ end
99
+
100
+ describe '#pad1' do
101
+ it 'should keep #trans_parameters 4-byte aligned' do
102
+ expect(data_block.trans_parameters.abs_offset % 4).to eq 0
103
+ end
104
+ end
105
+
106
+ describe '#pad2' do
107
+ it 'should keep #trans_data 4-byte aligned' do
108
+ data_block.trans_parameters = 'a'
109
+ expect(data_block.trans_data.abs_offset % 4).to eq 0
110
+ end
111
+ end
112
+ end
113
+
114
+ it 'reads its own binary representation and output the same packet' do
115
+ # Adding some data to the DataBlock to make sure
116
+ # paddings and lengths are handled correctly
117
+ packet.data_block.trans_data.read_data = 'a'
118
+ binary = packet.to_binary_s
119
+ expect(described_class.read(binary)).to eq(packet)
120
+ end
121
+ end
122
+
@@ -39,8 +39,8 @@ RSpec.describe RubySMB::SMB1::Packet::Trans2::Request do
39
39
  it { is_expected.to respond_to :setup_count }
40
40
 
41
41
  describe 'flags' do
42
- it 'is a trans2_flags BitField' do
43
- expect(parameter_block.flags).to be_a RubySMB::SMB1::BitField::Trans2Flags
42
+ it 'is a trans_flags BitField' do
43
+ expect(parameter_block.flags).to be_a RubySMB::SMB1::BitField::TransFlags
44
44
  end
45
45
  end
46
46
 
@@ -62,4 +62,202 @@ RSpec.describe RubySMB::SMB1::Pipe do
62
62
  end
63
63
  end
64
64
 
65
- end
65
+ context 'with DCERPC' do
66
+ describe '#net_share_enum_all' do
67
+ let(:host) { '1.2.3.4' }
68
+ let(:dcerpc_response) { RubySMB::Dcerpc::Response.new }
69
+
70
+ before :example do
71
+ allow(pipe).to receive(:bind)
72
+ allow(pipe).to receive(:request).and_return(dcerpc_response)
73
+ allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return([])
74
+ end
75
+
76
+ it 'calls #bind with the expected arguments' do
77
+ expect(pipe).to receive(:bind).with(endpoint: RubySMB::Dcerpc::Srvsvc)
78
+ pipe.net_share_enum_all(host)
79
+ end
80
+
81
+ it 'calls #request with the expected arguments' do
82
+ expect(pipe).to receive(:request).with(RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL, host: host)
83
+ pipe.net_share_enum_all(host)
84
+ end
85
+
86
+ it 'parse the response with NetShareEnumAll #parse_response method' do
87
+ stub = 'ABCD'
88
+ dcerpc_response.alloc_hint = stub.size
89
+ dcerpc_response.stub = stub
90
+ expect(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).with(stub)
91
+ pipe.net_share_enum_all(host)
92
+ end
93
+
94
+ it 'returns the remote shares' do
95
+ shares = [
96
+ ["C$", "DISK", "Default share"],
97
+ ["Shared", "DISK", ""],
98
+ ["IPC$", "IPC", "Remote IPC"],
99
+ ["ADMIN$", "DISK", "Remote Admin"]
100
+ ]
101
+ output = [
102
+ {:name=>"C$", :type=>"DISK", :comment=>"Default share"},
103
+ {:name=>"Shared", :type=>"DISK", :comment=>""},
104
+ {:name=>"IPC$", :type=>"IPC", :comment=>"Remote IPC"},
105
+ {:name=>"ADMIN$", :type=>"DISK", :comment=>"Remote Admin"},
106
+ ]
107
+ allow(RubySMB::Dcerpc::Srvsvc::NetShareEnumAll).to receive(:parse_response).and_return(shares)
108
+ expect(pipe.net_share_enum_all(host)).to eq(output)
109
+ end
110
+ end
111
+
112
+ describe '#bind' do
113
+ let(:options) { { endpoint: RubySMB::Dcerpc::Srvsvc } }
114
+ let(:bind_packet) { RubySMB::Dcerpc::Bind.new(options) }
115
+ let(:bind_ack_packet) { RubySMB::Dcerpc::BindAck.new }
116
+
117
+ before :example do
118
+ allow(RubySMB::Dcerpc::Bind).to receive(:new).and_return(bind_packet)
119
+ allow(pipe).to receive(:write)
120
+ allow(pipe).to receive(:read)
121
+ bind_ack_packet.p_result_list.n_results = 1
122
+ bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::ACCEPTANCE
123
+ allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(bind_ack_packet)
124
+ end
125
+
126
+ it 'creates a Bind packet' do
127
+ expect(RubySMB::Dcerpc::Bind).to receive(:new).with(options).and_return(bind_packet)
128
+ pipe.bind(options)
129
+ end
130
+
131
+ it 'writes to the named pipe' do
132
+ expect(pipe).to receive(:write).with(data: bind_packet.to_binary_s)
133
+ pipe.bind(options)
134
+ end
135
+
136
+ it 'reads the socket' do
137
+ expect(pipe).to receive(:read)
138
+ pipe.bind(options)
139
+ end
140
+
141
+ it 'creates a BindAck packet from the response' do
142
+ raw_response = RubySMB::Dcerpc::BindAck.new.to_binary_s
143
+ allow(pipe).to receive(:read).and_return(raw_response)
144
+ expect(RubySMB::Dcerpc::BindAck).to receive(:read).with(raw_response).and_return(bind_ack_packet)
145
+ pipe.bind(options)
146
+ end
147
+
148
+ it 'raises the expected exception when an invalid packet is received' do
149
+ allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_raise(IOError)
150
+ expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
151
+ end
152
+
153
+ it 'raises the expected exception when it is not a BindAck packet' do
154
+ response = RubySMB::Dcerpc::Bind.new
155
+ allow(RubySMB::Dcerpc::BindAck).to receive(:read).and_return(response)
156
+ expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
157
+ end
158
+
159
+ it 'raises an exception when no result is returned' do
160
+ bind_ack_packet.p_result_list.n_results = 0
161
+ expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
162
+ end
163
+
164
+ it 'raises an exception when result is not ACCEPTANCE' do
165
+ bind_ack_packet.p_result_list.p_results[0].result = RubySMB::Dcerpc::BindAck::USER_REJECTION
166
+ expect { pipe.bind(options) }.to raise_error(RubySMB::Dcerpc::Error::BindError)
167
+ end
168
+
169
+ it 'returns the expected BindAck packet' do
170
+ expect(pipe.bind(options)).to eq(bind_ack_packet)
171
+ end
172
+ end
173
+
174
+ describe '#request' do
175
+ let(:options) { { host: '1.2.3.4' } }
176
+ let(:opnum) { RubySMB::Dcerpc::Srvsvc::NET_SHARE_ENUM_ALL }
177
+ let(:req_packet) { RubySMB::Dcerpc::Request.new({ :opnum => opnum }, options) }
178
+ let(:nmpipe_packet) { RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest.new(options) }
179
+ let(:nmpipe_response) { RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse.new }
180
+ let(:res_packet) { RubySMB::Dcerpc::Response.new }
181
+
182
+ before :example do
183
+ allow(RubySMB::Dcerpc::Request).to receive(:new).and_return(req_packet)
184
+ allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to receive(:new).and_return(nmpipe_packet)
185
+ allow(client).to receive(:send_recv)
186
+ allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(nmpipe_response)
187
+ allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(res_packet)
188
+ end
189
+
190
+ it 'creates a Request packet' do
191
+ expect(RubySMB::Dcerpc::Request).to receive(:new).and_return(req_packet)
192
+ pipe.request(opnum, options)
193
+ end
194
+
195
+ it 'creates a Trans TransactNmpipeRequest packet' do
196
+ expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeRequest).to receive(:new).and_return(nmpipe_packet)
197
+ pipe.request(opnum, options)
198
+ end
199
+
200
+ it 'calls Tree #set_header_fields' do
201
+ expect(tree).to receive(:set_header_fields).with(nmpipe_packet)
202
+ pipe.request(opnum, options)
203
+ end
204
+
205
+ it 'calls TransactNmpipeRequest #set_fid' do
206
+ expect(nmpipe_packet).to receive(:set_fid).with(pipe.fid)
207
+ pipe.request(opnum, options)
208
+ end
209
+
210
+ it 'sets the expected data on the request' do
211
+ expect(client).to receive(:send_recv) do
212
+ expect(nmpipe_packet.data_block.trans_data.write_data).to eq(req_packet.to_binary_s)
213
+ end
214
+ pipe.request(opnum, options)
215
+ end
216
+
217
+ it 'sends the expected request' do
218
+ expect(client).to receive(:send_recv).with(nmpipe_packet)
219
+ pipe.request(opnum, options)
220
+ end
221
+
222
+ it 'creates a Trans TransactNmpipeResponse packet from the response' do
223
+ raw_response = double('Raw response')
224
+ allow(client).to receive(:send_recv).and_return(raw_response)
225
+ expect(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).with(raw_response).and_return(nmpipe_response)
226
+ pipe.request(opnum, options)
227
+ end
228
+
229
+ it 'raises the expected exception when it is not a Trans packet' do
230
+ response = RubySMB::SMB1::Packet::Trans2::Response.new
231
+ allow(RubySMB::SMB1::Packet::Trans::TransactNmpipeResponse).to receive(:read).and_return(response)
232
+ expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Error::InvalidPacket)
233
+ end
234
+
235
+ it 'raises the expected exception when the status code is not STATUS_SUCCESS' do
236
+ nmpipe_response.smb_header.nt_status = WindowsError::NTStatus::STATUS_INVALID_HANDLE.value
237
+ expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Error::UnexpectedStatusCode)
238
+ end
239
+
240
+ it 'creates a DCERPC Response packet from the response' do
241
+ nmpipe_response.data_block.trans_data.read_data = "test"
242
+ expect(RubySMB::Dcerpc::Response).to receive(:read).with(nmpipe_response.data_block.trans_data.read_data)
243
+ pipe.request(opnum, options)
244
+ end
245
+
246
+ it 'raises the expected exception when an invalid packet is received' do
247
+ allow(RubySMB::Dcerpc::Response).to receive(:read).and_raise(IOError)
248
+ expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
249
+ end
250
+
251
+ it 'raises the expected exception when it is not a Response packet' do
252
+ response = RubySMB::Dcerpc::Request.new
253
+ allow(RubySMB::Dcerpc::Response).to receive(:read).and_return(response)
254
+ expect { pipe.request(opnum, options) }.to raise_error(RubySMB::Dcerpc::Error::InvalidPacket)
255
+ end
256
+
257
+ it 'returns the expected DCERPC Response' do
258
+ expect(pipe.request(opnum, options)).to eq(res_packet)
259
+ end
260
+ end
261
+ end
262
+
263
+ end