2 Unix SMB/CIFS implementation.
3 raw trans/trans2/nttrans operations
5 Copyright (C) James Myers 2003 <myersjj@samba.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include "../lib/util/dlinklist.h"
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
26 #define TORTURE_TRANS_DATA 0
29 check out of bounds for incoming data
31 static bool raw_trans_oob(struct smbcli_request
*req
,
32 uint_t offset
, uint_t count
)
40 ptr
= req
->in
.hdr
+ offset
;
42 /* be careful with wraparound! */
43 if ((uintptr_t)ptr
< (uintptr_t)req
->in
.data
||
44 (uintptr_t)ptr
>= (uintptr_t)req
->in
.data
+ req
->in
.data_size
||
45 count
> req
->in
.data_size
||
46 (uintptr_t)ptr
+ count
> (uintptr_t)req
->in
.data
+ req
->in
.data_size
) {
52 static size_t raw_trans_space_left(struct smbcli_request
*req
)
54 if (req
->transport
->negotiate
.max_xmit
<= req
->out
.size
) {
58 return req
->transport
->negotiate
.max_xmit
- req
->out
.size
;
61 struct smb_raw_trans2_recv_state
{
63 uint32_t params_total
;
73 NTSTATUS
smb_raw_trans2_recv(struct smbcli_request
*req
,
75 struct smb_trans2
*parms
)
77 struct smb_raw_trans2_recv_state
*state
;
79 if (!smbcli_request_receive(req
) ||
80 smbcli_request_is_error(req
)) {
84 state
= talloc_get_type(req
->recv_helper
.private_data
,
85 struct smb_raw_trans2_recv_state
);
87 parms
->out
= state
->io
.out
;
88 talloc_steal(mem_ctx
, parms
->out
.setup
);
89 talloc_steal(mem_ctx
, parms
->out
.params
.data
);
90 talloc_steal(mem_ctx
, parms
->out
.data
.data
);
93 ZERO_STRUCT(req
->recv_helper
);
96 return smbcli_request_destroy(req
);
99 static enum smbcli_request_state
smb_raw_trans2_ship_rest(struct smbcli_request
*req
,
100 struct smb_raw_trans2_recv_state
*state
);
103 * This helper returns SMBCLI_REQUEST_RECV until all data has arrived
105 static enum smbcli_request_state
smb_raw_trans2_recv_helper(struct smbcli_request
*req
)
107 struct smb_raw_trans2_recv_state
*state
= talloc_get_type(req
->recv_helper
.private_data
,
108 struct smb_raw_trans2_recv_state
);
109 uint16_t param_count
, param_ofs
, param_disp
;
110 uint16_t data_count
, data_ofs
, data_disp
;
111 uint16_t total_data
, total_param
;
115 * An NT RPC pipe call can return ERRDOS, ERRmoredata
116 * to a trans call. This is not an error and should not
117 * be treated as such.
119 if (smbcli_request_is_error(req
)) {
123 if (state
->params_left
> 0 || state
->data_left
> 0) {
124 return smb_raw_trans2_ship_rest(req
, state
);
127 SMBCLI_CHECK_MIN_WCT(req
, 10);
129 total_data
= SVAL(req
->in
.vwv
, VWV(1));
130 total_param
= SVAL(req
->in
.vwv
, VWV(0));
131 setup_count
= CVAL(req
->in
.vwv
, VWV(9));
133 param_count
= SVAL(req
->in
.vwv
, VWV(3));
134 param_ofs
= SVAL(req
->in
.vwv
, VWV(4));
135 param_disp
= SVAL(req
->in
.vwv
, VWV(5));
137 data_count
= SVAL(req
->in
.vwv
, VWV(6));
138 data_ofs
= SVAL(req
->in
.vwv
, VWV(7));
139 data_disp
= SVAL(req
->in
.vwv
, VWV(8));
141 if (!state
->got_first
) {
142 if (total_param
> 0) {
143 state
->io
.out
.params
= data_blob_talloc(state
, NULL
, total_param
);
144 if (!state
->io
.out
.params
.data
) {
149 if (total_data
> 0) {
150 state
->io
.out
.data
= data_blob_talloc(state
, NULL
, total_data
);
151 if (!state
->io
.out
.data
.data
) {
156 if (setup_count
> 0) {
159 SMBCLI_CHECK_WCT(req
, 10 + setup_count
);
161 state
->io
.out
.setup_count
= setup_count
;
162 state
->io
.out
.setup
= talloc_array(state
, uint16_t, setup_count
);
163 if (!state
->io
.out
.setup
) {
166 for (i
=0; i
< setup_count
; i
++) {
167 state
->io
.out
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(10+i
));
171 state
->got_first
= true;
174 if (total_data
> state
->io
.out
.data
.length
||
175 total_param
> state
->io
.out
.params
.length
) {
176 /* they must *only* shrink */
177 DEBUG(1,("smb_raw_trans2_recv_helper: data/params expanded!\n"));
178 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
182 state
->io
.out
.data
.length
= total_data
;
183 state
->io
.out
.params
.length
= total_param
;
185 if (data_count
+ data_disp
> total_data
||
186 param_count
+ param_disp
> total_param
) {
187 DEBUG(1,("smb_raw_trans2_recv_helper: Buffer overflow\n"));
188 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
192 /* check the server isn't being nasty */
193 if (raw_trans_oob(req
, param_ofs
, param_count
) ||
194 raw_trans_oob(req
, data_ofs
, data_count
)) {
195 DEBUG(1,("smb_raw_trans2_recv_helper: out of bounds parameters!\n"));
196 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
201 memcpy(state
->io
.out
.data
.data
+ data_disp
,
202 req
->in
.hdr
+ data_ofs
,
207 memcpy(state
->io
.out
.params
.data
+ param_disp
,
208 req
->in
.hdr
+ param_ofs
,
212 state
->recvd_param
+= param_count
;
213 state
->recvd_data
+= data_count
;
215 if (state
->recvd_data
< total_data
||
216 state
->recvd_param
< total_param
) {
218 /* we don't need the in buffer any more */
219 talloc_free(req
->in
.buffer
);
220 ZERO_STRUCT(req
->in
);
222 /* we still wait for more data */
223 DEBUG(10,("smb_raw_trans2_recv_helper: more data needed\n"));
224 return SMBCLI_REQUEST_RECV
;
227 DEBUG(10,("smb_raw_trans2_recv_helper: done\n"));
228 return SMBCLI_REQUEST_DONE
;
231 req
->status
= NT_STATUS_NO_MEMORY
;
233 return SMBCLI_REQUEST_ERROR
;
236 _PUBLIC_ NTSTATUS
smb_raw_trans_recv(struct smbcli_request
*req
,
238 struct smb_trans2
*parms
)
240 return smb_raw_trans2_recv(req
, mem_ctx
, parms
);
245 trans/trans2 raw async interface - only BLOBs used in this interface.
247 struct smbcli_request
*smb_raw_trans_send_backend(struct smbcli_tree
*tree
,
248 struct smb_trans2
*parms
,
251 struct smb_raw_trans2_recv_state
*state
;
252 struct smbcli_request
*req
;
257 DATA_BLOB params_chunk
;
259 uint16_t params_ofs
= 0;
260 DATA_BLOB data_chunk
;
261 uint16_t data_ofs
= 0;
263 if (parms
->in
.params
.length
> UINT16_MAX
||
264 parms
->in
.data
.length
> UINT16_MAX
) {
265 DEBUG(3,("Attempt to send invalid trans2 request (params %u, data %u)\n",
266 (unsigned)parms
->in
.params
.length
, (unsigned)parms
->in
.data
.length
));
271 if (command
== SMBtrans
)
276 req
= smbcli_request_setup(tree
, command
,
277 14 + parms
->in
.setup_count
,
283 state
= talloc_zero(req
, struct smb_raw_trans2_recv_state
);
285 smbcli_request_destroy(req
);
289 state
->command
= command
;
291 /* make sure we don't leak data via the padding */
292 memset(req
->out
.data
, 0, padding
);
294 /* Watch out, this changes the req->out.* pointers */
295 if (command
== SMBtrans
&& parms
->in
.trans_name
) {
296 namelen
= smbcli_req_append_string(req
, parms
->in
.trans_name
,
300 ofs
= PTR_DIFF(req
->out
.data
,req
->out
.hdr
)+padding
+namelen
;
302 /* see how much bytes of the params block we can ship in the first request */
303 space_left
= raw_trans_space_left(req
);
305 params_chunk
.length
= MIN(parms
->in
.params
.length
, space_left
);
306 params_chunk
.data
= parms
->in
.params
.data
;
309 state
->params_left
= parms
->in
.params
.length
- params_chunk
.length
;
311 if (state
->params_left
> 0) {
312 /* we copy the whole params block, if needed we can optimize that latter */
313 state
->io
.in
.params
= data_blob_talloc(state
, NULL
, parms
->in
.params
.length
);
314 if (!state
->io
.in
.params
.data
) {
315 smbcli_request_destroy(req
);
318 memcpy(state
->io
.in
.params
.data
,
319 parms
->in
.params
.data
,
320 parms
->in
.params
.length
);
323 /* see how much bytes of the data block we can ship in the first request */
324 space_left
-= params_chunk
.length
;
326 #if TORTURE_TRANS_DATA
327 if (space_left
> 1) {
332 data_chunk
.length
= MIN(parms
->in
.data
.length
, space_left
);
333 data_chunk
.data
= parms
->in
.data
.data
;
334 data_ofs
= params_ofs
+ params_chunk
.length
;
336 state
->data_left
= parms
->in
.data
.length
- data_chunk
.length
;
338 if (state
->data_left
> 0) {
339 /* we copy the whole params block, if needed we can optimize that latter */
340 state
->io
.in
.data
= data_blob_talloc(state
, NULL
, parms
->in
.data
.length
);
341 if (!state
->io
.in
.data
.data
) {
342 smbcli_request_destroy(req
);
345 memcpy(state
->io
.in
.data
.data
,
347 parms
->in
.data
.length
);
350 state
->params_total
= parms
->in
.params
.length
;
351 state
->data_total
= parms
->in
.data
.length
;
353 /* primary request */
354 SSVAL(req
->out
.vwv
,VWV(0),parms
->in
.params
.length
);
355 SSVAL(req
->out
.vwv
,VWV(1),parms
->in
.data
.length
);
356 SSVAL(req
->out
.vwv
,VWV(2),parms
->in
.max_param
);
357 SSVAL(req
->out
.vwv
,VWV(3),parms
->in
.max_data
);
358 SCVAL(req
->out
.vwv
,VWV(4),parms
->in
.max_setup
);
359 SCVAL(req
->out
.vwv
,VWV(4)+1,0); /* reserved */
360 SSVAL(req
->out
.vwv
,VWV(5),parms
->in
.flags
);
361 SIVAL(req
->out
.vwv
,VWV(6),parms
->in
.timeout
);
362 SSVAL(req
->out
.vwv
,VWV(8),0); /* reserved */
363 SSVAL(req
->out
.vwv
,VWV(9),params_chunk
.length
);
364 SSVAL(req
->out
.vwv
,VWV(10),params_ofs
);
365 SSVAL(req
->out
.vwv
,VWV(11),data_chunk
.length
);
366 SSVAL(req
->out
.vwv
,VWV(12),data_ofs
);
367 SCVAL(req
->out
.vwv
,VWV(13),parms
->in
.setup_count
);
368 SCVAL(req
->out
.vwv
,VWV(13)+1,0); /* reserved */
369 for (i
=0;i
<parms
->in
.setup_count
;i
++) {
370 SSVAL(req
->out
.vwv
,VWV(14)+VWV(i
),parms
->in
.setup
[i
]);
372 smbcli_req_append_blob(req
, ¶ms_chunk
);
373 smbcli_req_append_blob(req
, &data_chunk
);
375 /* add the helper which will check that all multi-part replies are
376 in before an async client callack will be issued */
377 req
->recv_helper
.fn
= smb_raw_trans2_recv_helper
;
378 req
->recv_helper
.private_data
= state
;
380 if (!smbcli_request_send(req
)) {
381 smbcli_request_destroy(req
);
388 static enum smbcli_request_state
smb_raw_trans2_ship_next(struct smbcli_request
*req
,
389 struct smb_raw_trans2_recv_state
*state
)
391 struct smbcli_request
*req2
;
393 DATA_BLOB params_chunk
;
395 uint16_t params_ofs
= 0;
396 uint16_t params_disp
= 0;
397 DATA_BLOB data_chunk
;
398 uint16_t data_ofs
= 0;
399 uint16_t data_disp
= 0;
402 if (state
->command
== SMBtrans2
) {
408 req2
= smbcli_request_setup(req
->tree
, state
->command
+1, wct
, 0);
412 req2
->mid
= req
->mid
;
413 SSVAL(req2
->out
.hdr
, HDR_MID
, req2
->mid
);
415 ofs
= PTR_DIFF(req2
->out
.data
,req2
->out
.hdr
);
417 /* see how much bytes of the params block we can ship in the first request */
418 space_left
= raw_trans_space_left(req2
);
420 params_disp
= state
->io
.in
.params
.length
- state
->params_left
;
421 params_chunk
.length
= MIN(state
->params_left
, space_left
);
422 params_chunk
.data
= state
->io
.in
.params
.data
+ params_disp
;
425 state
->params_left
-= params_chunk
.length
;
427 /* see how much bytes of the data block we can ship in the first request */
428 space_left
-= params_chunk
.length
;
430 #if TORTURE_TRANS_DATA
431 if (space_left
> 1) {
436 data_disp
= state
->io
.in
.data
.length
- state
->data_left
;
437 data_chunk
.length
= MIN(state
->data_left
, space_left
);
438 data_chunk
.data
= state
->io
.in
.data
.data
+ data_disp
;
439 data_ofs
= params_ofs
+params_chunk
.length
;
441 state
->data_left
-= data_chunk
.length
;
443 SSVAL(req2
->out
.vwv
,VWV(0), state
->params_total
);
444 SSVAL(req2
->out
.vwv
,VWV(1), state
->data_total
);
445 SSVAL(req2
->out
.vwv
,VWV(2), params_chunk
.length
);
446 SSVAL(req2
->out
.vwv
,VWV(3), params_ofs
);
447 SSVAL(req2
->out
.vwv
,VWV(4), params_disp
);
448 SSVAL(req2
->out
.vwv
,VWV(5), data_chunk
.length
);
449 SSVAL(req2
->out
.vwv
,VWV(6), data_ofs
);
450 SSVAL(req2
->out
.vwv
,VWV(7), data_disp
);
452 SSVAL(req2
->out
.vwv
,VWV(8), 0xFFFF);
455 smbcli_req_append_blob(req2
, ¶ms_chunk
);
456 smbcli_req_append_blob(req2
, &data_chunk
);
459 * it's a one way request but we need
460 * the seq_num, so we destroy req2 by hand
462 if (!smbcli_request_send(req2
)) {
466 req
->seq_num
= req2
->seq_num
;
467 smbcli_request_destroy(req2
);
469 return SMBCLI_REQUEST_RECV
;
472 req
->status
= NT_STATUS_NO_MEMORY
;
475 req
->status
= smbcli_request_destroy(req2
);
477 return SMBCLI_REQUEST_ERROR
;
480 static enum smbcli_request_state
smb_raw_trans2_ship_rest(struct smbcli_request
*req
,
481 struct smb_raw_trans2_recv_state
*state
)
483 enum smbcli_request_state ret
= SMBCLI_REQUEST_ERROR
;
485 while (state
->params_left
> 0 || state
->data_left
> 0) {
486 ret
= smb_raw_trans2_ship_next(req
, state
);
487 if (ret
!= SMBCLI_REQUEST_RECV
) {
497 trans/trans2 raw async interface - only BLOBs used in this interface.
498 note that this doesn't yet support multi-part requests
500 _PUBLIC_
struct smbcli_request
*smb_raw_trans_send(struct smbcli_tree
*tree
,
501 struct smb_trans2
*parms
)
503 return smb_raw_trans_send_backend(tree
, parms
, SMBtrans
);
506 struct smbcli_request
*smb_raw_trans2_send(struct smbcli_tree
*tree
,
507 struct smb_trans2
*parms
)
509 return smb_raw_trans_send_backend(tree
, parms
, SMBtrans2
);
513 trans2 synchronous blob interface
515 NTSTATUS
smb_raw_trans2(struct smbcli_tree
*tree
,
517 struct smb_trans2
*parms
)
519 struct smbcli_request
*req
;
520 req
= smb_raw_trans2_send(tree
, parms
);
521 if (!req
) return NT_STATUS_UNSUCCESSFUL
;
522 return smb_raw_trans2_recv(req
, mem_ctx
, parms
);
527 trans synchronous blob interface
529 _PUBLIC_ NTSTATUS
smb_raw_trans(struct smbcli_tree
*tree
,
531 struct smb_trans2
*parms
)
533 struct smbcli_request
*req
;
534 req
= smb_raw_trans_send(tree
, parms
);
535 if (!req
) return NT_STATUS_UNSUCCESSFUL
;
536 return smb_raw_trans_recv(req
, mem_ctx
, parms
);
539 struct smb_raw_nttrans_recv_state
{
540 uint32_t params_total
;
542 uint32_t params_left
;
546 uint32_t recvd_param
;
547 struct smb_nttrans io
;
550 NTSTATUS
smb_raw_nttrans_recv(struct smbcli_request
*req
,
552 struct smb_nttrans
*parms
)
554 struct smb_raw_nttrans_recv_state
*state
;
556 if (!smbcli_request_receive(req
) ||
557 smbcli_request_is_error(req
)) {
561 state
= talloc_get_type(req
->recv_helper
.private_data
,
562 struct smb_raw_nttrans_recv_state
);
564 parms
->out
= state
->io
.out
;
565 talloc_steal(mem_ctx
, parms
->out
.setup
);
566 talloc_steal(mem_ctx
, parms
->out
.params
.data
);
567 talloc_steal(mem_ctx
, parms
->out
.data
.data
);
570 ZERO_STRUCT(req
->recv_helper
);
573 return smbcli_request_destroy(req
);
576 static enum smbcli_request_state
smb_raw_nttrans_ship_rest(struct smbcli_request
*req
,
577 struct smb_raw_nttrans_recv_state
*state
);
580 * This helper returns SMBCLI_REQUEST_RECV until all data has arrived
582 static enum smbcli_request_state
smb_raw_nttrans_recv_helper(struct smbcli_request
*req
)
584 struct smb_raw_nttrans_recv_state
*state
= talloc_get_type(req
->recv_helper
.private_data
,
585 struct smb_raw_nttrans_recv_state
);
586 uint32_t param_count
, param_ofs
, param_disp
;
587 uint32_t data_count
, data_ofs
, data_disp
;
588 uint32_t total_data
, total_param
;
592 * An NT RPC pipe call can return ERRDOS, ERRmoredata
593 * to a trans call. This is not an error and should not
594 * be treated as such.
596 if (smbcli_request_is_error(req
)) {
601 if (CVAL(req
->in
.hdr
, HDR_COM
) != SMBnttrans
) {
602 DEBUG(0,("smb_raw_nttrans_recv_helper: Expected %s response, got command 0x%02x\n",
604 CVAL(req
->in
.hdr
,HDR_COM
)));
605 req
->status
= NT_STATUS_INVALID_NETWORK_RESPONSE
;
609 if (state
->params_left
> 0 || state
->data_left
> 0) {
610 return smb_raw_nttrans_ship_rest(req
, state
);
613 /* this is the first packet of the response */
614 SMBCLI_CHECK_MIN_WCT(req
, 18);
616 total_param
= IVAL(req
->in
.vwv
, 3);
617 total_data
= IVAL(req
->in
.vwv
, 7);
618 setup_count
= CVAL(req
->in
.vwv
, 35);
620 param_count
= IVAL(req
->in
.vwv
, 11);
621 param_ofs
= IVAL(req
->in
.vwv
, 15);
622 param_disp
= IVAL(req
->in
.vwv
, 19);
624 data_count
= IVAL(req
->in
.vwv
, 23);
625 data_ofs
= IVAL(req
->in
.vwv
, 27);
626 data_disp
= IVAL(req
->in
.vwv
, 31);
628 if (!state
->got_first
) {
629 if (total_param
> 0) {
630 state
->io
.out
.params
= data_blob_talloc(state
, NULL
, total_param
);
631 if (!state
->io
.out
.params
.data
) {
636 if (total_data
> 0) {
637 state
->io
.out
.data
= data_blob_talloc(state
, NULL
, total_data
);
638 if (!state
->io
.out
.data
.data
) {
643 if (setup_count
> 0) {
644 SMBCLI_CHECK_WCT(req
, 18 + setup_count
);
646 state
->io
.out
.setup_count
= setup_count
;
647 state
->io
.out
.setup
= talloc_array(state
, uint8_t,
648 setup_count
* VWV(1));
649 if (!state
->io
.out
.setup
) {
652 memcpy(state
->io
.out
.setup
, (uint8_t *)req
->out
.vwv
+ VWV(18),
653 setup_count
* VWV(1));
656 state
->got_first
= true;
659 if (total_data
> state
->io
.out
.data
.length
||
660 total_param
> state
->io
.out
.params
.length
) {
661 /* they must *only* shrink */
662 DEBUG(1,("smb_raw_nttrans_recv_helper: data/params expanded!\n"));
663 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
667 state
->io
.out
.data
.length
= total_data
;
668 state
->io
.out
.params
.length
= total_param
;
670 if (data_count
+ data_disp
> total_data
||
671 param_count
+ param_disp
> total_param
) {
672 DEBUG(1,("smb_raw_nttrans_recv_helper: Buffer overflow\n"));
673 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
677 /* check the server isn't being nasty */
678 if (raw_trans_oob(req
, param_ofs
, param_count
) ||
679 raw_trans_oob(req
, data_ofs
, data_count
)) {
680 DEBUG(1,("smb_raw_nttrans_recv_helper: out of bounds parameters!\n"));
681 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
686 memcpy(state
->io
.out
.data
.data
+ data_disp
,
687 req
->in
.hdr
+ data_ofs
,
692 memcpy(state
->io
.out
.params
.data
+ param_disp
,
693 req
->in
.hdr
+ param_ofs
,
697 state
->recvd_param
+= param_count
;
698 state
->recvd_data
+= data_count
;
700 if (state
->recvd_data
< total_data
||
701 state
->recvd_param
< total_param
) {
703 /* we don't need the in buffer any more */
704 talloc_free(req
->in
.buffer
);
705 ZERO_STRUCT(req
->in
);
707 /* we still wait for more data */
708 DEBUG(10,("smb_raw_nttrans_recv_helper: more data needed\n"));
709 return SMBCLI_REQUEST_RECV
;
712 DEBUG(10,("smb_raw_nttrans_recv_helper: done\n"));
713 return SMBCLI_REQUEST_DONE
;
716 req
->status
= NT_STATUS_NO_MEMORY
;
718 return SMBCLI_REQUEST_ERROR
;
721 /****************************************************************************
722 nttrans raw - only BLOBs used in this interface.
723 at the moment we only handle a single primary request
724 ****************************************************************************/
725 struct smbcli_request
*smb_raw_nttrans_send(struct smbcli_tree
*tree
,
726 struct smb_nttrans
*parms
)
728 struct smbcli_request
*req
;
729 struct smb_raw_nttrans_recv_state
*state
;
732 DATA_BLOB params_chunk
;
734 DATA_BLOB data_chunk
;
738 /* only align if there are parameters or data */
739 if (parms
->in
.params
.length
|| parms
->in
.data
.length
) {
743 req
= smbcli_request_setup(tree
, SMBnttrans
,
744 19 + parms
->in
.setup_count
, align
);
749 state
= talloc_zero(req
, struct smb_raw_nttrans_recv_state
);
755 /* fill in SMB parameters */
758 memset(req
->out
.data
, 0, align
);
761 ofs
= PTR_DIFF(req
->out
.data
,req
->out
.hdr
)+align
;
763 /* see how much bytes of the params block we can ship in the first request */
764 space_left
= raw_trans_space_left(req
);
766 params_chunk
.length
= MIN(parms
->in
.params
.length
, space_left
);
767 params_chunk
.data
= parms
->in
.params
.data
;
770 state
->params_left
= parms
->in
.params
.length
- params_chunk
.length
;
772 if (state
->params_left
> 0) {
773 /* we copy the whole params block, if needed we can optimize that latter */
774 state
->io
.in
.params
= data_blob_talloc(state
, NULL
, parms
->in
.params
.length
);
775 if (!state
->io
.in
.params
.data
) {
776 smbcli_request_destroy(req
);
779 memcpy(state
->io
.in
.params
.data
,
780 parms
->in
.params
.data
,
781 parms
->in
.params
.length
);
784 /* see how much bytes of the data block we can ship in the first request */
785 space_left
-= params_chunk
.length
;
787 #if TORTURE_TRANS_DATA
788 if (space_left
> 1) {
793 data_chunk
.length
= MIN(parms
->in
.data
.length
, space_left
);
794 data_chunk
.data
= parms
->in
.data
.data
;
795 data_ofs
= params_ofs
+ params_chunk
.length
;
797 state
->data_left
= parms
->in
.data
.length
- data_chunk
.length
;
799 if (state
->data_left
> 0) {
800 /* we copy the whole params block, if needed we can optimize that latter */
801 state
->io
.in
.data
= data_blob_talloc(state
, NULL
, parms
->in
.data
.length
);
802 if (!state
->io
.in
.data
.data
) {
803 smbcli_request_destroy(req
);
806 memcpy(state
->io
.in
.data
.data
,
808 parms
->in
.data
.length
);
811 state
->params_total
= parms
->in
.params
.length
;
812 state
->data_total
= parms
->in
.data
.length
;
814 SCVAL(req
->out
.vwv
, 0, parms
->in
.max_setup
);
815 SSVAL(req
->out
.vwv
, 1, 0); /* reserved */
816 SIVAL(req
->out
.vwv
, 3, parms
->in
.params
.length
);
817 SIVAL(req
->out
.vwv
, 7, parms
->in
.data
.length
);
818 SIVAL(req
->out
.vwv
, 11, parms
->in
.max_param
);
819 SIVAL(req
->out
.vwv
, 15, parms
->in
.max_data
);
820 SIVAL(req
->out
.vwv
, 19, params_chunk
.length
);
821 SIVAL(req
->out
.vwv
, 23, params_ofs
);
822 SIVAL(req
->out
.vwv
, 27, data_chunk
.length
);
823 SIVAL(req
->out
.vwv
, 31, data_ofs
);
824 SCVAL(req
->out
.vwv
, 35, parms
->in
.setup_count
);
825 SSVAL(req
->out
.vwv
, 36, parms
->in
.function
);
826 memcpy(req
->out
.vwv
+ VWV(19), parms
->in
.setup
,
827 sizeof(uint16_t) * parms
->in
.setup_count
);
829 smbcli_req_append_blob(req
, ¶ms_chunk
);
830 smbcli_req_append_blob(req
, &data_chunk
);
832 /* add the helper which will check that all multi-part replies are
833 in before an async client callack will be issued */
834 req
->recv_helper
.fn
= smb_raw_nttrans_recv_helper
;
835 req
->recv_helper
.private_data
= state
;
837 if (!smbcli_request_send(req
)) {
838 smbcli_request_destroy(req
);
845 static enum smbcli_request_state
smb_raw_nttrans_ship_next(struct smbcli_request
*req
,
846 struct smb_raw_nttrans_recv_state
*state
)
848 struct smbcli_request
*req2
;
850 DATA_BLOB params_chunk
;
852 uint32_t params_ofs
= 0;
853 uint32_t params_disp
= 0;
854 DATA_BLOB data_chunk
;
855 uint32_t data_ofs
= 0;
856 uint32_t data_disp
= 0;
858 req2
= smbcli_request_setup(req
->tree
, SMBnttranss
, 18, 0);
862 req2
->mid
= req
->mid
;
863 SSVAL(req2
->out
.hdr
, HDR_MID
, req2
->mid
);
865 ofs
= PTR_DIFF(req2
->out
.data
,req2
->out
.hdr
);
867 /* see how much bytes of the params block we can ship in the first request */
868 space_left
= raw_trans_space_left(req2
);
870 params_disp
= state
->io
.in
.params
.length
- state
->params_left
;
871 params_chunk
.length
= MIN(state
->params_left
, space_left
);
872 params_chunk
.data
= state
->io
.in
.params
.data
+ params_disp
;
875 state
->params_left
-= params_chunk
.length
;
877 /* see how much bytes of the data block we can ship in the first request */
878 space_left
-= params_chunk
.length
;
880 #if TORTURE_TRANS_DATA
881 if (space_left
> 1) {
886 data_disp
= state
->io
.in
.data
.length
- state
->data_left
;
887 data_chunk
.length
= MIN(state
->data_left
, space_left
);
888 data_chunk
.data
= state
->io
.in
.data
.data
+ data_disp
;
889 data_ofs
= params_ofs
+params_chunk
.length
;
891 state
->data_left
-= data_chunk
.length
;
893 SSVAL(req2
->out
.vwv
,0, 0); /* reserved */
894 SCVAL(req2
->out
.vwv
,2, 0); /* reserved */
895 SIVAL(req2
->out
.vwv
,3, state
->params_total
);
896 SIVAL(req2
->out
.vwv
,7, state
->data_total
);
897 SIVAL(req2
->out
.vwv
,11, params_chunk
.length
);
898 SIVAL(req2
->out
.vwv
,15, params_ofs
);
899 SIVAL(req2
->out
.vwv
,19, params_disp
);
900 SIVAL(req2
->out
.vwv
,23, data_chunk
.length
);
901 SIVAL(req2
->out
.vwv
,27, data_ofs
);
902 SIVAL(req2
->out
.vwv
,31, data_disp
);
903 SCVAL(req2
->out
.vwv
,35, 0); /* reserved */
905 smbcli_req_append_blob(req2
, ¶ms_chunk
);
906 smbcli_req_append_blob(req2
, &data_chunk
);
909 * it's a one way request but we need
910 * the seq_num, so we destroy req2 by hand
912 if (!smbcli_request_send(req2
)) {
916 req
->seq_num
= req2
->seq_num
;
917 smbcli_request_destroy(req2
);
919 return SMBCLI_REQUEST_RECV
;
922 req
->status
= NT_STATUS_NO_MEMORY
;
925 req
->status
= smbcli_request_destroy(req2
);
927 return SMBCLI_REQUEST_ERROR
;
930 static enum smbcli_request_state
smb_raw_nttrans_ship_rest(struct smbcli_request
*req
,
931 struct smb_raw_nttrans_recv_state
*state
)
933 enum smbcli_request_state ret
= SMBCLI_REQUEST_ERROR
;
935 while (state
->params_left
> 0 || state
->data_left
> 0) {
936 ret
= smb_raw_nttrans_ship_next(req
, state
);
937 if (ret
!= SMBCLI_REQUEST_RECV
) {
946 /****************************************************************************
947 receive a SMB nttrans response allocating the necessary memory
948 ****************************************************************************/
949 NTSTATUS
smb_raw_nttrans(struct smbcli_tree
*tree
,
951 struct smb_nttrans
*parms
)
953 struct smbcli_request
*req
;
955 req
= smb_raw_nttrans_send(tree
, parms
);
957 return NT_STATUS_UNSUCCESSFUL
;
960 return smb_raw_nttrans_recv(req
, mem_ctx
, parms
);