source: vendor/current/libcli/smb/smb1cli_trans.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 23.1 KB
Line 
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
26struct trans_recvblob {
27 uint8_t *data;
28 uint32_t max, total, received;
29};
30
31struct 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
73static void smb1cli_trans_cleanup_primary(struct smb1cli_trans_state *state)
74{
75 if (state->primary_subreq) {
76 smb1cli_req_set_mid(state->primary_subreq, 0);
77 smbXcli_req_unset_pending(state->primary_subreq);
78 TALLOC_FREE(state->primary_subreq);
79 }
80}
81
82static int smb1cli_trans_state_destructor(struct smb1cli_trans_state *state)
83{
84 smb1cli_trans_cleanup_primary(state);
85 return 0;
86}
87
88static 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 uint32_t param_ofs, data_ofs;
103 uint8_t expected_num_setup;
104 uint32_t max_bytes = UINT32_MAX - bytes_ofs;
105 uint32_t bytes_end;
106
107 if (num_bytes > max_bytes) {
108 return NT_STATUS_INVALID_NETWORK_RESPONSE;
109 }
110
111 bytes_end = bytes_ofs + num_bytes;
112
113 if (expect_first_reply) {
114 if ((wct != 0) || (num_bytes != 0)) {
115 return NT_STATUS_INVALID_NETWORK_RESPONSE;
116 }
117 return NT_STATUS_OK;
118 }
119
120 switch (smb_cmd) {
121 case SMBtrans:
122 case SMBtrans2:
123 if (wct < 10) {
124 return NT_STATUS_INVALID_NETWORK_RESPONSE;
125 }
126 expected_num_setup = wct - 10;
127 *ptotal_param = SVAL(vwv + 0, 0);
128 *ptotal_data = SVAL(vwv + 1, 0);
129 *pnum_param = SVAL(vwv + 3, 0);
130 param_ofs = SVAL(vwv + 4, 0);
131 *pparam_disp = SVAL(vwv + 5, 0);
132 *pnum_data = SVAL(vwv + 6, 0);
133 data_ofs = SVAL(vwv + 7, 0);
134 *pdata_disp = SVAL(vwv + 8, 0);
135 *pnum_setup = CVAL(vwv + 9, 0);
136 if (expected_num_setup < (*pnum_setup)) {
137 return NT_STATUS_INVALID_NETWORK_RESPONSE;
138 }
139 *psetup = vwv + 10;
140
141 break;
142 case SMBnttrans:
143 if (wct < 18) {
144 return NT_STATUS_INVALID_NETWORK_RESPONSE;
145 }
146 expected_num_setup = wct - 18;
147 *ptotal_param = IVAL(vwv, 3);
148 *ptotal_data = IVAL(vwv, 7);
149 *pnum_param = IVAL(vwv, 11);
150 param_ofs = IVAL(vwv, 15);
151 *pparam_disp = IVAL(vwv, 19);
152 *pnum_data = IVAL(vwv, 23);
153 data_ofs = IVAL(vwv, 27);
154 *pdata_disp = IVAL(vwv, 31);
155 *pnum_setup = CVAL(vwv, 35);
156 if (expected_num_setup < (*pnum_setup)) {
157 return NT_STATUS_INVALID_NETWORK_RESPONSE;
158 }
159 *psetup = vwv + 18;
160 break;
161
162 default:
163 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 if (smb_buffer_oob(bytes_end, param_ofs, *pnum_param)
173 || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param)
174 || smb_buffer_oob(bytes_end, data_ofs, *pnum_data)
175 || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
176 return NT_STATUS_INVALID_NETWORK_RESPONSE;
177 }
178
179 *pparam = (uint8_t *)inhdr + param_ofs;
180 *pdata = (uint8_t *)inhdr + data_ofs;
181
182 return NT_STATUS_OK;
183}
184
185static 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 if (blob->data == NULL) {
191 if (total > blob->max) {
192 return NT_STATUS_INVALID_NETWORK_RESPONSE;
193 }
194 blob->total = total;
195 blob->data = talloc_array(mem_ctx, uint8_t, total);
196 if (blob->data == NULL) {
197 return NT_STATUS_NO_MEMORY;
198 }
199 }
200
201 if (total > blob->total) {
202 return NT_STATUS_INVALID_NETWORK_RESPONSE;
203 }
204
205 if (thistime) {
206 memcpy(blob->data + displacement, buf, thistime);
207 blob->received += thistime;
208 }
209
210 return NT_STATUS_OK;
211}
212
213static void smb1cli_trans_format(struct smb1cli_trans_state *state,
214 uint8_t *pwct,
215 int *piov_count)
216{
217 uint8_t wct = 0;
218 struct iovec *iov = state->iov;
219 uint8_t *pad = state->pad;
220 uint16_t *vwv = state->vwv;
221 uint32_t param_offset;
222 uint32_t this_param = 0;
223 uint32_t param_pad;
224 uint32_t data_offset;
225 uint32_t this_data = 0;
226 uint32_t data_pad;
227 uint32_t useable_space;
228 uint8_t cmd;
229 uint32_t max_trans = smb1cli_conn_max_xmit(state->conn);
230
231 cmd = state->cmd;
232
233 if ((state->param_sent != 0) || (state->data_sent != 0)) {
234 /* The secondary commands are one after the primary ones */
235 cmd += 1;
236 }
237
238 param_offset = MIN_SMB_SIZE;
239
240 switch (cmd) {
241 case SMBtrans:
242 if (smbXcli_conn_use_unicode(state->conn)) {
243 pad[0] = 0;
244 iov[0].iov_base = (void *)pad;
245 iov[0].iov_len = 1;
246 param_offset += 1;
247 iov += 1;
248 }
249 iov[0].iov_base = (void *)state->pipe_name_conv;
250 iov[0].iov_len = state->pipe_name_conv_len;
251 wct = 14 + state->num_setup;
252 param_offset += iov[0].iov_len;
253 iov += 1;
254 break;
255 case SMBtrans2:
256 pad[0] = 0;
257 pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
258 pad[2] = ' ';
259 iov[0].iov_base = (void *)pad;
260 iov[0].iov_len = 3;
261 wct = 14 + state->num_setup;
262 param_offset += 3;
263 iov += 1;
264 break;
265 case SMBtranss:
266 wct = 8;
267 break;
268 case SMBtranss2:
269 wct = 9;
270 break;
271 case SMBnttrans:
272 wct = 19 + state->num_setup;
273 break;
274 case SMBnttranss:
275 wct = 18;
276 break;
277 }
278
279 param_offset += wct * sizeof(uint16_t);
280 useable_space = max_trans - param_offset;
281
282 param_pad = param_offset % 4;
283 if (param_pad > 0) {
284 param_pad = MIN(param_pad, useable_space);
285 iov[0].iov_base = (void *)state->zero_pad;
286 iov[0].iov_len = param_pad;
287 iov += 1;
288 param_offset += param_pad;
289 }
290 useable_space = max_trans - param_offset;
291
292 if (state->param_sent < state->num_param) {
293 this_param = MIN(state->num_param - state->param_sent,
294 useable_space);
295 iov[0].iov_base = (void *)(state->param + state->param_sent);
296 iov[0].iov_len = this_param;
297 iov += 1;
298 }
299
300 data_offset = param_offset + this_param;
301 useable_space = max_trans - data_offset;
302
303 data_pad = data_offset % 4;
304 if (data_pad > 0) {
305 data_pad = MIN(data_pad, useable_space);
306 iov[0].iov_base = (void *)state->zero_pad;
307 iov[0].iov_len = data_pad;
308 iov += 1;
309 data_offset += data_pad;
310 }
311 useable_space = max_trans - data_offset;
312
313 if (state->data_sent < state->num_data) {
314 this_data = MIN(state->num_data - state->data_sent,
315 useable_space);
316 iov[0].iov_base = (void *)(state->data + state->data_sent);
317 iov[0].iov_len = this_data;
318 iov += 1;
319 }
320
321 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 switch (cmd) {
337 case SMBtrans:
338 case SMBtrans2:
339 SSVAL(vwv + 0, 0, state->num_param);
340 SSVAL(vwv + 1, 0, state->num_data);
341 SSVAL(vwv + 2, 0, state->rparam.max);
342 SSVAL(vwv + 3, 0, state->rdata.max);
343 SCVAL(vwv + 4, 0, state->max_setup);
344 SCVAL(vwv + 4, 1, 0); /* reserved */
345 SSVAL(vwv + 5, 0, state->flags);
346 SIVAL(vwv + 6, 0, 0); /* timeout */
347 SSVAL(vwv + 8, 0, 0); /* reserved */
348 SSVAL(vwv + 9, 0, this_param);
349 SSVAL(vwv +10, 0, param_offset);
350 SSVAL(vwv +11, 0, this_data);
351 SSVAL(vwv +12, 0, data_offset);
352 SCVAL(vwv +13, 0, state->num_setup);
353 SCVAL(vwv +13, 1, 0); /* reserved */
354 memcpy(vwv + 14, state->setup,
355 sizeof(uint16_t) * state->num_setup);
356 break;
357 case SMBtranss:
358 case SMBtranss2:
359 SSVAL(vwv + 0, 0, state->num_param);
360 SSVAL(vwv + 1, 0, state->num_data);
361 SSVAL(vwv + 2, 0, this_param);
362 SSVAL(vwv + 3, 0, param_offset);
363 SSVAL(vwv + 4, 0, state->param_sent);
364 SSVAL(vwv + 5, 0, this_data);
365 SSVAL(vwv + 6, 0, data_offset);
366 SSVAL(vwv + 7, 0, state->data_sent);
367 if (cmd == SMBtranss2) {
368 SSVAL(vwv + 8, 0, state->fid);
369 }
370 break;
371 case SMBnttrans:
372 SCVAL(vwv + 0, 0, state->max_setup);
373 SSVAL(vwv + 0, 1, 0); /* reserved */
374 SIVAL(vwv + 1, 1, state->num_param);
375 SIVAL(vwv + 3, 1, state->num_data);
376 SIVAL(vwv + 5, 1, state->rparam.max);
377 SIVAL(vwv + 7, 1, state->rdata.max);
378 SIVAL(vwv + 9, 1, this_param);
379 SIVAL(vwv +11, 1, param_offset);
380 SIVAL(vwv +13, 1, this_data);
381 SIVAL(vwv +15, 1, data_offset);
382 SCVAL(vwv +17, 1, state->num_setup);
383 SSVAL(vwv +18, 0, state->function);
384 memcpy(vwv + 19, state->setup,
385 sizeof(uint16_t) * state->num_setup);
386 break;
387 case SMBnttranss:
388 SSVAL(vwv + 0, 0, 0); /* reserved */
389 SCVAL(vwv + 1, 0, 0); /* reserved */
390 SIVAL(vwv + 1, 1, state->num_param);
391 SIVAL(vwv + 3, 1, state->num_data);
392 SIVAL(vwv + 5, 1, this_param);
393 SIVAL(vwv + 7, 1, param_offset);
394 SIVAL(vwv + 9, 1, state->param_sent);
395 SIVAL(vwv +11, 1, this_data);
396 SIVAL(vwv +13, 1, data_offset);
397 SIVAL(vwv +15, 1, state->data_sent);
398 SCVAL(vwv +17, 1, 0); /* reserved */
399 break;
400 }
401
402 state->param_sent += this_param;
403 state->data_sent += this_data;
404
405 *pwct = wct;
406 *piov_count = iov - state->iov;
407}
408
409static bool smb1cli_trans_cancel(struct tevent_req *req);
410static void smb1cli_trans_done(struct tevent_req *subreq);
411
412struct tevent_req *smb1cli_trans_send(
413 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
414 struct smbXcli_conn *conn, uint8_t cmd,
415 uint8_t additional_flags, uint8_t clear_flags,
416 uint16_t additional_flags2, uint16_t clear_flags2,
417 uint32_t timeout_msec,
418 uint32_t pid,
419 struct smbXcli_tcon *tcon,
420 struct smbXcli_session *session,
421 const char *pipe_name, uint16_t fid, uint16_t function, int flags,
422 uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
423 uint8_t *param, uint32_t num_param, uint32_t max_param,
424 uint8_t *data, uint32_t num_data, uint32_t max_data)
425{
426 struct tevent_req *req, *subreq;
427 struct smb1cli_trans_state *state;
428 int iov_count;
429 uint8_t wct;
430 NTSTATUS status;
431 charset_t charset;
432
433 req = tevent_req_create(mem_ctx, &state,
434 struct smb1cli_trans_state);
435 if (req == NULL) {
436 return NULL;
437 }
438
439 if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
440 if ((num_param > 0xffff) || (max_param > 0xffff)
441 || (num_data > 0xffff) || (max_data > 0xffff)) {
442 DEBUG(3, ("Attempt to send invalid trans2 request "
443 "(setup %u, params %u/%u, data %u/%u)\n",
444 (unsigned)num_setup,
445 (unsigned)num_param, (unsigned)max_param,
446 (unsigned)num_data, (unsigned)max_data));
447 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
448 return tevent_req_post(req, ev);
449 }
450 }
451
452 /*
453 * The largest wct will be for nttrans (19+num_setup). Make sure we
454 * don't overflow state->vwv in smb1cli_trans_format.
455 */
456
457 if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
458 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER_MIX);
459 return tevent_req_post(req, ev);
460 }
461
462 state->conn = conn;
463 state->ev = ev;
464 state->cmd = cmd;
465 state->additional_flags = additional_flags;
466 state->clear_flags = clear_flags;
467 state->additional_flags2 = additional_flags2;
468 state->clear_flags2 = clear_flags2;
469 state->timeout_msec = timeout_msec;
470 state->flags = flags;
471 state->num_rsetup = 0;
472 state->rsetup = NULL;
473 state->pid = pid;
474 state->tcon = tcon;
475 state->session = session;
476 ZERO_STRUCT(state->rparam);
477 ZERO_STRUCT(state->rdata);
478
479 if (smbXcli_conn_use_unicode(conn)) {
480 charset = CH_UTF16LE;
481 } else {
482 charset = CH_DOS;
483 }
484
485 if ((pipe_name != NULL)
486 && (!convert_string_talloc(state, CH_UNIX, charset,
487 pipe_name, strlen(pipe_name) + 1,
488 &state->pipe_name_conv,
489 &state->pipe_name_conv_len))) {
490 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
491 return tevent_req_post(req, ev);
492 }
493 state->fid = fid; /* trans2 */
494 state->function = function; /* nttrans */
495
496 state->setup = setup;
497 state->num_setup = num_setup;
498 state->max_setup = max_setup;
499
500 state->param = param;
501 state->num_param = num_param;
502 state->param_sent = 0;
503 state->rparam.max = max_param;
504
505 state->data = data;
506 state->num_data = num_data;
507 state->data_sent = 0;
508 state->rdata.max = max_data;
509
510 smb1cli_trans_format(state, &wct, &iov_count);
511
512 subreq = smb1cli_req_create(state, ev, conn, cmd,
513 state->additional_flags,
514 state->clear_flags,
515 state->additional_flags2,
516 state->clear_flags2,
517 state->timeout_msec,
518 state->pid,
519 state->tcon,
520 state->session,
521 wct, state->vwv,
522 iov_count, state->iov);
523 if (tevent_req_nomem(subreq, req)) {
524 return tevent_req_post(req, ev);
525 }
526 status = smb1cli_req_chain_submit(&subreq, 1);
527 if (tevent_req_nterror(req, status)) {
528 return tevent_req_post(req, state->ev);
529 }
530 tevent_req_set_callback(subreq, smb1cli_trans_done, req);
531
532 /*
533 * Now get the MID of the primary request
534 * and mark it as persistent. This means
535 * we will able to send and receive multiple
536 * SMB pdus using this MID in both directions
537 * (including correct SMB signing).
538 */
539 state->mid = smb1cli_req_mid(subreq);
540 smb1cli_req_set_mid(subreq, state->mid);
541 state->primary_subreq = subreq;
542 talloc_set_destructor(state, smb1cli_trans_state_destructor);
543
544 tevent_req_set_cancel_fn(req, smb1cli_trans_cancel);
545
546 return req;
547}
548
549static bool smb1cli_trans_cancel(struct tevent_req *req)
550{
551 struct smb1cli_trans_state *state =
552 tevent_req_data(req,
553 struct smb1cli_trans_state);
554
555 if (state->primary_subreq == NULL) {
556 return false;
557 }
558
559 return tevent_req_cancel(state->primary_subreq);
560}
561
562static void smb1cli_trans_done2(struct tevent_req *subreq);
563
564static void smb1cli_trans_done(struct tevent_req *subreq)
565{
566 struct tevent_req *req =
567 tevent_req_callback_data(subreq,
568 struct tevent_req);
569 struct smb1cli_trans_state *state =
570 tevent_req_data(req,
571 struct smb1cli_trans_state);
572 NTSTATUS status;
573 bool sent_all;
574 struct iovec *recv_iov = NULL;
575 uint8_t *inhdr;
576 uint8_t wct;
577 uint16_t *vwv;
578 uint32_t vwv_ofs;
579 uint32_t num_bytes;
580 uint8_t *bytes;
581 uint32_t bytes_ofs;
582 uint8_t num_setup = 0;
583 uint16_t *setup = NULL;
584 uint32_t total_param = 0;
585 uint32_t num_param = 0;
586 uint32_t param_disp = 0;
587 uint32_t total_data = 0;
588 uint32_t num_data = 0;
589 uint32_t data_disp = 0;
590 uint8_t *param = NULL;
591 uint8_t *data = NULL;
592
593 status = smb1cli_req_recv(subreq, state,
594 &recv_iov,
595 &inhdr,
596 &wct,
597 &vwv,
598 &vwv_ofs,
599 &num_bytes,
600 &bytes,
601 &bytes_ofs,
602 NULL, /* pinbuf */
603 NULL, 0); /* expected */
604 /*
605 * Do not TALLOC_FREE(subreq) here, we might receive more than
606 * one response for the same mid.
607 */
608
609 /*
610 * We can receive something like STATUS_MORE_ENTRIES, so don't use
611 * !NT_STATUS_IS_OK(status) here.
612 */
613
614 if (NT_STATUS_IS_ERR(status)) {
615 goto fail;
616 }
617
618 if (recv_iov == NULL) {
619 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
620 goto fail;
621 }
622 state->status = status;
623
624 sent_all = ((state->param_sent == state->num_param)
625 && (state->data_sent == state->num_data));
626
627 status = smb1cli_pull_trans(
628 inhdr, wct, vwv, vwv_ofs,
629 num_bytes, bytes, bytes_ofs,
630 state->cmd, !sent_all, &num_setup, &setup,
631 &total_param, &num_param, &param_disp, &param,
632 &total_data, &num_data, &data_disp, &data);
633
634 if (!NT_STATUS_IS_OK(status)) {
635 goto fail;
636 }
637
638 if (!sent_all) {
639 int iov_count;
640 struct tevent_req *subreq2;
641
642 smb1cli_trans_format(state, &wct, &iov_count);
643
644 subreq2 = smb1cli_req_create(state, state->ev, state->conn,
645 state->cmd + 1,
646 state->additional_flags,
647 state->clear_flags,
648 state->additional_flags2,
649 state->clear_flags2,
650 state->timeout_msec,
651 state->pid,
652 state->tcon,
653 state->session,
654 wct, state->vwv,
655 iov_count, state->iov);
656 if (tevent_req_nomem(subreq2, req)) {
657 return;
658 }
659 smb1cli_req_set_mid(subreq2, state->mid);
660
661 status = smb1cli_req_chain_submit(&subreq2, 1);
662
663 if (!NT_STATUS_IS_OK(status)) {
664 goto fail;
665 }
666 tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
667
668 return;
669 }
670
671 status = smb1cli_trans_pull_blob(
672 state, &state->rparam, total_param, num_param, param,
673 param_disp);
674
675 if (!NT_STATUS_IS_OK(status)) {
676 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
677 goto fail;
678 }
679
680 status = smb1cli_trans_pull_blob(
681 state, &state->rdata, total_data, num_data, data,
682 data_disp);
683
684 if (!NT_STATUS_IS_OK(status)) {
685 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
686 goto fail;
687 }
688
689 if ((state->rparam.total == state->rparam.received)
690 && (state->rdata.total == state->rdata.received)) {
691 state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
692 smb1cli_trans_cleanup_primary(state);
693 tevent_req_done(req);
694 return;
695 }
696
697 TALLOC_FREE(recv_iov);
698
699 return;
700
701 fail:
702 smb1cli_trans_cleanup_primary(state);
703 tevent_req_nterror(req, status);
704}
705
706static void smb1cli_trans_done2(struct tevent_req *subreq2)
707{
708 struct tevent_req *req =
709 tevent_req_callback_data(subreq2,
710 struct tevent_req);
711 struct smb1cli_trans_state *state =
712 tevent_req_data(req,
713 struct smb1cli_trans_state);
714 NTSTATUS status;
715 bool sent_all;
716 uint32_t seqnum;
717
718 /*
719 * First backup the seqnum of the secondary request
720 * and attach it to the primary request.
721 */
722 seqnum = smb1cli_req_seqnum(subreq2);
723 smb1cli_req_set_seqnum(state->primary_subreq, seqnum);
724
725 /* This was a one way request */
726 status = smb1cli_req_recv(subreq2, state,
727 NULL, /* recv_iov */
728 NULL, /* phdr */
729 NULL, /* pwct */
730 NULL, /* pvwv */
731 NULL, /* pvwv_offset */
732 NULL, /* pnum_bytes */
733 NULL, /* pbytes */
734 NULL, /* pbytes_offset */
735 NULL, /* pinbuf */
736 NULL, 0); /* expected */
737 TALLOC_FREE(subreq2);
738
739 if (!NT_STATUS_IS_OK(status)) {
740 goto fail;
741 }
742
743 sent_all = ((state->param_sent == state->num_param)
744 && (state->data_sent == state->num_data));
745
746 if (!sent_all) {
747 uint8_t wct;
748 int iov_count;
749
750 smb1cli_trans_format(state, &wct, &iov_count);
751
752 subreq2 = smb1cli_req_create(state, state->ev, state->conn,
753 state->cmd + 1,
754 state->additional_flags,
755 state->clear_flags,
756 state->additional_flags2,
757 state->clear_flags2,
758 state->timeout_msec,
759 state->pid,
760 state->tcon,
761 state->session,
762 wct, state->vwv,
763 iov_count, state->iov);
764 if (tevent_req_nomem(subreq2, req)) {
765 return;
766 }
767 smb1cli_req_set_mid(subreq2, state->mid);
768
769 status = smb1cli_req_chain_submit(&subreq2, 1);
770
771 if (!NT_STATUS_IS_OK(status)) {
772 goto fail;
773 }
774 tevent_req_set_callback(subreq2, smb1cli_trans_done2, req);
775 return;
776 }
777
778 return;
779
780 fail:
781 smb1cli_trans_cleanup_primary(state);
782 tevent_req_nterror(req, status);
783}
784
785NTSTATUS smb1cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
786 uint16_t *recv_flags2,
787 uint16_t **setup, uint8_t min_setup,
788 uint8_t *num_setup,
789 uint8_t **param, uint32_t min_param,
790 uint32_t *num_param,
791 uint8_t **data, uint32_t min_data,
792 uint32_t *num_data)
793{
794 struct smb1cli_trans_state *state =
795 tevent_req_data(req,
796 struct smb1cli_trans_state);
797 NTSTATUS status;
798
799 smb1cli_trans_cleanup_primary(state);
800
801 if (tevent_req_is_nterror(req, &status)) {
802 if (!NT_STATUS_IS_ERR(status)) {
803 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
804 }
805 tevent_req_received(req);
806 return status;
807 }
808
809 if ((state->num_rsetup < min_setup)
810 || (state->rparam.total < min_param)
811 || (state->rdata.total < min_data)) {
812 tevent_req_received(req);
813 return NT_STATUS_INVALID_NETWORK_RESPONSE;
814 }
815
816 if (recv_flags2 != NULL) {
817 *recv_flags2 = state->recv_flags2;
818 }
819
820 if (setup != NULL) {
821 *setup = talloc_move(mem_ctx, &state->rsetup);
822 *num_setup = state->num_rsetup;
823 } else {
824 TALLOC_FREE(state->rsetup);
825 }
826
827 if (param != NULL) {
828 *param = talloc_move(mem_ctx, &state->rparam.data);
829 *num_param = state->rparam.total;
830 } else {
831 TALLOC_FREE(state->rparam.data);
832 }
833
834 if (data != NULL) {
835 *data = talloc_move(mem_ctx, &state->rdata.data);
836 *num_data = state->rdata.total;
837 } else {
838 TALLOC_FREE(state->rdata.data);
839 }
840
841 status = state->status;
842 tevent_req_received(req);
843 return status;
844}
845
846NTSTATUS smb1cli_trans(TALLOC_CTX *mem_ctx, struct smbXcli_conn *conn,
847 uint8_t trans_cmd,
848 uint8_t additional_flags, uint8_t clear_flags,
849 uint16_t additional_flags2, uint16_t clear_flags2,
850 uint32_t timeout_msec,
851 uint32_t pid,
852 struct smbXcli_tcon *tcon,
853 struct smbXcli_session *session,
854 const char *pipe_name, uint16_t fid, uint16_t function,
855 int flags,
856 uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
857 uint8_t *param, uint32_t num_param, uint32_t max_param,
858 uint8_t *data, uint32_t num_data, uint32_t max_data,
859 uint16_t *recv_flags2,
860 uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
861 uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
862 uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
863{
864 TALLOC_CTX *frame = talloc_stackframe();
865 struct tevent_context *ev;
866 struct tevent_req *req;
867 NTSTATUS status = NT_STATUS_NO_MEMORY;
868
869 if (smbXcli_conn_has_async_calls(conn)) {
870 /*
871 * Can't use sync call while an async call is in flight
872 */
873 status = NT_STATUS_INVALID_PARAMETER_MIX;
874 goto fail;
875 }
876
877 ev = samba_tevent_context_init(frame);
878 if (ev == NULL) {
879 goto fail;
880 }
881
882 req = smb1cli_trans_send(frame, ev, conn, trans_cmd,
883 additional_flags, clear_flags,
884 additional_flags2, clear_flags2,
885 timeout_msec,
886 pid, tcon, session,
887 pipe_name, fid, function, flags,
888 setup, num_setup, max_setup,
889 param, num_param, max_param,
890 data, num_data, max_data);
891 if (req == NULL) {
892 goto fail;
893 }
894
895 if (!tevent_req_poll_ntstatus(req, ev, &status)) {
896 goto fail;
897 }
898
899 status = smb1cli_trans_recv(req, mem_ctx, recv_flags2,
900 rsetup, min_rsetup, num_rsetup,
901 rparam, min_rparam, num_rparam,
902 rdata, min_rdata, num_rdata);
903 fail:
904 TALLOC_FREE(frame);
905 return status;
906}
Note: See TracBrowser for help on using the repository browser.