Line data Source code
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 286370 : static void smb1cli_trans_cleanup_primary(struct smb1cli_trans_state *state)
74 : {
75 286370 : if (state->primary_subreq) {
76 95454 : smb1cli_req_set_mid(state->primary_subreq, 0);
77 95454 : smbXcli_req_unset_pending(state->primary_subreq);
78 95454 : TALLOC_FREE(state->primary_subreq);
79 : }
80 286370 : }
81 :
82 95454 : static int smb1cli_trans_state_destructor(struct smb1cli_trans_state *state)
83 : {
84 95454 : smb1cli_trans_cleanup_primary(state);
85 95454 : return 0;
86 : }
87 :
88 57210 : 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 : {
102 1218 : uint32_t param_ofs, data_ofs;
103 1218 : uint8_t expected_num_setup;
104 57210 : uint32_t max_bytes = UINT32_MAX - bytes_ofs;
105 1218 : uint32_t bytes_end;
106 :
107 57210 : if (num_bytes > max_bytes) {
108 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
109 : }
110 :
111 57210 : bytes_end = bytes_ofs + num_bytes;
112 :
113 57210 : if (expect_first_reply) {
114 0 : if ((wct != 0) || (num_bytes != 0)) {
115 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
116 : }
117 0 : return NT_STATUS_OK;
118 : }
119 :
120 57210 : switch (smb_cmd) {
121 40067 : case SMBtrans:
122 : case SMBtrans2:
123 40067 : if (wct < 10) {
124 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
125 : }
126 40067 : expected_num_setup = wct - 10;
127 40067 : *ptotal_param = SVAL(vwv + 0, 0);
128 40067 : *ptotal_data = SVAL(vwv + 1, 0);
129 40067 : *pnum_param = SVAL(vwv + 3, 0);
130 40067 : param_ofs = SVAL(vwv + 4, 0);
131 40067 : *pparam_disp = SVAL(vwv + 5, 0);
132 40067 : *pnum_data = SVAL(vwv + 6, 0);
133 40067 : data_ofs = SVAL(vwv + 7, 0);
134 40067 : *pdata_disp = SVAL(vwv + 8, 0);
135 40067 : *pnum_setup = CVAL(vwv + 9, 0);
136 40067 : if (expected_num_setup < (*pnum_setup)) {
137 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
138 : }
139 40067 : *psetup = vwv + 10;
140 :
141 40067 : break;
142 17143 : case SMBnttrans:
143 17143 : if (wct < 18) {
144 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
145 : }
146 17143 : expected_num_setup = wct - 18;
147 17143 : *ptotal_param = IVAL(vwv, 3);
148 17143 : *ptotal_data = IVAL(vwv, 7);
149 17143 : *pnum_param = IVAL(vwv, 11);
150 17143 : param_ofs = IVAL(vwv, 15);
151 17143 : *pparam_disp = IVAL(vwv, 19);
152 17143 : *pnum_data = IVAL(vwv, 23);
153 17143 : data_ofs = IVAL(vwv, 27);
154 17143 : *pdata_disp = IVAL(vwv, 31);
155 17143 : *pnum_setup = CVAL(vwv, 35);
156 17143 : if (expected_num_setup < (*pnum_setup)) {
157 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
158 : }
159 17143 : *psetup = vwv + 18;
160 17143 : break;
161 :
162 0 : default:
163 0 : return NT_STATUS_INTERNAL_ERROR;
164 : }
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 57210 : if (smb_buffer_oob(bytes_end, param_ofs, *pnum_param)
173 57210 : || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param)
174 57210 : || smb_buffer_oob(bytes_end, data_ofs, *pnum_data)
175 57210 : || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
176 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
177 : }
178 :
179 57210 : *pparam = (uint8_t *)inhdr + param_ofs;
180 57210 : *pdata = (uint8_t *)inhdr + data_ofs;
181 :
182 57210 : return NT_STATUS_OK;
183 : }
184 :
185 114420 : 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 : {
190 114420 : if (blob->data == NULL) {
191 114336 : if (total > blob->max) {
192 8 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
193 : }
194 114328 : blob->total = total;
195 114328 : blob->data = talloc_array(mem_ctx, uint8_t, total);
196 114328 : if (blob->data == NULL) {
197 0 : return NT_STATUS_NO_MEMORY;
198 : }
199 : }
200 :
201 114412 : if (total > blob->total) {
202 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
203 : }
204 :
205 114412 : if (thistime) {
206 85937 : memcpy(blob->data + displacement, buf, thistime);
207 85937 : blob->received += thistime;
208 : }
209 :
210 114412 : return NT_STATUS_OK;
211 : }
212 :
213 95462 : static void smb1cli_trans_format(struct smb1cli_trans_state *state,
214 : uint8_t *pwct,
215 : int *piov_count)
216 : {
217 95462 : uint8_t wct = 0;
218 95462 : struct iovec *iov = state->iov;
219 95462 : uint8_t *pad = state->pad;
220 95462 : uint16_t *vwv = state->vwv;
221 1283 : uint32_t param_offset;
222 95462 : uint32_t this_param = 0;
223 1283 : uint32_t param_pad;
224 1283 : uint32_t data_offset;
225 95462 : uint32_t this_data = 0;
226 1283 : uint32_t data_pad;
227 1283 : uint32_t useable_space;
228 1283 : uint8_t cmd;
229 95462 : uint32_t max_trans = smb1cli_conn_max_xmit(state->conn);
230 :
231 95462 : cmd = state->cmd;
232 :
233 95462 : if ((state->param_sent != 0) || (state->data_sent != 0)) {
234 : /* The secondary commands are one after the primary ones */
235 0 : cmd += 1;
236 : }
237 :
238 95462 : param_offset = MIN_SMB_SIZE;
239 :
240 95462 : switch (cmd) {
241 1617 : case SMBtrans:
242 1617 : if (smbXcli_conn_use_unicode(state->conn)) {
243 1617 : pad[0] = 0;
244 1617 : iov[0].iov_base = (void *)pad;
245 1617 : iov[0].iov_len = 1;
246 1617 : param_offset += 1;
247 1617 : iov += 1;
248 : }
249 1617 : iov[0].iov_base = (void *)state->pipe_name_conv;
250 1617 : iov[0].iov_len = state->pipe_name_conv_len;
251 1617 : wct = 14 + state->num_setup;
252 1617 : param_offset += iov[0].iov_len;
253 1617 : iov += 1;
254 1617 : break;
255 75009 : case SMBtrans2:
256 75009 : pad[0] = 0;
257 75009 : pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
258 75009 : pad[2] = ' ';
259 75009 : iov[0].iov_base = (void *)pad;
260 75009 : iov[0].iov_len = 3;
261 75009 : wct = 14 + state->num_setup;
262 75009 : param_offset += 3;
263 75009 : iov += 1;
264 75009 : break;
265 0 : case SMBtranss:
266 0 : wct = 8;
267 0 : break;
268 0 : case SMBtranss2:
269 0 : wct = 9;
270 0 : break;
271 18836 : case SMBnttrans:
272 18836 : wct = 19 + state->num_setup;
273 18836 : break;
274 0 : case SMBnttranss:
275 0 : wct = 18;
276 0 : break;
277 : }
278 :
279 95462 : param_offset += wct * sizeof(uint16_t);
280 95462 : useable_space = max_trans - param_offset;
281 :
282 95462 : param_pad = param_offset % 4;
283 95462 : if (param_pad > 0) {
284 20453 : param_pad = MIN(param_pad, useable_space);
285 20453 : iov[0].iov_base = (void *)state->zero_pad;
286 20453 : iov[0].iov_len = param_pad;
287 20453 : iov += 1;
288 20453 : param_offset += param_pad;
289 : }
290 95462 : useable_space = max_trans - param_offset;
291 :
292 95462 : if (state->param_sent < state->num_param) {
293 90835 : this_param = MIN(state->num_param - state->param_sent,
294 : useable_space);
295 90835 : iov[0].iov_base = (void *)(state->param + state->param_sent);
296 90835 : iov[0].iov_len = this_param;
297 90835 : iov += 1;
298 : }
299 :
300 95462 : data_offset = param_offset + this_param;
301 95462 : useable_space = max_trans - data_offset;
302 :
303 95462 : data_pad = data_offset % 4;
304 95462 : if (data_pad > 0) {
305 55550 : data_pad = MIN(data_pad, useable_space);
306 55550 : iov[0].iov_base = (void *)state->zero_pad;
307 55550 : iov[0].iov_len = data_pad;
308 55550 : iov += 1;
309 55550 : data_offset += data_pad;
310 : }
311 95462 : useable_space = max_trans - data_offset;
312 :
313 95462 : if (state->data_sent < state->num_data) {
314 22088 : this_data = MIN(state->num_data - state->data_sent,
315 : useable_space);
316 22088 : iov[0].iov_base = (void *)(state->data + state->data_sent);
317 22088 : iov[0].iov_len = this_data;
318 22088 : iov += 1;
319 : }
320 :
321 95462 : DEBUG(10, ("num_setup=%u, max_setup=%u, "
322 : "param_total=%u, this_param=%u, max_param=%u, "
323 : "data_total=%u, this_data=%u, max_data=%u, "
324 : "param_offset=%u, param_pad=%u, param_disp=%u, "
325 : "data_offset=%u, data_pad=%u, data_disp=%u\n",
326 : (unsigned)state->num_setup, (unsigned)state->max_setup,
327 : (unsigned)state->num_param, (unsigned)this_param,
328 : (unsigned)state->rparam.max,
329 : (unsigned)state->num_data, (unsigned)this_data,
330 : (unsigned)state->rdata.max,
331 : (unsigned)param_offset, (unsigned)param_pad,
332 : (unsigned)state->param_sent,
333 : (unsigned)data_offset, (unsigned)data_pad,
334 : (unsigned)state->data_sent));
335 :
336 95462 : switch (cmd) {
337 76626 : case SMBtrans:
338 : case SMBtrans2:
339 76626 : SSVAL(vwv + 0, 0, state->num_param);
340 76626 : SSVAL(vwv + 1, 0, state->num_data);
341 76626 : SSVAL(vwv + 2, 0, state->rparam.max);
342 76626 : SSVAL(vwv + 3, 0, state->rdata.max);
343 76626 : SCVAL(vwv + 4, 0, state->max_setup);
344 76626 : SCVAL(vwv + 4, 1, 0); /* reserved */
345 76626 : SSVAL(vwv + 5, 0, state->flags);
346 76626 : SIVAL(vwv + 6, 0, 0); /* timeout */
347 76626 : SSVAL(vwv + 8, 0, 0); /* reserved */
348 76626 : SSVAL(vwv + 9, 0, this_param);
349 76626 : SSVAL(vwv +10, 0, param_offset);
350 76626 : SSVAL(vwv +11, 0, this_data);
351 76626 : SSVAL(vwv +12, 0, data_offset);
352 76626 : SCVAL(vwv +13, 0, state->num_setup);
353 76626 : SCVAL(vwv +13, 1, 0); /* reserved */
354 76626 : if (state->num_setup > 0) {
355 77762 : memcpy(vwv + 14, state->setup,
356 76479 : sizeof(uint16_t) * state->num_setup);
357 : }
358 75408 : break;
359 0 : case SMBtranss:
360 : 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 : }
372 0 : break;
373 18836 : case SMBnttrans:
374 18836 : SCVAL(vwv + 0, 0, state->max_setup);
375 18836 : SSVAL(vwv + 0, 1, 0); /* reserved */
376 18836 : SIVAL(vwv + 1, 1, state->num_param);
377 18836 : SIVAL(vwv + 3, 1, state->num_data);
378 18836 : SIVAL(vwv + 5, 1, state->rparam.max);
379 18836 : SIVAL(vwv + 7, 1, state->rdata.max);
380 18836 : SIVAL(vwv + 9, 1, this_param);
381 18836 : SIVAL(vwv +11, 1, param_offset);
382 18836 : SIVAL(vwv +13, 1, this_data);
383 18836 : SIVAL(vwv +15, 1, data_offset);
384 18836 : SCVAL(vwv +17, 1, state->num_setup);
385 18836 : SSVAL(vwv +18, 0, state->function);
386 20119 : memcpy(vwv + 19, state->setup,
387 18836 : sizeof(uint16_t) * state->num_setup);
388 18771 : 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 : }
403 :
404 95462 : state->param_sent += this_param;
405 95462 : state->data_sent += this_data;
406 :
407 95462 : *pwct = wct;
408 95462 : *piov_count = iov - state->iov;
409 95462 : }
410 :
411 : static bool smb1cli_trans_cancel(struct tevent_req *req);
412 : static void smb1cli_trans_done(struct tevent_req *subreq);
413 :
414 95462 : 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 : {
428 1283 : struct tevent_req *req, *subreq;
429 1283 : struct smb1cli_trans_state *state;
430 1283 : int iov_count;
431 1283 : uint8_t wct;
432 1283 : NTSTATUS status;
433 1283 : charset_t charset;
434 :
435 95462 : req = tevent_req_create(mem_ctx, &state,
436 : struct smb1cli_trans_state);
437 95462 : if (req == NULL) {
438 0 : return NULL;
439 : }
440 :
441 95462 : if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
442 76626 : if ((num_param > 0xffff) || (max_param > 0xffff)
443 76626 : || (num_data > 0xffff) || (max_data > 0xffff)) {
444 0 : DEBUG(3, ("Attempt to send invalid trans2 request "
445 : "(setup %u, params %u/%u, data %u/%u)\n",
446 : (unsigned)num_setup,
447 : (unsigned)num_param, (unsigned)max_param,
448 : (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 : }
452 : }
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 95462 : 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 : }
463 :
464 95462 : state->conn = conn;
465 95462 : state->ev = ev;
466 95462 : state->cmd = cmd;
467 95462 : state->additional_flags = additional_flags;
468 95462 : state->clear_flags = clear_flags;
469 95462 : state->additional_flags2 = additional_flags2;
470 95462 : state->clear_flags2 = clear_flags2;
471 95462 : state->timeout_msec = timeout_msec;
472 95462 : state->flags = flags;
473 95462 : state->num_rsetup = 0;
474 95462 : state->rsetup = NULL;
475 95462 : state->pid = pid;
476 95462 : state->tcon = tcon;
477 95462 : state->session = session;
478 95462 : ZERO_STRUCT(state->rparam);
479 95462 : ZERO_STRUCT(state->rdata);
480 :
481 95462 : if (smbXcli_conn_use_unicode(conn)) {
482 94177 : charset = CH_UTF16LE;
483 : } else {
484 2 : charset = CH_DOS;
485 : }
486 :
487 95462 : if ((pipe_name != NULL)
488 1617 : && (!convert_string_talloc(state, CH_UNIX, charset,
489 1617 : pipe_name, strlen(pipe_name) + 1,
490 1617 : &state->pipe_name_conv,
491 1617 : &state->pipe_name_conv_len))) {
492 0 : tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
493 0 : return tevent_req_post(req, ev);
494 : }
495 95462 : state->fid = fid; /* trans2 */
496 95462 : state->function = function; /* nttrans */
497 :
498 95462 : state->setup = setup;
499 95462 : state->num_setup = num_setup;
500 95462 : state->max_setup = max_setup;
501 :
502 95462 : state->param = param;
503 95462 : state->num_param = num_param;
504 95462 : state->param_sent = 0;
505 95462 : state->rparam.max = max_param;
506 :
507 95462 : state->data = data;
508 95462 : state->num_data = num_data;
509 95462 : state->data_sent = 0;
510 95462 : state->rdata.max = max_data;
511 :
512 95462 : smb1cli_trans_format(state, &wct, &iov_count);
513 :
514 190924 : subreq = smb1cli_req_create(state, ev, conn, cmd,
515 95462 : state->additional_flags,
516 95462 : state->clear_flags,
517 95462 : state->additional_flags2,
518 95462 : state->clear_flags2,
519 94179 : state->timeout_msec,
520 94179 : state->pid,
521 94179 : state->tcon,
522 94179 : state->session,
523 95462 : wct, state->vwv,
524 95462 : iov_count, state->iov);
525 95462 : if (tevent_req_nomem(subreq, req)) {
526 0 : return tevent_req_post(req, ev);
527 : }
528 95462 : status = smb1cli_req_chain_submit(&subreq, 1);
529 95462 : if (tevent_req_nterror(req, status)) {
530 8 : return tevent_req_post(req, state->ev);
531 : }
532 95454 : 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 95454 : state->mid = smb1cli_req_mid(subreq);
542 95454 : smb1cli_req_set_mid(subreq, state->mid);
543 95454 : state->primary_subreq = subreq;
544 95454 : talloc_set_destructor(state, smb1cli_trans_state_destructor);
545 :
546 95454 : tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);
547 :
548 95454 : return req;
549 : }
550 :
551 1510 : static bool smb1cli_trans_cancel(struct tevent_req *req)
552 : {
553 0 : struct smb1cli_trans_state *state =
554 1510 : tevent_req_data(req,
555 : struct smb1cli_trans_state);
556 :
557 1510 : if (state->primary_subreq == NULL) {
558 0 : return false;
559 : }
560 :
561 1510 : return tevent_req_cancel(state->primary_subreq);
562 : }
563 :
564 : static void smb1cli_trans_done2(struct tevent_req *subreq);
565 :
566 95496 : static void smb1cli_trans_done(struct tevent_req *subreq)
567 : {
568 1283 : struct tevent_req *req =
569 95496 : tevent_req_callback_data(subreq,
570 : struct tevent_req);
571 1283 : struct smb1cli_trans_state *state =
572 95496 : tevent_req_data(req,
573 : struct smb1cli_trans_state);
574 1283 : NTSTATUS status;
575 1283 : bool sent_all;
576 95496 : struct iovec *recv_iov = NULL;
577 1283 : uint8_t *inhdr;
578 1283 : uint8_t wct;
579 1283 : uint16_t *vwv;
580 1283 : uint32_t vwv_ofs;
581 1283 : uint32_t num_bytes;
582 1283 : uint8_t *bytes;
583 1283 : uint32_t bytes_ofs;
584 95496 : uint8_t num_setup = 0;
585 95496 : uint16_t *setup = NULL;
586 95496 : uint32_t total_param = 0;
587 95496 : uint32_t num_param = 0;
588 95496 : uint32_t param_disp = 0;
589 95496 : uint32_t total_data = 0;
590 95496 : uint32_t num_data = 0;
591 95496 : uint32_t data_disp = 0;
592 95496 : uint8_t *param = NULL;
593 95496 : uint8_t *data = NULL;
594 :
595 95496 : status = smb1cli_req_recv(subreq, state,
596 : &recv_iov,
597 : &inhdr,
598 : &wct,
599 : &vwv,
600 : &vwv_ofs,
601 : &num_bytes,
602 : &bytes,
603 : &bytes_ofs,
604 : NULL, /* pinbuf */
605 : 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 95496 : if (NT_STATUS_IS_ERR(status)) {
617 38286 : goto fail;
618 : }
619 :
620 57210 : if (recv_iov == NULL) {
621 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
622 0 : goto fail;
623 : }
624 57210 : state->status = status;
625 :
626 114420 : sent_all = ((state->param_sent == state->num_param)
627 57210 : && (state->data_sent == state->num_data));
628 :
629 58428 : status = smb1cli_pull_trans(
630 : inhdr, wct, vwv, vwv_ofs,
631 : num_bytes, bytes, bytes_ofs,
632 57210 : state->cmd, !sent_all, &num_setup, &setup,
633 : &total_param, &num_param, ¶m_disp, ¶m,
634 57210 : &total_data, &num_data, &data_disp, &data);
635 :
636 57210 : if (!NT_STATUS_IS_OK(status)) {
637 0 : goto fail;
638 : }
639 :
640 57210 : 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 : state->timeout_msec,
653 : state->pid,
654 : state->tcon,
655 : 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 : }
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 : }
668 0 : tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
669 :
670 0 : return;
671 : }
672 :
673 57210 : status = smb1cli_trans_pull_blob(
674 : state, &state->rparam, total_param, num_param, param,
675 : param_disp);
676 :
677 57210 : if (!NT_STATUS_IS_OK(status)) {
678 0 : DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
679 0 : goto fail;
680 : }
681 :
682 57210 : status = smb1cli_trans_pull_blob(
683 : state, &state->rdata, total_data, num_data, data,
684 : data_disp);
685 :
686 57210 : if (!NT_STATUS_IS_OK(status)) {
687 8 : DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
688 8 : goto fail;
689 : }
690 :
691 57202 : if ((state->rparam.total == state->rparam.received)
692 57202 : && (state->rdata.total == state->rdata.received)) {
693 57160 : state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
694 57160 : smb1cli_trans_cleanup_primary(state);
695 57160 : tevent_req_done(req);
696 57160 : return;
697 : }
698 :
699 42 : TALLOC_FREE(recv_iov);
700 :
701 42 : return;
702 :
703 38294 : fail:
704 38294 : smb1cli_trans_cleanup_primary(state);
705 38294 : tevent_req_nterror(req, status);
706 : }
707 :
708 0 : static void smb1cli_trans_done2(struct tevent_req *subreq2)
709 : {
710 0 : struct tevent_req *req =
711 0 : tevent_req_callback_data(subreq2,
712 : struct tevent_req);
713 0 : struct smb1cli_trans_state *state =
714 0 : tevent_req_data(req,
715 : 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 : NULL, /* recv_iov */
730 : NULL, /* phdr */
731 : NULL, /* pwct */
732 : NULL, /* pvwv */
733 : NULL, /* pvwv_offset */
734 : NULL, /* pnum_bytes */
735 : NULL, /* pbytes */
736 : NULL, /* pbytes_offset */
737 : NULL, /* pinbuf */
738 : NULL, 0); /* expected */
739 0 : TALLOC_FREE(subreq2);
740 :
741 0 : if (!NT_STATUS_IS_OK(status)) {
742 0 : goto fail;
743 : }
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 : state->timeout_msec,
761 : state->pid,
762 : state->tcon,
763 : 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 : }
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 : }
776 0 : tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
777 0 : return;
778 : }
779 :
780 0 : return;
781 :
782 0 : fail:
783 0 : smb1cli_trans_cleanup_primary(state);
784 0 : tevent_req_nterror(req, status);
785 : }
786 :
787 95462 : 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 : {
796 1283 : struct smb1cli_trans_state *state =
797 95462 : tevent_req_data(req,
798 : struct smb1cli_trans_state);
799 1283 : NTSTATUS status;
800 :
801 95462 : smb1cli_trans_cleanup_primary(state);
802 :
803 95462 : if (tevent_req_is_nterror(req, &status)) {
804 38302 : if (!NT_STATUS_IS_ERR(status)) {
805 0 : status = NT_STATUS_INVALID_NETWORK_RESPONSE;
806 : }
807 38302 : tevent_req_received(req);
808 38302 : return status;
809 : }
810 :
811 57160 : if ((state->num_rsetup < min_setup)
812 57160 : || (state->rparam.total < min_param)
813 57160 : || (state->rdata.total < min_data)) {
814 0 : tevent_req_received(req);
815 0 : return NT_STATUS_INVALID_NETWORK_RESPONSE;
816 : }
817 :
818 57160 : if (recv_flags2 != NULL) {
819 54829 : *recv_flags2 = state->recv_flags2;
820 : }
821 :
822 57160 : if (setup != NULL) {
823 54829 : *setup = talloc_move(mem_ctx, &state->rsetup);
824 54829 : *num_setup = state->num_rsetup;
825 : } else {
826 2331 : TALLOC_FREE(state->rsetup);
827 : }
828 :
829 57160 : if (param != NULL) {
830 55709 : *param = talloc_move(mem_ctx, &state->rparam.data);
831 55709 : *num_param = state->rparam.total;
832 : } else {
833 1451 : TALLOC_FREE(state->rparam.data);
834 : }
835 :
836 57160 : if (data != NULL) {
837 57160 : *data = talloc_move(mem_ctx, &state->rdata.data);
838 57160 : *num_data = state->rdata.total;
839 : } else {
840 0 : TALLOC_FREE(state->rdata.data);
841 : }
842 :
843 57160 : status = state->status;
844 57160 : tevent_req_received(req);
845 57160 : return status;
846 : }
847 :
848 0 : NTSTATUS smb1cli_trans(TALLOC_CTX *mem_ctx, struct smbXcli_conn *conn,
849 : uint8_t trans_cmd,
850 : uint8_t additional_flags, uint8_t clear_flags,
851 : uint16_t additional_flags2, uint16_t clear_flags2,
852 : uint32_t timeout_msec,
853 : uint32_t pid,
854 : struct smbXcli_tcon *tcon,
855 : struct smbXcli_session *session,
856 : const char *pipe_name, uint16_t fid, uint16_t function,
857 : int flags,
858 : uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
859 : uint8_t *param, uint32_t num_param, uint32_t max_param,
860 : uint8_t *data, uint32_t num_data, uint32_t max_data,
861 : uint16_t *recv_flags2,
862 : uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
863 : uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
864 : uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
865 : {
866 0 : TALLOC_CTX *frame = talloc_stackframe();
867 0 : struct tevent_context *ev;
868 0 : struct tevent_req *req;
869 0 : NTSTATUS status = NT_STATUS_NO_MEMORY;
870 :
871 0 : if (smbXcli_conn_has_async_calls(conn)) {
872 : /*
873 : * Can't use sync call while an async call is in flight
874 : */
875 0 : status = NT_STATUS_INVALID_PARAMETER_MIX;
876 0 : goto fail;
877 : }
878 :
879 0 : ev = samba_tevent_context_init(frame);
880 0 : if (ev == NULL) {
881 0 : goto fail;
882 : }
883 :
884 0 : req = smb1cli_trans_send(frame, ev, conn, trans_cmd,
885 : additional_flags, clear_flags,
886 : additional_flags2, clear_flags2,
887 : timeout_msec,
888 : pid, tcon, session,
889 : pipe_name, fid, function, flags,
890 : setup, num_setup, max_setup,
891 : param, num_param, max_param,
892 : data, num_data, max_data);
893 0 : if (req == NULL) {
894 0 : goto fail;
895 : }
896 :
897 0 : if (!tevent_req_poll_ntstatus(req, ev, &status)) {
898 0 : goto fail;
899 : }
900 :
901 0 : status = smb1cli_trans_recv(req, mem_ctx, recv_flags2,
902 : rsetup, min_rsetup, num_rsetup,
903 : rparam, min_rparam, num_rparam,
904 : rdata, min_rdata, num_rdata);
905 0 : fail:
906 0 : TALLOC_FREE(frame);
907 0 : return status;
908 : }
|