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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include "dlinklist.h"
24 #include "libcli/raw/libcliraw.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 (ptr
< req
->in
.data
||
44 ptr
>= req
->in
.data
+ req
->in
.data_size
||
45 count
> req
->in
.data_size
||
46 ptr
+ count
> req
->in
.data
+ req
->in
.data_size
) {
52 /****************************************************************************
53 receive a SMB trans or trans2 response allocating the necessary memory
54 ****************************************************************************/
55 NTSTATUS
smb_raw_trans2_recv(struct smbcli_request
*req
,
57 struct smb_trans2
*parms
)
64 parms
->out
.data
.length
= 0;
65 parms
->out
.data
.data
= NULL
;
66 parms
->out
.params
.length
= 0;
67 parms
->out
.params
.data
= NULL
;
69 if (!smbcli_request_receive(req
)) {
70 return smbcli_request_destroy(req
);
74 * An NT RPC pipe call can return ERRDOS, ERRmoredata
75 * to a trans call. This is not an error and should not
78 if (NT_STATUS_IS_ERR(req
->status
)) {
79 return smbcli_request_destroy(req
);
82 SMBCLI_CHECK_MIN_WCT(req
, 10);
84 /* parse out the lengths */
85 total_data
= SVAL(req
->in
.vwv
, VWV(1));
86 total_param
= SVAL(req
->in
.vwv
, VWV(0));
89 if (total_data
!= 0) {
90 tdata
= talloc_size(mem_ctx
, total_data
);
92 DEBUG(0,("smb_raw_receive_trans: failed to enlarge data buffer to %d bytes\n", total_data
));
93 req
->status
= NT_STATUS_NO_MEMORY
;
94 return smbcli_request_destroy(req
);
96 parms
->out
.data
.data
= tdata
;
99 if (total_param
!= 0) {
100 tparam
= talloc_size(mem_ctx
, total_param
);
102 DEBUG(0,("smb_raw_receive_trans: failed to enlarge param buffer to %d bytes\n", total_param
));
103 req
->status
= NT_STATUS_NO_MEMORY
;
104 return smbcli_request_destroy(req
);
106 parms
->out
.params
.data
= tparam
;
109 parms
->out
.setup_count
= SVAL(req
->in
.vwv
, VWV(9));
110 SMBCLI_CHECK_WCT(req
, 10 + parms
->out
.setup_count
);
112 if (parms
->out
.setup_count
> 0) {
114 parms
->out
.setup
= talloc_array(mem_ctx
, uint16_t, parms
->out
.setup_count
);
115 if (!parms
->out
.setup
) {
116 req
->status
= NT_STATUS_NO_MEMORY
;
117 return smbcli_request_destroy(req
);
119 for (i
=0;i
<parms
->out
.setup_count
;i
++) {
120 parms
->out
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(10+i
));
125 uint16_t param_count
, param_ofs
, param_disp
;
126 uint16_t data_count
, data_ofs
, data_disp
;
127 uint16_t total_data2
, total_param2
;
129 /* parse out the total lengths again - they can shrink! */
130 total_data2
= SVAL(req
->in
.vwv
, VWV(1));
131 total_param2
= SVAL(req
->in
.vwv
, VWV(0));
133 if (total_data2
> total_data
||
134 total_param2
> total_param
) {
135 /* they must *only* shrink */
136 DEBUG(1,("smb_raw_receive_trans: data/params expanded!\n"));
137 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
138 return smbcli_request_destroy(req
);
141 total_data
= total_data2
;
142 total_param
= total_param2
;
144 /* parse params for this lump */
145 param_count
= SVAL(req
->in
.vwv
, VWV(3));
146 param_ofs
= SVAL(req
->in
.vwv
, VWV(4));
147 param_disp
= SVAL(req
->in
.vwv
, VWV(5));
149 data_count
= SVAL(req
->in
.vwv
, VWV(6));
150 data_ofs
= SVAL(req
->in
.vwv
, VWV(7));
151 data_disp
= SVAL(req
->in
.vwv
, VWV(8));
153 if (data_count
+ data_disp
> total_data
||
154 param_count
+ param_disp
> total_param
) {
155 DEBUG(1,("smb_raw_receive_trans: Buffer overflow\n"));
156 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
157 return smbcli_request_destroy(req
);
160 /* check the server isn't being nasty */
161 if (raw_trans_oob(req
, param_ofs
, param_count
) ||
162 raw_trans_oob(req
, data_ofs
, data_count
)) {
163 DEBUG(1,("smb_raw_receive_trans: out of bounds parameters!\n"));
164 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
165 return smbcli_request_destroy(req
);
169 memcpy(parms
->out
.data
.data
+ data_disp
,
170 req
->in
.hdr
+ data_ofs
,
175 memcpy(parms
->out
.params
.data
+ param_disp
,
176 req
->in
.hdr
+ param_ofs
,
180 parms
->out
.data
.length
+= data_count
;
181 parms
->out
.params
.length
+= param_count
;
183 if (total_data
<= parms
->out
.data
.length
&& total_param
<= parms
->out
.params
.length
)
186 if (!smbcli_request_receive_more(req
)) {
187 req
->status
= NT_STATUS_UNSUCCESSFUL
;
188 return smbcli_request_destroy(req
);
193 return smbcli_request_destroy(req
);
196 NTSTATUS
smb_raw_trans_recv(struct smbcli_request
*req
,
198 struct smb_trans2
*parms
)
200 return smb_raw_trans2_recv(req
, mem_ctx
, parms
);
205 trans/trans2 raw async interface - only BLOBs used in this interface.
207 struct smbcli_request
*smb_raw_trans_send_backend(struct smbcli_tree
*tree
,
208 struct smb_trans2
*parms
,
211 int wct
= 14 + parms
->in
.setup_count
;
212 struct smbcli_request
*req
, *req2
;
213 uint8_t *outdata
,*outparam
;
217 uint16_t data_disp
, data_length
, max_data
;
219 if (command
== SMBtrans
)
224 req
= smbcli_request_setup(tree
, command
, wct
, padding
);
229 /* Watch out, this changes the req->out.* pointers */
230 if (command
== SMBtrans
&& parms
->in
.trans_name
) {
231 namelen
= smbcli_req_append_string(req
, parms
->in
.trans_name
,
235 /* fill in SMB parameters */
236 outparam
= req
->out
.data
+ padding
;
237 outdata
= outparam
+ parms
->in
.params
.length
;
239 /* make sure we don't leak data via the padding */
240 memset(req
->out
.data
, 0, padding
);
242 data_length
= parms
->in
.data
.length
;
244 max_data
= smb_raw_max_trans_data(tree
, parms
->in
.params
.length
);
245 if (max_data
< data_length
) {
246 data_length
= max_data
;
249 #if TORTURE_TRANS_DATA
250 if (data_length
> 1) {
255 /* primary request */
256 SSVAL(req
->out
.vwv
,VWV(0),parms
->in
.params
.length
);
257 SSVAL(req
->out
.vwv
,VWV(1),parms
->in
.data
.length
);
258 SSVAL(req
->out
.vwv
,VWV(2),parms
->in
.max_param
);
259 SSVAL(req
->out
.vwv
,VWV(3),parms
->in
.max_data
);
260 SSVAL(req
->out
.vwv
,VWV(4),parms
->in
.max_setup
);
261 SSVAL(req
->out
.vwv
,VWV(5),parms
->in
.flags
);
262 SIVAL(req
->out
.vwv
,VWV(6),parms
->in
.timeout
);
263 SSVAL(req
->out
.vwv
,VWV(8),0); /* reserved */
264 SSVAL(req
->out
.vwv
,VWV(9),parms
->in
.params
.length
);
265 SSVAL(req
->out
.vwv
,VWV(10),PTR_DIFF(outparam
,req
->out
.hdr
)+namelen
);
266 SSVAL(req
->out
.vwv
,VWV(11),data_length
);
267 SSVAL(req
->out
.vwv
,VWV(12),PTR_DIFF(outdata
,req
->out
.hdr
)+namelen
);
268 SSVAL(req
->out
.vwv
,VWV(13),parms
->in
.setup_count
);
269 for (i
=0;i
<parms
->in
.setup_count
;i
++) {
270 SSVAL(req
->out
.vwv
,VWV(14)+i
*2,parms
->in
.setup
[i
]);
272 if (parms
->in
.params
.data
) {
273 smbcli_req_append_blob(req
, &parms
->in
.params
);
275 if (parms
->in
.data
.data
) {
277 data
.data
= parms
->in
.data
.data
;
278 data
.length
= data_length
;
279 smbcli_req_append_blob(req
, &data
);
282 if (!smbcli_request_send(req
)) {
283 smbcli_request_destroy(req
);
287 data_disp
= data_length
;
290 if (data_disp
!= parms
->in
.data
.length
) {
291 /* TODO: this should be done asynchronously .... */
292 if (!smbcli_request_receive(req
) ||
293 !NT_STATUS_IS_OK(req
->status
)) {
297 req
->state
= SMBCLI_REQUEST_RECV
;
298 DLIST_ADD(req
->transport
->pending_recv
, req
);
302 while (data_disp
!= parms
->in
.data
.length
) {
303 data_length
= parms
->in
.data
.length
- data_disp
;
305 max_data
= smb_raw_max_trans_data(tree
, 0);
306 if (max_data
< data_length
) {
307 data_length
= max_data
;
310 #if TORTURE_TRANS_DATA
311 if (data_length
> 1) {
316 req2
= smbcli_request_setup(tree
, command
+1, 9, data_length
);
320 req2
->mid
= req
->mid
;
321 SSVAL(req2
->out
.hdr
, HDR_MID
, req2
->mid
);
323 outdata
= req2
->out
.data
;
325 SSVAL(req2
->out
.vwv
,VWV(0), parms
->in
.params
.length
);
326 SSVAL(req2
->out
.vwv
,VWV(1), parms
->in
.data
.length
);
327 SSVAL(req2
->out
.vwv
,VWV(2), 0);
328 SSVAL(req2
->out
.vwv
,VWV(3), 0);
329 SSVAL(req2
->out
.vwv
,VWV(4), 0);
330 SSVAL(req2
->out
.vwv
,VWV(5), data_length
);
331 SSVAL(req2
->out
.vwv
,VWV(6), PTR_DIFF(outdata
,req2
->out
.hdr
));
332 SSVAL(req2
->out
.vwv
,VWV(7), data_disp
);
333 SSVAL(req2
->out
.vwv
,VWV(8), 0xFFFF);
335 memcpy(req2
->out
.data
, parms
->in
.data
.data
+ data_disp
, data_length
);
337 data_disp
+= data_length
;
339 req2
->one_way_request
= 1;
341 if (!smbcli_request_send(req2
)) {
342 smbcli_request_destroy(req2
);
346 req
->seq_num
= req2
->seq_num
;
355 trans/trans2 raw async interface - only BLOBs used in this interface.
356 note that this doesn't yet support multi-part requests
358 struct smbcli_request
*smb_raw_trans_send(struct smbcli_tree
*tree
,
359 struct smb_trans2
*parms
)
361 return smb_raw_trans_send_backend(tree
, parms
, SMBtrans
);
364 struct smbcli_request
*smb_raw_trans2_send(struct smbcli_tree
*tree
,
365 struct smb_trans2
*parms
)
367 return smb_raw_trans_send_backend(tree
, parms
, SMBtrans2
);
371 trans2 synchronous blob interface
373 NTSTATUS
smb_raw_trans2(struct smbcli_tree
*tree
,
375 struct smb_trans2
*parms
)
377 struct smbcli_request
*req
;
378 req
= smb_raw_trans2_send(tree
, parms
);
379 if (!req
) return NT_STATUS_UNSUCCESSFUL
;
380 return smb_raw_trans2_recv(req
, mem_ctx
, parms
);
385 trans synchronous blob interface
387 NTSTATUS
smb_raw_trans(struct smbcli_tree
*tree
,
389 struct smb_trans2
*parms
)
391 struct smbcli_request
*req
;
392 req
= smb_raw_trans_send(tree
, parms
);
393 if (!req
) return NT_STATUS_UNSUCCESSFUL
;
394 return smb_raw_trans_recv(req
, mem_ctx
, parms
);
398 /****************************************************************************
399 receive a SMB nttrans response allocating the necessary memory
400 ****************************************************************************/
401 NTSTATUS
smb_raw_nttrans_recv(struct smbcli_request
*req
,
403 struct smb_nttrans
*parms
)
405 uint32_t total_data
, recvd_data
=0;
406 uint32_t total_param
, recvd_param
=0;
408 if (!smbcli_request_receive(req
) ||
409 smbcli_request_is_error(req
)) {
410 return smbcli_request_destroy(req
);
414 if (CVAL(req
->in
.hdr
, HDR_COM
) != SMBnttrans
) {
415 DEBUG(0,("smb_raw_receive_nttrans: Expected %s response, got command 0x%02x\n",
417 CVAL(req
->in
.hdr
,HDR_COM
)));
418 req
->status
= NT_STATUS_UNSUCCESSFUL
;
419 return smbcli_request_destroy(req
);
422 SMBCLI_CHECK_MIN_WCT(req
, 18);
424 /* parse out the lengths */
425 total_param
= IVAL(req
->in
.vwv
, 3);
426 total_data
= IVAL(req
->in
.vwv
, 7);
428 parms
->out
.data
= data_blob_talloc(mem_ctx
, NULL
, total_data
);
429 parms
->out
.params
= data_blob_talloc(mem_ctx
, NULL
, total_param
);
431 if (parms
->out
.data
.length
!= total_data
||
432 parms
->out
.params
.length
!= total_param
) {
433 req
->status
= NT_STATUS_NO_MEMORY
;
434 return smbcli_request_destroy(req
);
437 parms
->out
.setup_count
= CVAL(req
->in
.vwv
, 35);
438 SMBCLI_CHECK_WCT(req
, 18 + parms
->out
.setup_count
);
440 if (parms
->out
.setup_count
> 0) {
442 parms
->out
.setup
= talloc_array(mem_ctx
, uint16_t, parms
->out
.setup_count
);
443 if (!parms
->out
.setup
) {
444 req
->status
= NT_STATUS_NO_MEMORY
;
445 return smbcli_request_destroy(req
);
447 for (i
=0;i
<parms
->out
.setup_count
;i
++) {
448 parms
->out
.setup
[i
] = SVAL(req
->in
.vwv
, VWV(18+i
));
452 while (recvd_data
< total_data
||
453 recvd_param
< total_param
) {
454 uint32_t param_count
, param_ofs
, param_disp
;
455 uint32_t data_count
, data_ofs
, data_disp
;
456 uint32_t total_data2
, total_param2
;
458 /* parse out the total lengths again - they can shrink! */
459 total_param2
= IVAL(req
->in
.vwv
, 3);
460 total_data2
= IVAL(req
->in
.vwv
, 7);
462 if (total_data2
> total_data
||
463 total_param2
> total_param
) {
464 /* they must *only* shrink */
465 DEBUG(1,("smb_raw_receive_nttrans: data/params expanded!\n"));
466 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
467 return smbcli_request_destroy(req
);
470 total_data
= total_data2
;
471 total_param
= total_param2
;
472 parms
->out
.data
.length
= total_data
;
473 parms
->out
.params
.length
= total_param
;
475 /* parse params for this lump */
476 param_count
= IVAL(req
->in
.vwv
, 11);
477 param_ofs
= IVAL(req
->in
.vwv
, 15);
478 param_disp
= IVAL(req
->in
.vwv
, 19);
480 data_count
= IVAL(req
->in
.vwv
, 23);
481 data_ofs
= IVAL(req
->in
.vwv
, 27);
482 data_disp
= IVAL(req
->in
.vwv
, 31);
484 if (data_count
+ data_disp
> total_data
||
485 param_count
+ param_disp
> total_param
) {
486 DEBUG(1,("smb_raw_receive_nttrans: Buffer overflow\n"));
487 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
488 return smbcli_request_destroy(req
);
491 /* check the server isn't being nasty */
492 if (raw_trans_oob(req
, param_ofs
, param_count
) ||
493 raw_trans_oob(req
, data_ofs
, data_count
)) {
494 DEBUG(1,("smb_raw_receive_nttrans: out of bounds parameters!\n"));
495 req
->status
= NT_STATUS_BUFFER_TOO_SMALL
;
496 return smbcli_request_destroy(req
);
500 memcpy(parms
->out
.data
.data
+ data_disp
,
501 req
->in
.hdr
+ data_ofs
,
506 memcpy(parms
->out
.params
.data
+ param_disp
,
507 req
->in
.hdr
+ param_ofs
,
511 recvd_param
+= param_count
;
512 recvd_data
+= data_count
;
514 if (recvd_data
>= total_data
&&
515 recvd_param
>= total_param
) {
519 if (!smbcli_request_receive(req
) ||
520 smbcli_request_is_error(req
)) {
521 return smbcli_request_destroy(req
);
525 if (CVAL(req
->in
.hdr
, HDR_COM
) != SMBnttrans
) {
526 DEBUG(0,("smb_raw_receive_nttrans: Expected nttranss, got command 0x%02x\n",
527 CVAL(req
->in
.hdr
, HDR_COM
)));
528 req
->status
= NT_STATUS_UNSUCCESSFUL
;
529 return smbcli_request_destroy(req
);
534 return smbcli_request_destroy(req
);
538 /****************************************************************************
539 nttrans raw - only BLOBs used in this interface.
540 at the moment we only handle a single primary request
541 ****************************************************************************/
542 struct smbcli_request
*smb_raw_nttrans_send(struct smbcli_tree
*tree
,
543 struct smb_nttrans
*parms
)
545 struct smbcli_request
*req
;
546 uint8_t *outdata
, *outparam
;
550 /* only align if there are parameters or data */
551 if (parms
->in
.params
.length
|| parms
->in
.data
.length
) {
555 req
= smbcli_request_setup(tree
, SMBnttrans
,
556 19 + parms
->in
.setup_count
,
558 parms
->in
.params
.length
+
559 parms
->in
.data
.length
);
564 /* fill in SMB parameters */
565 outparam
= req
->out
.data
+ align
;
566 outdata
= outparam
+ parms
->in
.params
.length
;
569 memset(req
->out
.data
, 0, align
);
572 SCVAL(req
->out
.vwv
, 0, parms
->in
.max_setup
);
573 SSVAL(req
->out
.vwv
, 1, 0); /* reserved */
574 SIVAL(req
->out
.vwv
, 3, parms
->in
.params
.length
);
575 SIVAL(req
->out
.vwv
, 7, parms
->in
.data
.length
);
576 SIVAL(req
->out
.vwv
, 11, parms
->in
.max_param
);
577 SIVAL(req
->out
.vwv
, 15, parms
->in
.max_data
);
578 SIVAL(req
->out
.vwv
, 19, parms
->in
.params
.length
);
579 SIVAL(req
->out
.vwv
, 23, PTR_DIFF(outparam
,req
->out
.hdr
));
580 SIVAL(req
->out
.vwv
, 27, parms
->in
.data
.length
);
581 SIVAL(req
->out
.vwv
, 31, PTR_DIFF(outdata
,req
->out
.hdr
));
582 SCVAL(req
->out
.vwv
, 35, parms
->in
.setup_count
);
583 SSVAL(req
->out
.vwv
, 36, parms
->in
.function
);
584 for (i
=0;i
<parms
->in
.setup_count
;i
++) {
585 SSVAL(req
->out
.vwv
,VWV(19+i
),parms
->in
.setup
[i
]);
587 if (parms
->in
.params
.length
) {
588 memcpy(outparam
, parms
->in
.params
.data
, parms
->in
.params
.length
);
590 if (parms
->in
.data
.length
) {
591 memcpy(outdata
, parms
->in
.data
.data
, parms
->in
.data
.length
);
594 if (!smbcli_request_send(req
)) {
595 smbcli_request_destroy(req
);
603 /****************************************************************************
604 receive a SMB nttrans response allocating the necessary memory
605 ****************************************************************************/
606 NTSTATUS
smb_raw_nttrans(struct smbcli_tree
*tree
,
608 struct smb_nttrans
*parms
)
610 struct smbcli_request
*req
;
612 req
= smb_raw_nttrans_send(tree
, parms
);
614 return NT_STATUS_UNSUCCESSFUL
;
617 return smb_raw_nttrans_recv(req
, mem_ctx
, parms
);
621 work out the maximum data size for a trans request while avoiding
624 TODO: we only need to avoid multi-part replies because the
625 multi-part trans receive code is broken.
627 size_t smb_raw_max_trans_data(struct smbcli_tree
*tree
, size_t param_size
)
629 return tree
->session
->transport
->negotiate
.max_xmit
- (70 + param_size
);