/src/samba/libcli/smb/smb1cli_trans.c
Line | Count | Source |
1 | | /* |
2 | | Unix SMB/CIFS implementation. |
3 | | client transaction calls |
4 | | Copyright (C) Andrew Tridgell 1994-1998 |
5 | | |
6 | | This program is free software; you can redistribute it and/or modify |
7 | | it under the terms of the GNU General Public License as published by |
8 | | the Free Software Foundation; either version 3 of the License, or |
9 | | (at your option) any later version. |
10 | | |
11 | | This program is distributed in the hope that it will be useful, |
12 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | GNU General Public License for more details. |
15 | | |
16 | | You should have received a copy of the GNU General Public License |
17 | | along with this program. If not, see <http://www.gnu.org/licenses/>. |
18 | | */ |
19 | | |
20 | | #include "includes.h" |
21 | | #include "system/network.h" |
22 | | #include "../lib/util/tevent_ntstatus.h" |
23 | | #include "../libcli/smb/smb_common.h" |
24 | | #include "../libcli/smb/smbXcli_base.h" |
25 | | |
26 | | struct trans_recvblob { |
27 | | uint8_t *data; |
28 | | uint32_t max, total, received; |
29 | | }; |
30 | | |
31 | | struct smb1cli_trans_state { |
32 | | struct smbXcli_conn *conn; |
33 | | struct tevent_context *ev; |
34 | | uint8_t cmd; |
35 | | uint8_t additional_flags; |
36 | | uint8_t clear_flags; |
37 | | uint16_t additional_flags2; |
38 | | uint16_t clear_flags2; |
39 | | uint32_t timeout_msec; |
40 | | uint16_t mid; |
41 | | uint32_t pid; |
42 | | struct smbXcli_tcon *tcon; |
43 | | struct smbXcli_session *session; |
44 | | const char *pipe_name; |
45 | | uint8_t *pipe_name_conv; |
46 | | size_t pipe_name_conv_len; |
47 | | uint16_t fid; |
48 | | uint16_t function; |
49 | | int flags; |
50 | | uint16_t *setup; |
51 | | uint8_t num_setup, max_setup; |
52 | | uint8_t *param; |
53 | | uint32_t num_param, param_sent; |
54 | | uint8_t *data; |
55 | | uint32_t num_data, data_sent; |
56 | | |
57 | | uint8_t num_rsetup; |
58 | | uint16_t *rsetup; |
59 | | struct trans_recvblob rparam; |
60 | | struct trans_recvblob rdata; |
61 | | uint16_t recv_flags2; |
62 | | |
63 | | struct iovec iov[6]; |
64 | | uint8_t pad[4]; |
65 | | uint8_t zero_pad[4]; |
66 | | uint16_t vwv[32]; |
67 | | |
68 | | NTSTATUS status; |
69 | | |
70 | | struct tevent_req *primary_subreq; |
71 | | }; |
72 | | |
73 | | static void smb1cli_trans_cleanup_primary(struct smb1cli_trans_state *state) |
74 | 0 | { |
75 | 0 | if (state->primary_subreq) { |
76 | 0 | smb1cli_req_set_mid(state->primary_subreq, 0); |
77 | 0 | smbXcli_req_unset_pending(state->primary_subreq); |
78 | 0 | TALLOC_FREE(state->primary_subreq); |
79 | 0 | } |
80 | 0 | } |
81 | | |
82 | | static int smb1cli_trans_state_destructor(struct smb1cli_trans_state *state) |
83 | 0 | { |
84 | 0 | smb1cli_trans_cleanup_primary(state); |
85 | 0 | return 0; |
86 | 0 | } |
87 | | |
88 | | static NTSTATUS smb1cli_pull_trans(uint8_t *inhdr, |
89 | | uint8_t wct, |
90 | | uint16_t *vwv, |
91 | | uint32_t vwv_ofs, |
92 | | uint32_t num_bytes, |
93 | | uint8_t *bytes, |
94 | | uint32_t bytes_ofs, |
95 | | uint8_t smb_cmd, bool expect_first_reply, |
96 | | uint8_t *pnum_setup, uint16_t **psetup, |
97 | | uint32_t *ptotal_param, uint32_t *pnum_param, |
98 | | uint32_t *pparam_disp, uint8_t **pparam, |
99 | | uint32_t *ptotal_data, uint32_t *pnum_data, |
100 | | uint32_t *pdata_disp, uint8_t **pdata) |
101 | 0 | { |
102 | 0 | uint32_t param_ofs, data_ofs; |
103 | 0 | uint8_t expected_num_setup; |
104 | 0 | uint32_t max_bytes = UINT32_MAX - bytes_ofs; |
105 | 0 | uint32_t bytes_end; |
106 | |
|
107 | 0 | if (num_bytes > max_bytes) { |
108 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
109 | 0 | } |
110 | | |
111 | 0 | bytes_end = bytes_ofs + num_bytes; |
112 | |
|
113 | 0 | if (expect_first_reply) { |
114 | 0 | if ((wct != 0) || (num_bytes != 0)) { |
115 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
116 | 0 | } |
117 | 0 | return NT_STATUS_OK; |
118 | 0 | } |
119 | | |
120 | 0 | switch (smb_cmd) { |
121 | 0 | case SMBtrans: |
122 | 0 | case SMBtrans2: |
123 | 0 | if (wct < 10) { |
124 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
125 | 0 | } |
126 | 0 | expected_num_setup = wct - 10; |
127 | 0 | *ptotal_param = SVAL(vwv + 0, 0); |
128 | 0 | *ptotal_data = SVAL(vwv + 1, 0); |
129 | 0 | *pnum_param = SVAL(vwv + 3, 0); |
130 | 0 | param_ofs = SVAL(vwv + 4, 0); |
131 | 0 | *pparam_disp = SVAL(vwv + 5, 0); |
132 | 0 | *pnum_data = SVAL(vwv + 6, 0); |
133 | 0 | data_ofs = SVAL(vwv + 7, 0); |
134 | 0 | *pdata_disp = SVAL(vwv + 8, 0); |
135 | 0 | *pnum_setup = CVAL(vwv + 9, 0); |
136 | 0 | if (expected_num_setup < (*pnum_setup)) { |
137 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
138 | 0 | } |
139 | 0 | *psetup = vwv + 10; |
140 | |
|
141 | 0 | break; |
142 | 0 | case SMBnttrans: |
143 | 0 | if (wct < 18) { |
144 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
145 | 0 | } |
146 | 0 | expected_num_setup = wct - 18; |
147 | 0 | *ptotal_param = IVAL(vwv, 3); |
148 | 0 | *ptotal_data = IVAL(vwv, 7); |
149 | 0 | *pnum_param = IVAL(vwv, 11); |
150 | 0 | param_ofs = IVAL(vwv, 15); |
151 | 0 | *pparam_disp = IVAL(vwv, 19); |
152 | 0 | *pnum_data = IVAL(vwv, 23); |
153 | 0 | data_ofs = IVAL(vwv, 27); |
154 | 0 | *pdata_disp = IVAL(vwv, 31); |
155 | 0 | *pnum_setup = CVAL(vwv, 35); |
156 | 0 | if (expected_num_setup < (*pnum_setup)) { |
157 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
158 | 0 | } |
159 | 0 | *psetup = vwv + 18; |
160 | 0 | break; |
161 | | |
162 | 0 | default: |
163 | 0 | return NT_STATUS_INTERNAL_ERROR; |
164 | 0 | } |
165 | | |
166 | | /* |
167 | | * Check for buffer overflows. data_ofs needs to be checked against |
168 | | * the incoming buffer length, data_disp against the total |
169 | | * length. Likewise for param_ofs/param_disp. |
170 | | */ |
171 | | |
172 | 0 | if (smb_buffer_oob(bytes_end, param_ofs, *pnum_param) |
173 | 0 | || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param) |
174 | 0 | || smb_buffer_oob(bytes_end, data_ofs, *pnum_data) |
175 | 0 | || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) { |
176 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
177 | 0 | } |
178 | | |
179 | 0 | *pparam = (uint8_t *)inhdr + param_ofs; |
180 | 0 | *pdata = (uint8_t *)inhdr + data_ofs; |
181 | |
|
182 | 0 | return NT_STATUS_OK; |
183 | 0 | } |
184 | | |
185 | | static NTSTATUS smb1cli_trans_pull_blob(TALLOC_CTX *mem_ctx, |
186 | | struct trans_recvblob *blob, |
187 | | uint32_t total, uint32_t thistime, |
188 | | uint8_t *buf, uint32_t displacement) |
189 | 0 | { |
190 | 0 | if (blob->data == NULL) { |
191 | 0 | if (total > blob->max) { |
192 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
193 | 0 | } |
194 | 0 | blob->total = total; |
195 | 0 | blob->data = talloc_array(mem_ctx, uint8_t, total); |
196 | 0 | if (blob->data == NULL) { |
197 | 0 | return NT_STATUS_NO_MEMORY; |
198 | 0 | } |
199 | 0 | } |
200 | | |
201 | 0 | if (total > blob->total) { |
202 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
203 | 0 | } |
204 | | |
205 | 0 | if (thistime) { |
206 | 0 | memcpy(blob->data + displacement, buf, thistime); |
207 | 0 | blob->received += thistime; |
208 | 0 | } |
209 | |
|
210 | 0 | return NT_STATUS_OK; |
211 | 0 | } |
212 | | |
213 | | static void smb1cli_trans_format(struct smb1cli_trans_state *state, |
214 | | uint8_t *pwct, |
215 | | int *piov_count) |
216 | 0 | { |
217 | 0 | uint8_t wct = 0; |
218 | 0 | struct iovec *iov = state->iov; |
219 | 0 | uint8_t *pad = state->pad; |
220 | 0 | uint16_t *vwv = state->vwv; |
221 | 0 | uint32_t param_offset; |
222 | 0 | uint32_t this_param = 0; |
223 | 0 | uint32_t param_pad; |
224 | 0 | uint32_t data_offset; |
225 | 0 | uint32_t this_data = 0; |
226 | 0 | uint32_t data_pad; |
227 | 0 | uint32_t useable_space; |
228 | 0 | uint8_t cmd; |
229 | 0 | uint32_t max_trans = smb1cli_conn_max_xmit(state->conn); |
230 | |
|
231 | 0 | cmd = state->cmd; |
232 | |
|
233 | 0 | if ((state->param_sent != 0) || (state->data_sent != 0)) { |
234 | | /* The secondary commands are one after the primary ones */ |
235 | 0 | cmd += 1; |
236 | 0 | } |
237 | |
|
238 | 0 | param_offset = MIN_SMB_SIZE; |
239 | |
|
240 | 0 | switch (cmd) { |
241 | 0 | case SMBtrans: |
242 | 0 | if (smbXcli_conn_use_unicode(state->conn)) { |
243 | 0 | pad[0] = 0; |
244 | 0 | iov[0].iov_base = (void *)pad; |
245 | 0 | iov[0].iov_len = 1; |
246 | 0 | param_offset += 1; |
247 | 0 | iov += 1; |
248 | 0 | } |
249 | 0 | iov[0].iov_base = (void *)state->pipe_name_conv; |
250 | 0 | iov[0].iov_len = state->pipe_name_conv_len; |
251 | 0 | wct = 14 + state->num_setup; |
252 | 0 | param_offset += iov[0].iov_len; |
253 | 0 | iov += 1; |
254 | 0 | break; |
255 | 0 | case SMBtrans2: |
256 | 0 | pad[0] = 0; |
257 | 0 | pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */ |
258 | 0 | pad[2] = ' '; |
259 | 0 | iov[0].iov_base = (void *)pad; |
260 | 0 | iov[0].iov_len = 3; |
261 | 0 | wct = 14 + state->num_setup; |
262 | 0 | param_offset += 3; |
263 | 0 | iov += 1; |
264 | 0 | break; |
265 | 0 | case SMBtranss: |
266 | 0 | wct = 8; |
267 | 0 | break; |
268 | 0 | case SMBtranss2: |
269 | 0 | wct = 9; |
270 | 0 | break; |
271 | 0 | case SMBnttrans: |
272 | 0 | wct = 19 + state->num_setup; |
273 | 0 | break; |
274 | 0 | case SMBnttranss: |
275 | 0 | wct = 18; |
276 | 0 | break; |
277 | 0 | } |
278 | | |
279 | 0 | param_offset += wct * sizeof(uint16_t); |
280 | 0 | useable_space = max_trans - param_offset; |
281 | |
|
282 | 0 | param_pad = param_offset % 4; |
283 | 0 | if (param_pad > 0) { |
284 | 0 | param_pad = MIN(param_pad, useable_space); |
285 | 0 | iov[0].iov_base = (void *)state->zero_pad; |
286 | 0 | iov[0].iov_len = param_pad; |
287 | 0 | iov += 1; |
288 | 0 | param_offset += param_pad; |
289 | 0 | } |
290 | 0 | useable_space = max_trans - param_offset; |
291 | |
|
292 | 0 | if (state->param_sent < state->num_param) { |
293 | 0 | this_param = MIN(state->num_param - state->param_sent, |
294 | 0 | useable_space); |
295 | 0 | iov[0].iov_base = (void *)(state->param + state->param_sent); |
296 | 0 | iov[0].iov_len = this_param; |
297 | 0 | iov += 1; |
298 | 0 | } |
299 | |
|
300 | 0 | data_offset = param_offset + this_param; |
301 | 0 | useable_space = max_trans - data_offset; |
302 | |
|
303 | 0 | data_pad = data_offset % 4; |
304 | 0 | if (data_pad > 0) { |
305 | 0 | data_pad = MIN(data_pad, useable_space); |
306 | 0 | iov[0].iov_base = (void *)state->zero_pad; |
307 | 0 | iov[0].iov_len = data_pad; |
308 | 0 | iov += 1; |
309 | 0 | data_offset += data_pad; |
310 | 0 | } |
311 | 0 | useable_space = max_trans - data_offset; |
312 | |
|
313 | 0 | if (state->data_sent < state->num_data) { |
314 | 0 | this_data = MIN(state->num_data - state->data_sent, |
315 | 0 | useable_space); |
316 | 0 | iov[0].iov_base = (void *)(state->data + state->data_sent); |
317 | 0 | iov[0].iov_len = this_data; |
318 | 0 | iov += 1; |
319 | 0 | } |
320 | |
|
321 | 0 | DEBUG(10, ("num_setup=%u, max_setup=%u, " |
322 | 0 | "param_total=%u, this_param=%u, max_param=%u, " |
323 | 0 | "data_total=%u, this_data=%u, max_data=%u, " |
324 | 0 | "param_offset=%u, param_pad=%u, param_disp=%u, " |
325 | 0 | "data_offset=%u, data_pad=%u, data_disp=%u\n", |
326 | 0 | (unsigned)state->num_setup, (unsigned)state->max_setup, |
327 | 0 | (unsigned)state->num_param, (unsigned)this_param, |
328 | 0 | (unsigned)state->rparam.max, |
329 | 0 | (unsigned)state->num_data, (unsigned)this_data, |
330 | 0 | (unsigned)state->rdata.max, |
331 | 0 | (unsigned)param_offset, (unsigned)param_pad, |
332 | 0 | (unsigned)state->param_sent, |
333 | 0 | (unsigned)data_offset, (unsigned)data_pad, |
334 | 0 | (unsigned)state->data_sent)); |
335 | |
|
336 | 0 | switch (cmd) { |
337 | 0 | case SMBtrans: |
338 | 0 | case SMBtrans2: |
339 | 0 | SSVAL(vwv + 0, 0, state->num_param); |
340 | 0 | SSVAL(vwv + 1, 0, state->num_data); |
341 | 0 | SSVAL(vwv + 2, 0, state->rparam.max); |
342 | 0 | SSVAL(vwv + 3, 0, state->rdata.max); |
343 | 0 | SCVAL(vwv + 4, 0, state->max_setup); |
344 | 0 | SCVAL(vwv + 4, 1, 0); /* reserved */ |
345 | 0 | SSVAL(vwv + 5, 0, state->flags); |
346 | 0 | SIVAL(vwv + 6, 0, 0); /* timeout */ |
347 | 0 | SSVAL(vwv + 8, 0, 0); /* reserved */ |
348 | 0 | SSVAL(vwv + 9, 0, this_param); |
349 | 0 | SSVAL(vwv +10, 0, param_offset); |
350 | 0 | SSVAL(vwv +11, 0, this_data); |
351 | 0 | SSVAL(vwv +12, 0, data_offset); |
352 | 0 | SCVAL(vwv +13, 0, state->num_setup); |
353 | 0 | SCVAL(vwv +13, 1, 0); /* reserved */ |
354 | 0 | if (state->num_setup > 0) { |
355 | 0 | memcpy(vwv + 14, state->setup, |
356 | 0 | sizeof(uint16_t) * state->num_setup); |
357 | 0 | } |
358 | 0 | break; |
359 | 0 | case SMBtranss: |
360 | 0 | case SMBtranss2: |
361 | 0 | SSVAL(vwv + 0, 0, state->num_param); |
362 | 0 | SSVAL(vwv + 1, 0, state->num_data); |
363 | 0 | SSVAL(vwv + 2, 0, this_param); |
364 | 0 | SSVAL(vwv + 3, 0, param_offset); |
365 | 0 | SSVAL(vwv + 4, 0, state->param_sent); |
366 | 0 | SSVAL(vwv + 5, 0, this_data); |
367 | 0 | SSVAL(vwv + 6, 0, data_offset); |
368 | 0 | SSVAL(vwv + 7, 0, state->data_sent); |
369 | 0 | if (cmd == SMBtranss2) { |
370 | 0 | SSVAL(vwv + 8, 0, state->fid); |
371 | 0 | } |
372 | 0 | break; |
373 | 0 | case SMBnttrans: |
374 | 0 | SCVAL(vwv + 0, 0, state->max_setup); |
375 | 0 | SSVAL(vwv + 0, 1, 0); /* reserved */ |
376 | 0 | SIVAL(vwv + 1, 1, state->num_param); |
377 | 0 | SIVAL(vwv + 3, 1, state->num_data); |
378 | 0 | SIVAL(vwv + 5, 1, state->rparam.max); |
379 | 0 | SIVAL(vwv + 7, 1, state->rdata.max); |
380 | 0 | SIVAL(vwv + 9, 1, this_param); |
381 | 0 | SIVAL(vwv +11, 1, param_offset); |
382 | 0 | SIVAL(vwv +13, 1, this_data); |
383 | 0 | SIVAL(vwv +15, 1, data_offset); |
384 | 0 | SCVAL(vwv +17, 1, state->num_setup); |
385 | 0 | SSVAL(vwv +18, 0, state->function); |
386 | 0 | memcpy(vwv + 19, state->setup, |
387 | 0 | sizeof(uint16_t) * state->num_setup); |
388 | 0 | break; |
389 | 0 | case SMBnttranss: |
390 | 0 | SSVAL(vwv + 0, 0, 0); /* reserved */ |
391 | 0 | SCVAL(vwv + 1, 0, 0); /* reserved */ |
392 | 0 | SIVAL(vwv + 1, 1, state->num_param); |
393 | 0 | SIVAL(vwv + 3, 1, state->num_data); |
394 | 0 | SIVAL(vwv + 5, 1, this_param); |
395 | 0 | SIVAL(vwv + 7, 1, param_offset); |
396 | 0 | SIVAL(vwv + 9, 1, state->param_sent); |
397 | 0 | SIVAL(vwv +11, 1, this_data); |
398 | 0 | SIVAL(vwv +13, 1, data_offset); |
399 | 0 | SIVAL(vwv +15, 1, state->data_sent); |
400 | 0 | SCVAL(vwv +17, 1, 0); /* reserved */ |
401 | 0 | break; |
402 | 0 | } |
403 | | |
404 | 0 | state->param_sent += this_param; |
405 | 0 | state->data_sent += this_data; |
406 | |
|
407 | 0 | *pwct = wct; |
408 | 0 | *piov_count = iov - state->iov; |
409 | 0 | } |
410 | | |
411 | | static bool smb1cli_trans_cancel(struct tevent_req *req); |
412 | | static void smb1cli_trans_done(struct tevent_req *subreq); |
413 | | |
414 | | struct tevent_req *smb1cli_trans_send( |
415 | | TALLOC_CTX *mem_ctx, struct tevent_context *ev, |
416 | | struct smbXcli_conn *conn, uint8_t cmd, |
417 | | uint8_t additional_flags, uint8_t clear_flags, |
418 | | uint16_t additional_flags2, uint16_t clear_flags2, |
419 | | uint32_t timeout_msec, |
420 | | uint32_t pid, |
421 | | struct smbXcli_tcon *tcon, |
422 | | struct smbXcli_session *session, |
423 | | const char *pipe_name, uint16_t fid, uint16_t function, int flags, |
424 | | uint16_t *setup, uint8_t num_setup, uint8_t max_setup, |
425 | | uint8_t *param, uint32_t num_param, uint32_t max_param, |
426 | | uint8_t *data, uint32_t num_data, uint32_t max_data) |
427 | 0 | { |
428 | 0 | struct tevent_req *req, *subreq; |
429 | 0 | struct smb1cli_trans_state *state; |
430 | 0 | int iov_count; |
431 | 0 | uint8_t wct; |
432 | 0 | NTSTATUS status; |
433 | 0 | charset_t charset; |
434 | |
|
435 | 0 | req = tevent_req_create(mem_ctx, &state, |
436 | 0 | struct smb1cli_trans_state); |
437 | 0 | if (req == NULL) { |
438 | 0 | return NULL; |
439 | 0 | } |
440 | | |
441 | 0 | if ((cmd == SMBtrans) || (cmd == SMBtrans2)) { |
442 | 0 | if ((num_param > 0xffff) || (max_param > 0xffff) |
443 | 0 | || (num_data > 0xffff) || (max_data > 0xffff)) { |
444 | 0 | DEBUG(3, ("Attempt to send invalid trans2 request " |
445 | 0 | "(setup %u, params %u/%u, data %u/%u)\n", |
446 | 0 | (unsigned)num_setup, |
447 | 0 | (unsigned)num_param, (unsigned)max_param, |
448 | 0 | (unsigned)num_data, (unsigned)max_data)); |
449 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); |
450 | 0 | return tevent_req_post(req, ev); |
451 | 0 | } |
452 | 0 | } |
453 | | |
454 | | /* |
455 | | * The largest wct will be for nttrans (19+num_setup). Make sure we |
456 | | * don't overflow state->vwv in smb1cli_trans_format. |
457 | | */ |
458 | | |
459 | 0 | if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) { |
460 | 0 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX); |
461 | 0 | return tevent_req_post(req, ev); |
462 | 0 | } |
463 | | |
464 | 0 | state->conn = conn; |
465 | 0 | state->ev = ev; |
466 | 0 | state->cmd = cmd; |
467 | 0 | state->additional_flags = additional_flags; |
468 | 0 | state->clear_flags = clear_flags; |
469 | 0 | state->additional_flags2 = additional_flags2; |
470 | 0 | state->clear_flags2 = clear_flags2; |
471 | 0 | state->timeout_msec = timeout_msec; |
472 | 0 | state->flags = flags; |
473 | 0 | state->num_rsetup = 0; |
474 | 0 | state->rsetup = NULL; |
475 | 0 | state->pid = pid; |
476 | 0 | state->tcon = tcon; |
477 | 0 | state->session = session; |
478 | 0 | ZERO_STRUCT(state->rparam); |
479 | 0 | ZERO_STRUCT(state->rdata); |
480 | |
|
481 | 0 | if (smbXcli_conn_use_unicode(conn)) { |
482 | 0 | charset = CH_UTF16LE; |
483 | 0 | } else { |
484 | 0 | charset = CH_DOS; |
485 | 0 | } |
486 | |
|
487 | 0 | if ((pipe_name != NULL) |
488 | 0 | && (!convert_string_talloc(state, CH_UNIX, charset, |
489 | 0 | pipe_name, strlen(pipe_name) + 1, |
490 | 0 | &state->pipe_name_conv, |
491 | 0 | &state->pipe_name_conv_len))) { |
492 | 0 | tevent_req_nterror(req, NT_STATUS_NO_MEMORY); |
493 | 0 | return tevent_req_post(req, ev); |
494 | 0 | } |
495 | 0 | state->fid = fid; /* trans2 */ |
496 | 0 | state->function = function; /* nttrans */ |
497 | |
|
498 | 0 | state->setup = setup; |
499 | 0 | state->num_setup = num_setup; |
500 | 0 | state->max_setup = max_setup; |
501 | |
|
502 | 0 | state->param = param; |
503 | 0 | state->num_param = num_param; |
504 | 0 | state->param_sent = 0; |
505 | 0 | state->rparam.max = max_param; |
506 | |
|
507 | 0 | state->data = data; |
508 | 0 | state->num_data = num_data; |
509 | 0 | state->data_sent = 0; |
510 | 0 | state->rdata.max = max_data; |
511 | |
|
512 | 0 | smb1cli_trans_format(state, &wct, &iov_count); |
513 | |
|
514 | 0 | subreq = smb1cli_req_create(state, ev, conn, cmd, |
515 | 0 | state->additional_flags, |
516 | 0 | state->clear_flags, |
517 | 0 | state->additional_flags2, |
518 | 0 | state->clear_flags2, |
519 | 0 | state->timeout_msec, |
520 | 0 | state->pid, |
521 | 0 | state->tcon, |
522 | 0 | state->session, |
523 | 0 | wct, state->vwv, |
524 | 0 | iov_count, state->iov); |
525 | 0 | if (tevent_req_nomem(subreq, req)) { |
526 | 0 | return tevent_req_post(req, ev); |
527 | 0 | } |
528 | 0 | status = smb1cli_req_chain_submit(&subreq, 1); |
529 | 0 | if (tevent_req_nterror(req, status)) { |
530 | 0 | return tevent_req_post(req, state->ev); |
531 | 0 | } |
532 | 0 | tevent_req_set_callback(subreq, smb1cli_trans_done, req); |
533 | | |
534 | | /* |
535 | | * Now get the MID of the primary request |
536 | | * and mark it as persistent. This means |
537 | | * we will able to send and receive multiple |
538 | | * SMB pdus using this MID in both directions |
539 | | * (including correct SMB signing). |
540 | | */ |
541 | 0 | state->mid = smb1cli_req_mid(subreq); |
542 | 0 | smb1cli_req_set_mid(subreq, state->mid); |
543 | 0 | state->primary_subreq = subreq; |
544 | 0 | talloc_set_destructor(state, smb1cli_trans_state_destructor); |
545 | |
|
546 | 0 | tevent_req_set_cancel_fn(req, smb1cli_trans_cancel); |
547 | |
|
548 | 0 | return req; |
549 | 0 | } |
550 | | |
551 | | static bool smb1cli_trans_cancel(struct tevent_req *req) |
552 | 0 | { |
553 | 0 | struct smb1cli_trans_state *state = |
554 | 0 | tevent_req_data(req, |
555 | 0 | struct smb1cli_trans_state); |
556 | |
|
557 | 0 | if (state->primary_subreq == NULL) { |
558 | 0 | return false; |
559 | 0 | } |
560 | | |
561 | 0 | return tevent_req_cancel(state->primary_subreq); |
562 | 0 | } |
563 | | |
564 | | static void smb1cli_trans_done2(struct tevent_req *subreq); |
565 | | |
566 | | static void smb1cli_trans_done(struct tevent_req *subreq) |
567 | 0 | { |
568 | 0 | struct tevent_req *req = |
569 | 0 | tevent_req_callback_data(subreq, |
570 | 0 | struct tevent_req); |
571 | 0 | struct smb1cli_trans_state *state = |
572 | 0 | tevent_req_data(req, |
573 | 0 | struct smb1cli_trans_state); |
574 | 0 | NTSTATUS status; |
575 | 0 | bool sent_all; |
576 | 0 | struct iovec *recv_iov = NULL; |
577 | 0 | uint8_t *inhdr; |
578 | 0 | uint8_t wct; |
579 | 0 | uint16_t *vwv; |
580 | 0 | uint32_t vwv_ofs; |
581 | 0 | uint32_t num_bytes; |
582 | 0 | uint8_t *bytes; |
583 | 0 | uint32_t bytes_ofs; |
584 | 0 | uint8_t num_setup = 0; |
585 | 0 | uint16_t *setup = NULL; |
586 | 0 | uint32_t total_param = 0; |
587 | 0 | uint32_t num_param = 0; |
588 | 0 | uint32_t param_disp = 0; |
589 | 0 | uint32_t total_data = 0; |
590 | 0 | uint32_t num_data = 0; |
591 | 0 | uint32_t data_disp = 0; |
592 | 0 | uint8_t *param = NULL; |
593 | 0 | uint8_t *data = NULL; |
594 | |
|
595 | 0 | status = smb1cli_req_recv(subreq, state, |
596 | 0 | &recv_iov, |
597 | 0 | &inhdr, |
598 | 0 | &wct, |
599 | 0 | &vwv, |
600 | 0 | &vwv_ofs, |
601 | 0 | &num_bytes, |
602 | 0 | &bytes, |
603 | 0 | &bytes_ofs, |
604 | 0 | NULL, /* pinbuf */ |
605 | 0 | NULL, 0); /* expected */ |
606 | | /* |
607 | | * Do not TALLOC_FREE(subreq) here, we might receive more than |
608 | | * one response for the same mid. |
609 | | */ |
610 | | |
611 | | /* |
612 | | * We can receive something like STATUS_MORE_ENTRIES, so don't use |
613 | | * !NT_STATUS_IS_OK(status) here. |
614 | | */ |
615 | |
|
616 | 0 | if (NT_STATUS_IS_ERR(status)) { |
617 | 0 | goto fail; |
618 | 0 | } |
619 | | |
620 | 0 | if (recv_iov == NULL) { |
621 | 0 | status = NT_STATUS_INVALID_NETWORK_RESPONSE; |
622 | 0 | goto fail; |
623 | 0 | } |
624 | 0 | state->status = status; |
625 | |
|
626 | 0 | sent_all = ((state->param_sent == state->num_param) |
627 | 0 | && (state->data_sent == state->num_data)); |
628 | |
|
629 | 0 | status = smb1cli_pull_trans( |
630 | 0 | inhdr, wct, vwv, vwv_ofs, |
631 | 0 | num_bytes, bytes, bytes_ofs, |
632 | 0 | state->cmd, !sent_all, &num_setup, &setup, |
633 | 0 | &total_param, &num_param, ¶m_disp, ¶m, |
634 | 0 | &total_data, &num_data, &data_disp, &data); |
635 | |
|
636 | 0 | if (!NT_STATUS_IS_OK(status)) { |
637 | 0 | goto fail; |
638 | 0 | } |
639 | | |
640 | 0 | if (!sent_all) { |
641 | 0 | int iov_count; |
642 | 0 | struct tevent_req *subreq2; |
643 | |
|
644 | 0 | smb1cli_trans_format(state, &wct, &iov_count); |
645 | |
|
646 | 0 | subreq2 = smb1cli_req_create(state, state->ev, state->conn, |
647 | 0 | state->cmd + 1, |
648 | 0 | state->additional_flags, |
649 | 0 | state->clear_flags, |
650 | 0 | state->additional_flags2, |
651 | 0 | state->clear_flags2, |
652 | 0 | state->timeout_msec, |
653 | 0 | state->pid, |
654 | 0 | state->tcon, |
655 | 0 | state->session, |
656 | 0 | wct, state->vwv, |
657 | 0 | iov_count, state->iov); |
658 | 0 | if (tevent_req_nomem(subreq2, req)) { |
659 | 0 | return; |
660 | 0 | } |
661 | 0 | smb1cli_req_set_mid(subreq2, state->mid); |
662 | |
|
663 | 0 | status = smb1cli_req_chain_submit(&subreq2, 1); |
664 | |
|
665 | 0 | if (!NT_STATUS_IS_OK(status)) { |
666 | 0 | goto fail; |
667 | 0 | } |
668 | 0 | tevent_req_set_callback(subreq2, smb1cli_trans_done2, req); |
669 | |
|
670 | 0 | return; |
671 | 0 | } |
672 | | |
673 | 0 | status = smb1cli_trans_pull_blob( |
674 | 0 | state, &state->rparam, total_param, num_param, param, |
675 | 0 | param_disp); |
676 | |
|
677 | 0 | if (!NT_STATUS_IS_OK(status)) { |
678 | 0 | DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status))); |
679 | 0 | goto fail; |
680 | 0 | } |
681 | | |
682 | 0 | status = smb1cli_trans_pull_blob( |
683 | 0 | state, &state->rdata, total_data, num_data, data, |
684 | 0 | data_disp); |
685 | |
|
686 | 0 | if (!NT_STATUS_IS_OK(status)) { |
687 | 0 | DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status))); |
688 | 0 | goto fail; |
689 | 0 | } |
690 | | |
691 | 0 | if ((state->rparam.total == state->rparam.received) |
692 | 0 | && (state->rdata.total == state->rdata.received)) { |
693 | 0 | state->recv_flags2 = SVAL(inhdr, HDR_FLG2); |
694 | 0 | smb1cli_trans_cleanup_primary(state); |
695 | 0 | tevent_req_done(req); |
696 | 0 | return; |
697 | 0 | } |
698 | | |
699 | 0 | TALLOC_FREE(recv_iov); |
700 | |
|
701 | 0 | return; |
702 | | |
703 | 0 | fail: |
704 | 0 | smb1cli_trans_cleanup_primary(state); |
705 | 0 | tevent_req_nterror(req, status); |
706 | 0 | } |
707 | | |
708 | | static void smb1cli_trans_done2(struct tevent_req *subreq2) |
709 | 0 | { |
710 | 0 | struct tevent_req *req = |
711 | 0 | tevent_req_callback_data(subreq2, |
712 | 0 | struct tevent_req); |
713 | 0 | struct smb1cli_trans_state *state = |
714 | 0 | tevent_req_data(req, |
715 | 0 | struct smb1cli_trans_state); |
716 | 0 | NTSTATUS status; |
717 | 0 | bool sent_all; |
718 | 0 | uint32_t seqnum; |
719 | | |
720 | | /* |
721 | | * First backup the seqnum of the secondary request |
722 | | * and attach it to the primary request. |
723 | | */ |
724 | 0 | seqnum = smb1cli_req_seqnum(subreq2); |
725 | 0 | smb1cli_req_set_seqnum(state->primary_subreq, seqnum); |
726 | | |
727 | | /* This was a one way request */ |
728 | 0 | status = smb1cli_req_recv(subreq2, state, |
729 | 0 | NULL, /* recv_iov */ |
730 | 0 | NULL, /* phdr */ |
731 | 0 | NULL, /* pwct */ |
732 | 0 | NULL, /* pvwv */ |
733 | 0 | NULL, /* pvwv_offset */ |
734 | 0 | NULL, /* pnum_bytes */ |
735 | 0 | NULL, /* pbytes */ |
736 | 0 | NULL, /* pbytes_offset */ |
737 | 0 | NULL, /* pinbuf */ |
738 | 0 | NULL, 0); /* expected */ |
739 | 0 | TALLOC_FREE(subreq2); |
740 | |
|
741 | 0 | if (!NT_STATUS_IS_OK(status)) { |
742 | 0 | goto fail; |
743 | 0 | } |
744 | | |
745 | 0 | sent_all = ((state->param_sent == state->num_param) |
746 | 0 | && (state->data_sent == state->num_data)); |
747 | |
|
748 | 0 | if (!sent_all) { |
749 | 0 | uint8_t wct; |
750 | 0 | int iov_count; |
751 | |
|
752 | 0 | smb1cli_trans_format(state, &wct, &iov_count); |
753 | |
|
754 | 0 | subreq2 = smb1cli_req_create(state, state->ev, state->conn, |
755 | 0 | state->cmd + 1, |
756 | 0 | state->additional_flags, |
757 | 0 | state->clear_flags, |
758 | 0 | state->additional_flags2, |
759 | 0 | state->clear_flags2, |
760 | 0 | state->timeout_msec, |
761 | 0 | state->pid, |
762 | 0 | state->tcon, |
763 | 0 | state->session, |
764 | 0 | wct, state->vwv, |
765 | 0 | iov_count, state->iov); |
766 | 0 | if (tevent_req_nomem(subreq2, req)) { |
767 | 0 | return; |
768 | 0 | } |
769 | 0 | smb1cli_req_set_mid(subreq2, state->mid); |
770 | |
|
771 | 0 | status = smb1cli_req_chain_submit(&subreq2, 1); |
772 | |
|
773 | 0 | if (!NT_STATUS_IS_OK(status)) { |
774 | 0 | goto fail; |
775 | 0 | } |
776 | 0 | tevent_req_set_callback(subreq2, smb1cli_trans_done2, req); |
777 | 0 | return; |
778 | 0 | } |
779 | | |
780 | 0 | return; |
781 | | |
782 | 0 | fail: |
783 | 0 | smb1cli_trans_cleanup_primary(state); |
784 | 0 | tevent_req_nterror(req, status); |
785 | 0 | } |
786 | | |
787 | | NTSTATUS smb1cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, |
788 | | uint16_t *recv_flags2, |
789 | | uint16_t **setup, uint8_t min_setup, |
790 | | uint8_t *num_setup, |
791 | | uint8_t **param, uint32_t min_param, |
792 | | uint32_t *num_param, |
793 | | uint8_t **data, uint32_t min_data, |
794 | | uint32_t *num_data) |
795 | 0 | { |
796 | 0 | struct smb1cli_trans_state *state = |
797 | 0 | tevent_req_data(req, |
798 | 0 | struct smb1cli_trans_state); |
799 | 0 | NTSTATUS status; |
800 | |
|
801 | 0 | smb1cli_trans_cleanup_primary(state); |
802 | |
|
803 | 0 | if (tevent_req_is_nterror(req, &status)) { |
804 | 0 | if (!NT_STATUS_IS_ERR(status)) { |
805 | 0 | status = NT_STATUS_INVALID_NETWORK_RESPONSE; |
806 | 0 | } |
807 | 0 | tevent_req_received(req); |
808 | 0 | return status; |
809 | 0 | } |
810 | | |
811 | 0 | if ((state->num_rsetup < min_setup) |
812 | 0 | || (state->rparam.total < min_param) |
813 | 0 | || (state->rdata.total < min_data)) { |
814 | 0 | tevent_req_received(req); |
815 | 0 | return NT_STATUS_INVALID_NETWORK_RESPONSE; |
816 | 0 | } |
817 | | |
818 | 0 | if (recv_flags2 != NULL) { |
819 | 0 | *recv_flags2 = state->recv_flags2; |
820 | 0 | } |
821 | |
|
822 | 0 | if (setup != NULL) { |
823 | 0 | *setup = talloc_move(mem_ctx, &state->rsetup); |
824 | 0 | *num_setup = state->num_rsetup; |
825 | 0 | } |
826 | |
|
827 | 0 | if (param != NULL) { |
828 | 0 | *param = talloc_move(mem_ctx, &state->rparam.data); |
829 | 0 | *num_param = state->rparam.total; |
830 | 0 | } |
831 | |
|
832 | 0 | if (data != NULL) { |
833 | 0 | *data = talloc_move(mem_ctx, &state->rdata.data); |
834 | 0 | *num_data = state->rdata.total; |
835 | 0 | } |
836 | |
|
837 | 0 | status = state->status; |
838 | 0 | tevent_req_received(req); |
839 | 0 | return status; |
840 | 0 | } |