ruby_smb 0.0.21 → 0.0.22

Sign up to get free protection for your applications and to get access to all the features.
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