2 Unix SMB/CIFS implementation.
3 client transaction calls
4 Copyright (C) Andrew Tridgell 1994-1998
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.
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.
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/>.
21 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
25 struct trans_recvblob
{
27 uint32_t max
, total
, received
;
30 struct cli_trans_state
{
31 struct cli_state
*cli
;
32 struct event_context
*ev
;
36 const char *pipe_name
;
37 uint8_t *pipe_name_conv
;
38 size_t pipe_name_conv_len
;
43 uint8_t num_setup
, max_setup
;
45 uint32_t num_param
, param_sent
;
47 uint32_t num_data
, data_sent
;
51 struct trans_recvblob rparam
;
52 struct trans_recvblob rdata
;
55 TALLOC_CTX
*secondary_request_ctx
;
62 static NTSTATUS
cli_pull_trans(uint8_t *inbuf
,
63 uint8_t wct
, uint16_t *vwv
,
64 uint16_t num_bytes
, uint8_t *bytes
,
65 uint8_t smb_cmd
, bool expect_first_reply
,
66 uint8_t *pnum_setup
, uint16_t **psetup
,
67 uint32_t *ptotal_param
, uint32_t *pnum_param
,
68 uint32_t *pparam_disp
, uint8_t **pparam
,
69 uint32_t *ptotal_data
, uint32_t *pnum_data
,
70 uint32_t *pdata_disp
, uint8_t **pdata
)
72 uint32_t param_ofs
, data_ofs
;
74 if (expect_first_reply
) {
75 if ((wct
!= 0) || (num_bytes
!= 0)) {
76 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
85 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
87 *ptotal_param
= SVAL(vwv
+ 0, 0);
88 *ptotal_data
= SVAL(vwv
+ 1, 0);
89 *pnum_param
= SVAL(vwv
+ 3, 0);
90 param_ofs
= SVAL(vwv
+ 4, 0);
91 *pparam_disp
= SVAL(vwv
+ 5, 0);
92 *pnum_data
= SVAL(vwv
+ 6, 0);
93 data_ofs
= SVAL(vwv
+ 7, 0);
94 *pdata_disp
= SVAL(vwv
+ 8, 0);
95 *pnum_setup
= CVAL(vwv
+ 9, 0);
96 if (wct
< 10 + (*pnum_setup
)) {
97 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
104 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
106 *ptotal_param
= IVAL(vwv
, 3);
107 *ptotal_data
= IVAL(vwv
, 7);
108 *pnum_param
= IVAL(vwv
, 11);
109 param_ofs
= IVAL(vwv
, 15);
110 *pparam_disp
= IVAL(vwv
, 19);
111 *pnum_data
= IVAL(vwv
, 23);
112 data_ofs
= IVAL(vwv
, 27);
113 *pdata_disp
= IVAL(vwv
, 31);
114 *pnum_setup
= CVAL(vwv
, 35);
119 return NT_STATUS_INTERNAL_ERROR
;
123 * Check for buffer overflows. data_ofs needs to be checked against
124 * the incoming buffer length, data_disp against the total
125 * length. Likewise for param_ofs/param_disp.
128 if (trans_oob(smb_len(inbuf
), param_ofs
, *pnum_param
)
129 || trans_oob(*ptotal_param
, *pparam_disp
, *pnum_param
)
130 || trans_oob(smb_len(inbuf
), data_ofs
, *pnum_data
)
131 || trans_oob(*ptotal_data
, *pdata_disp
, *pnum_data
)) {
132 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
135 *pparam
= (uint8_t *)inbuf
+ 4 + param_ofs
;
136 *pdata
= (uint8_t *)inbuf
+ 4 + data_ofs
;
141 static NTSTATUS
cli_trans_pull_blob(TALLOC_CTX
*mem_ctx
,
142 struct trans_recvblob
*blob
,
143 uint32_t total
, uint32_t thistime
,
144 uint8_t *buf
, uint32_t displacement
)
146 if (blob
->data
== NULL
) {
147 if (total
> blob
->max
) {
148 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
151 blob
->data
= TALLOC_ARRAY(mem_ctx
, uint8_t, total
);
152 if (blob
->data
== NULL
) {
153 return NT_STATUS_NO_MEMORY
;
157 if (total
> blob
->total
) {
158 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
162 memcpy(blob
->data
+ displacement
, buf
, thistime
);
163 blob
->received
+= thistime
;
169 static void cli_trans_format(struct cli_trans_state
*state
, uint8_t *pwct
,
173 struct iovec
*iov
= state
->iov
;
174 uint8_t *pad
= state
->pad
;
175 uint16_t *vwv
= state
->vwv
;
176 uint16_t param_offset
;
177 uint16_t this_param
= 0;
178 uint16_t this_data
= 0;
179 uint32_t useable_space
;
184 if ((state
->param_sent
!= 0) || (state
->data_sent
!= 0)) {
185 /* The secondary commands are one after the primary ones */
189 param_offset
= smb_size
- 4;
194 iov
[0].iov_base
= (void *)pad
;
196 iov
[1].iov_base
= (void *)state
->pipe_name_conv
;
197 iov
[1].iov_len
= state
->pipe_name_conv_len
;
198 wct
= 14 + state
->num_setup
;
199 param_offset
+= iov
[0].iov_len
+ iov
[1].iov_len
;
204 pad
[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
206 iov
[0].iov_base
= (void *)pad
;
208 wct
= 14 + state
->num_setup
;
219 wct
= 19 + state
->num_setup
;
226 useable_space
= state
->cli
->max_xmit
- smb_size
- sizeof(uint16_t)*wct
;
228 if (state
->param_sent
< state
->num_param
) {
229 this_param
= MIN(state
->num_param
- state
->param_sent
,
231 iov
[0].iov_base
= (void *)(state
->param
+ state
->param_sent
);
232 iov
[0].iov_len
= this_param
;
236 if (state
->data_sent
< state
->num_data
) {
237 this_data
= MIN(state
->num_data
- state
->data_sent
,
238 useable_space
- this_param
);
239 iov
[0].iov_base
= (void *)(state
->data
+ state
->data_sent
);
240 iov
[0].iov_len
= this_data
;
244 param_offset
+= wct
* sizeof(uint16_t);
246 DEBUG(10, ("num_setup=%u, max_setup=%u, "
247 "param_total=%u, this_param=%u, max_param=%u, "
248 "data_total=%u, this_data=%u, max_data=%u, "
249 "param_offset=%u, param_disp=%u, data_disp=%u\n",
250 (unsigned)state
->num_setup
, (unsigned)state
->max_setup
,
251 (unsigned)state
->num_param
, (unsigned)this_param
,
252 (unsigned)state
->rparam
.max
,
253 (unsigned)state
->num_data
, (unsigned)this_data
,
254 (unsigned)state
->rdata
.max
,
255 (unsigned)param_offset
,
256 (unsigned)state
->param_sent
, (unsigned)state
->data_sent
));
261 SSVAL(vwv
+ 0, 0, state
->num_param
);
262 SSVAL(vwv
+ 1, 0, state
->num_data
);
263 SSVAL(vwv
+ 2, 0, state
->rparam
.max
);
264 SSVAL(vwv
+ 3, 0, state
->rdata
.max
);
265 SCVAL(vwv
+ 4, 0, state
->max_setup
);
266 SCVAL(vwv
+ 4, 1, 0); /* reserved */
267 SSVAL(vwv
+ 5, 0, state
->flags
);
268 SIVAL(vwv
+ 6, 0, 0); /* timeout */
269 SSVAL(vwv
+ 8, 0, 0); /* reserved */
270 SSVAL(vwv
+ 9, 0, this_param
);
271 SSVAL(vwv
+10, 0, param_offset
);
272 SSVAL(vwv
+11, 0, this_data
);
273 SSVAL(vwv
+12, 0, param_offset
+ this_param
);
274 SCVAL(vwv
+13, 0, state
->num_setup
);
275 SCVAL(vwv
+13, 1, 0); /* reserved */
276 memcpy(vwv
+ 14, state
->setup
,
277 sizeof(uint16_t) * state
->num_setup
);
281 SSVAL(vwv
+ 0, 0, state
->num_param
);
282 SSVAL(vwv
+ 1, 0, state
->num_data
);
283 SSVAL(vwv
+ 2, 0, this_param
);
284 SSVAL(vwv
+ 3, 0, param_offset
);
285 SSVAL(vwv
+ 4, 0, state
->param_sent
);
286 SSVAL(vwv
+ 5, 0, this_data
);
287 SSVAL(vwv
+ 6, 0, param_offset
+ this_param
);
288 SSVAL(vwv
+ 7, 0, state
->data_sent
);
289 if (cmd
== SMBtranss2
) {
290 SSVAL(vwv
+ 8, 0, state
->fid
);
294 SCVAL(vwv
, 0, state
->max_setup
);
295 SSVAL(vwv
, 1, 0); /* reserved */
296 SIVAL(vwv
, 3, state
->num_param
);
297 SIVAL(vwv
, 7, state
->num_data
);
298 SIVAL(vwv
, 11, state
->rparam
.max
);
299 SIVAL(vwv
, 15, state
->rdata
.max
);
300 SIVAL(vwv
, 19, this_param
);
301 SIVAL(vwv
, 23, param_offset
);
302 SIVAL(vwv
, 27, this_data
);
303 SIVAL(vwv
, 31, param_offset
+ this_param
);
304 SCVAL(vwv
, 35, state
->num_setup
);
305 SSVAL(vwv
, 36, state
->function
);
306 memcpy(vwv
+ 19, state
->setup
,
307 sizeof(uint16_t) * state
->num_setup
);
310 SSVAL(vwv
, 0, 0); /* reserved */
311 SCVAL(vwv
, 2, 0); /* reserved */
312 SIVAL(vwv
, 3, state
->num_param
);
313 SIVAL(vwv
, 7, state
->num_data
);
314 SIVAL(vwv
, 11, this_param
);
315 SIVAL(vwv
, 15, param_offset
);
316 SIVAL(vwv
, 19, state
->param_sent
);
317 SIVAL(vwv
, 23, this_data
);
318 SIVAL(vwv
, 27, param_offset
+ this_param
);
319 SIVAL(vwv
, 31, state
->data_sent
);
320 SCVAL(vwv
, 35, 0); /* reserved */
324 state
->param_sent
+= this_param
;
325 state
->data_sent
+= this_data
;
328 *piov_count
= iov
- state
->iov
;
331 static void cli_trans_done(struct tevent_req
*subreq
);
333 struct tevent_req
*cli_trans_send(
334 TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
335 struct cli_state
*cli
, uint8_t cmd
,
336 const char *pipe_name
, uint16_t fid
, uint16_t function
, int flags
,
337 uint16_t *setup
, uint8_t num_setup
, uint8_t max_setup
,
338 uint8_t *param
, uint32_t num_param
, uint32_t max_param
,
339 uint8_t *data
, uint32_t num_data
, uint32_t max_data
)
341 struct tevent_req
*req
, *subreq
;
342 struct cli_trans_state
*state
;
347 req
= tevent_req_create(mem_ctx
, &state
, struct cli_trans_state
);
352 if ((cmd
== SMBtrans
) || (cmd
== SMBtrans2
)) {
353 if ((num_param
> 0xffff) || (max_param
> 0xffff)
354 || (num_data
> 0xffff) || (max_data
> 0xffff)) {
355 DEBUG(3, ("Attempt to send invalid trans2 request "
356 "(setup %u, params %u/%u, data %u/%u)\n",
358 (unsigned)num_param
, (unsigned)max_param
,
359 (unsigned)num_data
, (unsigned)max_data
));
360 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
361 return tevent_req_post(req
, ev
);
366 * The largest wct will be for nttrans (19+num_setup). Make sure we
367 * don't overflow state->vwv in cli_trans_format.
370 if ((num_setup
+ 19) > ARRAY_SIZE(state
->vwv
)) {
371 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
372 return tevent_req_post(req
, ev
);
378 state
->flags
= flags
;
379 state
->num_rsetup
= 0;
380 state
->rsetup
= NULL
;
381 ZERO_STRUCT(state
->rparam
);
382 ZERO_STRUCT(state
->rdata
);
384 if ((pipe_name
!= NULL
)
385 && (!convert_string_talloc(state
, CH_UNIX
,
386 cli_ucs2(cli
) ? CH_UTF16LE
: CH_DOS
,
387 pipe_name
, strlen(pipe_name
) + 1,
388 &state
->pipe_name_conv
,
389 &state
->pipe_name_conv_len
))) {
390 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
391 return tevent_req_post(req
, ev
);
393 state
->fid
= fid
; /* trans2 */
394 state
->function
= function
; /* nttrans */
396 state
->setup
= setup
;
397 state
->num_setup
= num_setup
;
398 state
->max_setup
= max_setup
;
400 state
->param
= param
;
401 state
->num_param
= num_param
;
402 state
->param_sent
= 0;
403 state
->rparam
.max
= max_param
;
406 state
->num_data
= num_data
;
407 state
->data_sent
= 0;
408 state
->rdata
.max
= max_data
;
410 cli_trans_format(state
, &wct
, &iov_count
);
412 subreq
= cli_smb_req_create(state
, ev
, cli
, cmd
, 0, wct
, state
->vwv
,
413 iov_count
, state
->iov
);
414 if (tevent_req_nomem(subreq
, req
)) {
415 return tevent_req_post(req
, ev
);
417 state
->mid
= cli_smb_req_mid(subreq
);
418 status
= cli_smb_req_send(subreq
);
419 if (!NT_STATUS_IS_OK(status
)) {
420 tevent_req_nterror(req
, status
);
421 return tevent_req_post(req
, state
->ev
);
423 cli_state_seqnum_persistent(cli
, state
->mid
);
424 tevent_req_set_callback(subreq
, cli_trans_done
, req
);
428 static void cli_trans_done(struct tevent_req
*subreq
)
430 struct tevent_req
*req
= tevent_req_callback_data(
431 subreq
, struct tevent_req
);
432 struct cli_trans_state
*state
= tevent_req_data(
433 req
, struct cli_trans_state
);
441 uint8_t num_setup
= 0;
442 uint16_t *setup
= NULL
;
443 uint32_t total_param
= 0;
444 uint32_t num_param
= 0;
445 uint32_t param_disp
= 0;
446 uint32_t total_data
= 0;
447 uint32_t num_data
= 0;
448 uint32_t data_disp
= 0;
449 uint8_t *param
= NULL
;
450 uint8_t *data
= NULL
;
452 status
= cli_smb_recv(subreq
, state
, &inbuf
, 0, &wct
, &vwv
,
455 * Do not TALLOC_FREE(subreq) here, we might receive more than
456 * one response for the same mid.
460 * We can receive something like STATUS_MORE_ENTRIES, so don't use
461 * !NT_STATUS_IS_OK(status) here.
464 if (NT_STATUS_IS_ERR(status
)) {
468 sent_all
= ((state
->param_sent
== state
->num_param
)
469 && (state
->data_sent
== state
->num_data
));
471 status
= cli_pull_trans(
472 inbuf
, wct
, vwv
, num_bytes
, bytes
,
473 state
->cmd
, !sent_all
, &num_setup
, &setup
,
474 &total_param
, &num_param
, ¶m_disp
, ¶m
,
475 &total_data
, &num_data
, &data_disp
, &data
);
477 if (!NT_STATUS_IS_OK(status
)) {
486 cli_trans_format(state
, &wct
, &iov_count
);
488 subreq
= cli_smb_req_create(state
, state
->ev
, state
->cli
,
489 state
->cmd
+ 1, 0, wct
, state
->vwv
,
490 iov_count
, state
->iov
);
491 if (tevent_req_nomem(subreq
, req
)) {
494 cli_smb_req_set_mid(subreq
, state
->mid
);
496 status
= cli_smb_req_send(subreq
);
498 if (!NT_STATUS_IS_OK(status
)) {
501 tevent_req_set_callback(subreq
, cli_trans_done
, req
);
505 status
= cli_trans_pull_blob(
506 state
, &state
->rparam
, total_param
, num_param
, param
,
509 if (!NT_STATUS_IS_OK(status
)) {
510 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status
)));
514 status
= cli_trans_pull_blob(
515 state
, &state
->rdata
, total_data
, num_data
, data
,
518 if (!NT_STATUS_IS_OK(status
)) {
519 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status
)));
523 if ((state
->rparam
.total
== state
->rparam
.received
)
524 && (state
->rdata
.total
== state
->rdata
.received
)) {
525 state
->recv_flags2
= SVAL(inbuf
, smb_flg2
);
527 cli_state_seqnum_remove(state
->cli
, state
->mid
);
528 tevent_req_done(req
);
534 if (!cli_smb_req_set_pending(subreq
)) {
535 status
= NT_STATUS_NO_MEMORY
;
541 cli_state_seqnum_remove(state
->cli
, state
->mid
);
543 tevent_req_nterror(req
, status
);
546 NTSTATUS
cli_trans_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
547 uint16_t *recv_flags2
,
548 uint16_t **setup
, uint8_t min_setup
,
550 uint8_t **param
, uint32_t min_param
,
552 uint8_t **data
, uint32_t min_data
,
555 struct cli_trans_state
*state
= tevent_req_data(
556 req
, struct cli_trans_state
);
559 if (tevent_req_is_nterror(req
, &status
)) {
563 if ((state
->num_rsetup
< min_setup
)
564 || (state
->rparam
.total
< min_param
)
565 || (state
->rdata
.total
< min_data
)) {
566 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
569 if (recv_flags2
!= NULL
) {
570 *recv_flags2
= state
->recv_flags2
;
574 *setup
= talloc_move(mem_ctx
, &state
->rsetup
);
575 *num_setup
= state
->num_rsetup
;
577 TALLOC_FREE(state
->rsetup
);
581 *param
= talloc_move(mem_ctx
, &state
->rparam
.data
);
582 *num_param
= state
->rparam
.total
;
584 TALLOC_FREE(state
->rparam
.data
);
588 *data
= talloc_move(mem_ctx
, &state
->rdata
.data
);
589 *num_data
= state
->rdata
.total
;
591 TALLOC_FREE(state
->rdata
.data
);
597 NTSTATUS
cli_trans(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
599 const char *pipe_name
, uint16_t fid
, uint16_t function
,
601 uint16_t *setup
, uint8_t num_setup
, uint8_t max_setup
,
602 uint8_t *param
, uint32_t num_param
, uint32_t max_param
,
603 uint8_t *data
, uint32_t num_data
, uint32_t max_data
,
604 uint16_t *recv_flags2
,
605 uint16_t **rsetup
, uint8_t min_rsetup
, uint8_t *num_rsetup
,
606 uint8_t **rparam
, uint32_t min_rparam
, uint32_t *num_rparam
,
607 uint8_t **rdata
, uint32_t min_rdata
, uint32_t *num_rdata
)
609 TALLOC_CTX
*frame
= talloc_stackframe();
610 struct event_context
*ev
;
611 struct tevent_req
*req
;
612 NTSTATUS status
= NT_STATUS_OK
;
614 if (cli_has_async_calls(cli
)) {
616 * Can't use sync call while an async call is in flight
618 status
= NT_STATUS_INVALID_PARAMETER
;
622 ev
= event_context_init(frame
);
624 status
= NT_STATUS_NO_MEMORY
;
628 req
= cli_trans_send(frame
, ev
, cli
, trans_cmd
,
629 pipe_name
, fid
, function
, flags
,
630 setup
, num_setup
, max_setup
,
631 param
, num_param
, max_param
,
632 data
, num_data
, max_data
);
634 status
= NT_STATUS_NO_MEMORY
;
638 if (!tevent_req_poll(req
, ev
)) {
639 status
= map_nt_error_from_unix(errno
);
643 status
= cli_trans_recv(req
, mem_ctx
, recv_flags2
,
644 rsetup
, min_rsetup
, num_rsetup
,
645 rparam
, min_rparam
, num_rparam
,
646 rdata
, min_rdata
, num_rdata
);
649 if (!NT_STATUS_IS_OK(status
)) {
650 cli_set_error(cli
, status
);