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 "async_smb.h"
23 /****************************************************************************
24 Send a SMB trans or trans2 request.
25 ****************************************************************************/
27 bool cli_send_trans(struct cli_state
*cli
, int trans
,
28 const char *pipe_name
,
30 uint16
*setup
, unsigned int lsetup
, unsigned int msetup
,
31 const char *param
, unsigned int lparam
, unsigned int mparam
,
32 const char *data
, unsigned int ldata
, unsigned int mdata
)
35 unsigned int this_ldata
,this_lparam
;
36 unsigned int tot_data
=0,tot_param
=0;
37 char *outdata
,*outparam
;
42 this_lparam
= MIN(lparam
,cli
->max_xmit
- (500+lsetup
*2)); /* hack */
43 this_ldata
= MIN(ldata
,cli
->max_xmit
- (500+lsetup
*2+this_lparam
));
45 memset(cli
->outbuf
,'\0',smb_size
);
46 cli_set_message(cli
->outbuf
,14+lsetup
,0,True
);
47 SCVAL(cli
->outbuf
,smb_com
,trans
);
48 SSVAL(cli
->outbuf
,smb_tid
, cli
->cnum
);
49 cli_setup_packet(cli
);
52 * Save the mid we're using. We need this for finding
59 pipe_name_len
= clistr_push(cli
, smb_buf(cli
->outbuf
), pipe_name
, -1, STR_TERMINATE
);
62 outparam
= smb_buf(cli
->outbuf
)+(trans
==SMBtrans
? pipe_name_len
: 3);
63 outdata
= outparam
+this_lparam
;
66 SSVAL(cli
->outbuf
,smb_tpscnt
,lparam
); /* tpscnt */
67 SSVAL(cli
->outbuf
,smb_tdscnt
,ldata
); /* tdscnt */
68 SSVAL(cli
->outbuf
,smb_mprcnt
,mparam
); /* mprcnt */
69 SSVAL(cli
->outbuf
,smb_mdrcnt
,mdata
); /* mdrcnt */
70 SCVAL(cli
->outbuf
,smb_msrcnt
,msetup
); /* msrcnt */
71 SSVAL(cli
->outbuf
,smb_flags
,flags
); /* flags */
72 SIVAL(cli
->outbuf
,smb_timeout
,0); /* timeout */
73 SSVAL(cli
->outbuf
,smb_pscnt
,this_lparam
); /* pscnt */
74 SSVAL(cli
->outbuf
,smb_psoff
,smb_offset(outparam
,cli
->outbuf
)); /* psoff */
75 SSVAL(cli
->outbuf
,smb_dscnt
,this_ldata
); /* dscnt */
76 SSVAL(cli
->outbuf
,smb_dsoff
,smb_offset(outdata
,cli
->outbuf
)); /* dsoff */
77 SCVAL(cli
->outbuf
,smb_suwcnt
,lsetup
); /* suwcnt */
78 for (i
=0;i
<lsetup
;i
++) /* setup[] */
79 SSVAL(cli
->outbuf
,smb_setup
+i
*2,setup
[i
]);
80 p
= smb_buf(cli
->outbuf
);
81 if (trans
!= SMBtrans
) {
82 *p
++ = 0; /* put in a null smb_name */
83 *p
++ = 'D'; *p
++ = ' '; /* observed in OS/2 */
85 if (this_lparam
) /* param[] */
86 memcpy(outparam
,param
,this_lparam
);
87 if (this_ldata
) /* data[] */
88 memcpy(outdata
,data
,this_ldata
);
89 cli_setup_bcc(cli
, outdata
+this_ldata
);
91 show_msg(cli
->outbuf
);
93 if (!cli_send_smb(cli
)) {
97 cli_state_seqnum_persistent(cli
, mid
);
99 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
100 /* receive interim response */
101 if (!cli_receive_smb(cli
) || cli_is_error(cli
)) {
102 cli_state_seqnum_remove(cli
, mid
);
106 tot_data
= this_ldata
;
107 tot_param
= this_lparam
;
109 while (tot_data
< ldata
|| tot_param
< lparam
) {
110 this_lparam
= MIN(lparam
-tot_param
,cli
->max_xmit
- 500); /* hack */
111 this_ldata
= MIN(ldata
-tot_data
,cli
->max_xmit
- (500+this_lparam
));
113 cli_set_message(cli
->outbuf
,trans
==SMBtrans
?8:9,0,True
);
114 SCVAL(cli
->outbuf
,smb_com
,(trans
==SMBtrans
? SMBtranss
: SMBtranss2
));
116 outparam
= smb_buf(cli
->outbuf
);
117 outdata
= outparam
+this_lparam
;
119 /* secondary request */
120 SSVAL(cli
->outbuf
,smb_tpscnt
,lparam
); /* tpscnt */
121 SSVAL(cli
->outbuf
,smb_tdscnt
,ldata
); /* tdscnt */
122 SSVAL(cli
->outbuf
,smb_spscnt
,this_lparam
); /* pscnt */
123 SSVAL(cli
->outbuf
,smb_spsoff
,smb_offset(outparam
,cli
->outbuf
)); /* psoff */
124 SSVAL(cli
->outbuf
,smb_spsdisp
,tot_param
); /* psdisp */
125 SSVAL(cli
->outbuf
,smb_sdscnt
,this_ldata
); /* dscnt */
126 SSVAL(cli
->outbuf
,smb_sdsoff
,smb_offset(outdata
,cli
->outbuf
)); /* dsoff */
127 SSVAL(cli
->outbuf
,smb_sdsdisp
,tot_data
); /* dsdisp */
128 if (trans
==SMBtrans2
)
129 SSVALS(cli
->outbuf
,smb_sfid
,fid
); /* fid */
130 if (this_lparam
) /* param[] */
131 memcpy(outparam
,param
+tot_param
,this_lparam
);
132 if (this_ldata
) /* data[] */
133 memcpy(outdata
,data
+tot_data
,this_ldata
);
134 cli_setup_bcc(cli
, outdata
+this_ldata
);
136 show_msg(cli
->outbuf
);
139 if (!cli_send_smb(cli
)) {
140 cli_state_seqnum_remove(cli
, mid
);
144 tot_data
+= this_ldata
;
145 tot_param
+= this_lparam
;
152 /****************************************************************************
153 Receive a SMB trans or trans2 response allocating the necessary memory.
154 ****************************************************************************/
156 bool cli_receive_trans(struct cli_state
*cli
,int trans
,
157 char **param
, unsigned int *param_len
,
158 char **data
, unsigned int *data_len
)
160 unsigned int total_data
=0;
161 unsigned int total_param
=0;
162 unsigned int this_data
,this_param
;
167 *data_len
= *param_len
= 0;
169 mid
= SVAL(cli
->outbuf
,smb_mid
);
171 if (!cli_receive_smb(cli
)) {
172 cli_state_seqnum_remove(cli
, mid
);
176 show_msg(cli
->inbuf
);
179 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
180 DEBUG(0,("Expected %s response, got command 0x%02x\n",
181 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
182 CVAL(cli
->inbuf
,smb_com
)));
183 cli_state_seqnum_remove(cli
, mid
);
188 * An NT RPC pipe call can return ERRDOS, ERRmoredata
189 * to a trans call. This is not an error and should not
190 * be treated as such. Note that STATUS_NO_MORE_FILES is
191 * returned when a trans2 findfirst/next finishes.
192 * When setting up an encrypted transport we can also
193 * see NT_STATUS_MORE_PROCESSING_REQUIRED here.
195 * Vista returns NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT if the folder
196 * "<share>/Users/All Users" is enumerated. This is a special pseudo
197 * folder, and the response does not have parameters (nor a parameter
200 status
= cli_nt_error(cli
);
202 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
203 if (NT_STATUS_IS_ERR(status
) ||
204 NT_STATUS_EQUAL(status
,STATUS_NO_MORE_FILES
) ||
205 NT_STATUS_EQUAL(status
,NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT
)) {
210 /* parse out the lengths */
211 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
212 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
216 /* We know adding 2 is safe as total_data is an
218 *data
= (char *)SMB_REALLOC(*data
,total_data
+2);
220 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
225 if (total_param
!=0) {
226 /* We know adding 2 is safe as total_param is an
228 *param
= (char *)SMB_REALLOC(*param
,total_param
+2);
230 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
236 this_data
= SVAL(cli
->inbuf
,smb_drcnt
);
237 this_param
= SVAL(cli
->inbuf
,smb_prcnt
);
239 if (this_data
+ *data_len
> total_data
||
240 this_param
+ *param_len
> total_param
) {
241 DEBUG(1,("Data overflow in cli_receive_trans\n"));
245 if (this_data
+ *data_len
< this_data
||
246 this_data
+ *data_len
< *data_len
||
247 this_param
+ *param_len
< this_param
||
248 this_param
+ *param_len
< *param_len
) {
249 DEBUG(1,("Data overflow in cli_receive_trans\n"));
254 unsigned int data_offset_out
= SVAL(cli
->inbuf
,smb_drdisp
);
255 unsigned int data_offset_in
= SVAL(cli
->inbuf
,smb_droff
);
257 if (data_offset_out
> total_data
||
258 data_offset_out
+ this_data
> total_data
||
259 data_offset_out
+ this_data
< data_offset_out
||
260 data_offset_out
+ this_data
< this_data
) {
261 DEBUG(1,("Data overflow in cli_receive_trans\n"));
264 if (data_offset_in
> cli
->bufsize
||
265 data_offset_in
+ this_data
> cli
->bufsize
||
266 data_offset_in
+ this_data
< data_offset_in
||
267 data_offset_in
+ this_data
< this_data
) {
268 DEBUG(1,("Data overflow in cli_receive_trans\n"));
272 memcpy(*data
+ data_offset_out
, smb_base(cli
->inbuf
) + data_offset_in
, this_data
);
275 unsigned int param_offset_out
= SVAL(cli
->inbuf
,smb_prdisp
);
276 unsigned int param_offset_in
= SVAL(cli
->inbuf
,smb_proff
);
278 if (param_offset_out
> total_param
||
279 param_offset_out
+ this_param
> total_param
||
280 param_offset_out
+ this_param
< param_offset_out
||
281 param_offset_out
+ this_param
< this_param
) {
282 DEBUG(1,("Param overflow in cli_receive_trans\n"));
285 if (param_offset_in
> cli
->bufsize
||
286 param_offset_in
+ this_param
> cli
->bufsize
||
287 param_offset_in
+ this_param
< param_offset_in
||
288 param_offset_in
+ this_param
< this_param
) {
289 DEBUG(1,("Param overflow in cli_receive_trans\n"));
293 memcpy(*param
+ param_offset_out
, smb_base(cli
->inbuf
) + param_offset_in
, this_param
);
295 *data_len
+= this_data
;
296 *param_len
+= this_param
;
298 if (total_data
<= *data_len
&& total_param
<= *param_len
) {
303 if (!cli_receive_smb(cli
)) {
307 show_msg(cli
->inbuf
);
310 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
311 DEBUG(0,("Expected %s response, got command 0x%02x\n",
312 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
313 CVAL(cli
->inbuf
,smb_com
)));
316 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
317 if (NT_STATUS_IS_ERR(cli_nt_error(cli
))) {
322 /* parse out the total lengths again - they can shrink! */
323 if (SVAL(cli
->inbuf
,smb_tdrcnt
) < total_data
)
324 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
325 if (SVAL(cli
->inbuf
,smb_tprcnt
) < total_param
)
326 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
328 if (total_data
<= *data_len
&& total_param
<= *param_len
) {
336 cli_state_seqnum_remove(cli
, mid
);
339 /* Ensure the last 2 bytes of param and data are 2 null
340 * bytes. These are malloc'ed, but not included in any
341 * length counts. This allows cli_XX string reading functions
342 * to safely null terminate. */
344 SSVAL(*data
,total_data
,0);
347 SSVAL(*param
,total_param
,0);
354 /****************************************************************************
355 Send a SMB nttrans request.
356 ****************************************************************************/
358 bool cli_send_nt_trans(struct cli_state
*cli
,
361 uint16
*setup
, unsigned int lsetup
, unsigned int msetup
,
362 char *param
, unsigned int lparam
, unsigned int mparam
,
363 char *data
, unsigned int ldata
, unsigned int mdata
)
366 unsigned int this_ldata
,this_lparam
;
367 unsigned int tot_data
=0,tot_param
=0;
369 char *outdata
,*outparam
;
371 this_lparam
= MIN(lparam
,cli
->max_xmit
- (500+lsetup
*2)); /* hack */
372 this_ldata
= MIN(ldata
,cli
->max_xmit
- (500+lsetup
*2+this_lparam
));
374 memset(cli
->outbuf
,'\0',smb_size
);
375 cli_set_message(cli
->outbuf
,19+lsetup
,0,True
);
376 SCVAL(cli
->outbuf
,smb_com
,SMBnttrans
);
377 SSVAL(cli
->outbuf
,smb_tid
, cli
->cnum
);
378 cli_setup_packet(cli
);
381 * Save the mid we're using. We need this for finding
387 outparam
= smb_buf(cli
->outbuf
)+3;
388 outdata
= outparam
+this_lparam
;
390 /* primary request */
391 SCVAL(cli
->outbuf
,smb_nt_MaxSetupCount
,msetup
);
392 SCVAL(cli
->outbuf
,smb_nt_Flags
,flags
);
393 SIVAL(cli
->outbuf
,smb_nt_TotalParameterCount
, lparam
);
394 SIVAL(cli
->outbuf
,smb_nt_TotalDataCount
, ldata
);
395 SIVAL(cli
->outbuf
,smb_nt_MaxParameterCount
, mparam
);
396 SIVAL(cli
->outbuf
,smb_nt_MaxDataCount
, mdata
);
397 SIVAL(cli
->outbuf
,smb_nt_ParameterCount
, this_lparam
);
398 SIVAL(cli
->outbuf
,smb_nt_ParameterOffset
, smb_offset(outparam
,cli
->outbuf
));
399 SIVAL(cli
->outbuf
,smb_nt_DataCount
, this_ldata
);
400 SIVAL(cli
->outbuf
,smb_nt_DataOffset
, smb_offset(outdata
,cli
->outbuf
));
401 SIVAL(cli
->outbuf
,smb_nt_SetupCount
, lsetup
);
402 SIVAL(cli
->outbuf
,smb_nt_Function
, function
);
403 for (i
=0;i
<lsetup
;i
++) /* setup[] */
404 SSVAL(cli
->outbuf
,smb_nt_SetupStart
+i
*2,setup
[i
]);
406 if (this_lparam
) /* param[] */
407 memcpy(outparam
,param
,this_lparam
);
408 if (this_ldata
) /* data[] */
409 memcpy(outdata
,data
,this_ldata
);
411 cli_setup_bcc(cli
, outdata
+this_ldata
);
413 show_msg(cli
->outbuf
);
414 if (!cli_send_smb(cli
)) {
418 cli_state_seqnum_persistent(cli
, mid
);
420 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
421 /* receive interim response */
422 if (!cli_receive_smb(cli
) || cli_is_error(cli
)) {
423 cli_state_seqnum_remove(cli
, mid
);
427 tot_data
= this_ldata
;
428 tot_param
= this_lparam
;
430 while (tot_data
< ldata
|| tot_param
< lparam
) {
431 this_lparam
= MIN(lparam
-tot_param
,cli
->max_xmit
- 500); /* hack */
432 this_ldata
= MIN(ldata
-tot_data
,cli
->max_xmit
- (500+this_lparam
));
434 cli_set_message(cli
->outbuf
,18,0,True
);
435 SCVAL(cli
->outbuf
,smb_com
,SMBnttranss
);
437 /* XXX - these should probably be aligned */
438 outparam
= smb_buf(cli
->outbuf
);
439 outdata
= outparam
+this_lparam
;
441 /* secondary request */
442 SIVAL(cli
->outbuf
,smb_nts_TotalParameterCount
,lparam
);
443 SIVAL(cli
->outbuf
,smb_nts_TotalDataCount
,ldata
);
444 SIVAL(cli
->outbuf
,smb_nts_ParameterCount
,this_lparam
);
445 SIVAL(cli
->outbuf
,smb_nts_ParameterOffset
,smb_offset(outparam
,cli
->outbuf
));
446 SIVAL(cli
->outbuf
,smb_nts_ParameterDisplacement
,tot_param
);
447 SIVAL(cli
->outbuf
,smb_nts_DataCount
,this_ldata
);
448 SIVAL(cli
->outbuf
,smb_nts_DataOffset
,smb_offset(outdata
,cli
->outbuf
));
449 SIVAL(cli
->outbuf
,smb_nts_DataDisplacement
,tot_data
);
450 if (this_lparam
) /* param[] */
451 memcpy(outparam
,param
+tot_param
,this_lparam
);
452 if (this_ldata
) /* data[] */
453 memcpy(outdata
,data
+tot_data
,this_ldata
);
454 cli_setup_bcc(cli
, outdata
+this_ldata
);
456 show_msg(cli
->outbuf
);
459 if (!cli_send_smb(cli
)) {
460 cli_state_seqnum_remove(cli
, mid
);
464 tot_data
+= this_ldata
;
465 tot_param
+= this_lparam
;
472 /****************************************************************************
473 Receive a SMB nttrans response allocating the necessary memory.
474 ****************************************************************************/
476 bool cli_receive_nt_trans(struct cli_state
*cli
,
477 char **param
, unsigned int *param_len
,
478 char **data
, unsigned int *data_len
)
480 unsigned int total_data
=0;
481 unsigned int total_param
=0;
482 unsigned int this_data
,this_param
;
488 *data_len
= *param_len
= 0;
490 mid
= SVAL(cli
->outbuf
,smb_mid
);
492 if (!cli_receive_smb(cli
)) {
493 cli_state_seqnum_remove(cli
, mid
);
497 show_msg(cli
->inbuf
);
500 if (CVAL(cli
->inbuf
,smb_com
) != SMBnttrans
) {
501 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
502 CVAL(cli
->inbuf
,smb_com
)));
503 cli_state_seqnum_remove(cli
, mid
);
508 * An NT RPC pipe call can return ERRDOS, ERRmoredata
509 * to a trans call. This is not an error and should not
510 * be treated as such.
512 if (cli_is_dos_error(cli
)) {
513 cli_dos_error(cli
, &eclass
, &ecode
);
514 if (!(eclass
== ERRDOS
&& ecode
== ERRmoredata
)) {
520 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
522 if (cli_is_nt_error(cli
)) {
523 if (!NT_STATUS_EQUAL(cli_nt_error(cli
),
524 NT_STATUS_BUFFER_TOO_SMALL
)) {
529 /* parse out the lengths */
530 total_data
= IVAL(cli
->inbuf
,smb_ntr_TotalDataCount
);
531 total_param
= IVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
);
532 /* Only allow 16 megs. */
533 if (total_param
> 16*1024*1024) {
534 DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n",
538 if (total_data
> 16*1024*1024) {
539 DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n",
546 /* We know adding 2 is safe as total_data is less
547 * than 16mb (above). */
548 *data
= (char *)SMB_REALLOC(*data
,total_data
+2);
550 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data
));
556 /* We know adding 2 is safe as total_param is less
557 * than 16mb (above). */
558 *param
= (char *)SMB_REALLOC(*param
,total_param
+2);
560 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param
));
566 this_data
= SVAL(cli
->inbuf
,smb_ntr_DataCount
);
567 this_param
= SVAL(cli
->inbuf
,smb_ntr_ParameterCount
);
569 if (this_data
+ *data_len
> total_data
||
570 this_param
+ *param_len
> total_param
) {
571 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
575 if (this_data
+ *data_len
< this_data
||
576 this_data
+ *data_len
< *data_len
||
577 this_param
+ *param_len
< this_param
||
578 this_param
+ *param_len
< *param_len
) {
579 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
584 unsigned int data_offset_out
= SVAL(cli
->inbuf
,smb_ntr_DataDisplacement
);
585 unsigned int data_offset_in
= SVAL(cli
->inbuf
,smb_ntr_DataOffset
);
587 if (data_offset_out
> total_data
||
588 data_offset_out
+ this_data
> total_data
||
589 data_offset_out
+ this_data
< data_offset_out
||
590 data_offset_out
+ this_data
< this_data
) {
591 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
594 if (data_offset_in
> cli
->bufsize
||
595 data_offset_in
+ this_data
> cli
->bufsize
||
596 data_offset_in
+ this_data
< data_offset_in
||
597 data_offset_in
+ this_data
< this_data
) {
598 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
602 memcpy(*data
+ data_offset_out
, smb_base(cli
->inbuf
) + data_offset_in
, this_data
);
606 unsigned int param_offset_out
= SVAL(cli
->inbuf
,smb_ntr_ParameterDisplacement
);
607 unsigned int param_offset_in
= SVAL(cli
->inbuf
,smb_ntr_ParameterOffset
);
609 if (param_offset_out
> total_param
||
610 param_offset_out
+ this_param
> total_param
||
611 param_offset_out
+ this_param
< param_offset_out
||
612 param_offset_out
+ this_param
< this_param
) {
613 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
616 if (param_offset_in
> cli
->bufsize
||
617 param_offset_in
+ this_param
> cli
->bufsize
||
618 param_offset_in
+ this_param
< param_offset_in
||
619 param_offset_in
+ this_param
< this_param
) {
620 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
624 memcpy(*param
+ param_offset_out
, smb_base(cli
->inbuf
) + param_offset_in
, this_param
);
627 *data_len
+= this_data
;
628 *param_len
+= this_param
;
630 if (total_data
<= *data_len
&& total_param
<= *param_len
) {
635 if (!cli_receive_smb(cli
)) {
639 show_msg(cli
->inbuf
);
642 if (CVAL(cli
->inbuf
,smb_com
) != SMBnttrans
) {
643 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
644 CVAL(cli
->inbuf
,smb_com
)));
647 if (cli_is_dos_error(cli
)) {
648 cli_dos_error(cli
, &eclass
, &ecode
);
649 if(!(eclass
== ERRDOS
&& ecode
== ERRmoredata
)) {
654 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
656 if (cli_is_nt_error(cli
)) {
657 if (!NT_STATUS_EQUAL(cli_nt_error(cli
),
658 NT_STATUS_BUFFER_TOO_SMALL
)) {
663 /* parse out the total lengths again - they can shrink! */
664 if (IVAL(cli
->inbuf
,smb_ntr_TotalDataCount
) < total_data
)
665 total_data
= IVAL(cli
->inbuf
,smb_ntr_TotalDataCount
);
666 if (IVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
) < total_param
)
667 total_param
= IVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
);
669 if (total_data
<= *data_len
&& total_param
<= *param_len
) {
677 cli_state_seqnum_remove(cli
, mid
);
680 /* Ensure the last 2 bytes of param and data are 2 null
681 * bytes. These are malloc'ed, but not included in any
682 * length counts. This allows cli_XX string reading functions
683 * to safely null terminate. */
685 SSVAL(*data
,total_data
,0);
688 SSVAL(*param
,total_param
,0);
695 struct trans_recvblob
{
697 uint32_t max
, total
, received
;
700 struct cli_trans_state
{
701 struct cli_state
*cli
;
702 struct event_context
*ev
;
706 const char *pipe_name
;
707 uint8_t *pipe_name_conv
;
708 size_t pipe_name_conv_len
;
713 uint8_t num_setup
, max_setup
;
715 uint32_t num_param
, param_sent
;
717 uint32_t num_data
, data_sent
;
721 struct trans_recvblob rparam
;
722 struct trans_recvblob rdata
;
723 uint16_t recv_flags2
;
725 TALLOC_CTX
*secondary_request_ctx
;
732 static NTSTATUS
cli_pull_trans(uint8_t *inbuf
,
733 uint8_t wct
, uint16_t *vwv
,
734 uint16_t num_bytes
, uint8_t *bytes
,
735 uint8_t smb_cmd
, bool expect_first_reply
,
736 uint8_t *pnum_setup
, uint16_t **psetup
,
737 uint32_t *ptotal_param
, uint32_t *pnum_param
,
738 uint32_t *pparam_disp
, uint8_t **pparam
,
739 uint32_t *ptotal_data
, uint32_t *pnum_data
,
740 uint32_t *pdata_disp
, uint8_t **pdata
)
742 uint32_t param_ofs
, data_ofs
;
744 if (expect_first_reply
) {
745 if ((wct
!= 0) || (num_bytes
!= 0)) {
746 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
755 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
757 *ptotal_param
= SVAL(vwv
+ 0, 0);
758 *ptotal_data
= SVAL(vwv
+ 1, 0);
759 *pnum_param
= SVAL(vwv
+ 3, 0);
760 param_ofs
= SVAL(vwv
+ 4, 0);
761 *pparam_disp
= SVAL(vwv
+ 5, 0);
762 *pnum_data
= SVAL(vwv
+ 6, 0);
763 data_ofs
= SVAL(vwv
+ 7, 0);
764 *pdata_disp
= SVAL(vwv
+ 8, 0);
765 *pnum_setup
= CVAL(vwv
+ 9, 0);
766 if (wct
< 10 + (*pnum_setup
)) {
767 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
774 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
776 *ptotal_param
= IVAL(vwv
, 3);
777 *ptotal_data
= IVAL(vwv
, 7);
778 *pnum_param
= IVAL(vwv
, 11);
779 param_ofs
= IVAL(vwv
, 15);
780 *pparam_disp
= IVAL(vwv
, 19);
781 *pnum_data
= IVAL(vwv
, 23);
782 data_ofs
= IVAL(vwv
, 27);
783 *pdata_disp
= IVAL(vwv
, 31);
784 *pnum_setup
= CVAL(vwv
, 35);
789 return NT_STATUS_INTERNAL_ERROR
;
793 * Check for buffer overflows. data_ofs needs to be checked against
794 * the incoming buffer length, data_disp against the total
795 * length. Likewise for param_ofs/param_disp.
798 if (trans_oob(smb_len(inbuf
), param_ofs
, *pnum_param
)
799 || trans_oob(*ptotal_param
, *pparam_disp
, *pnum_param
)
800 || trans_oob(smb_len(inbuf
), data_ofs
, *pnum_data
)
801 || trans_oob(*ptotal_data
, *pdata_disp
, *pnum_data
)) {
802 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
805 *pparam
= (uint8_t *)inbuf
+ 4 + param_ofs
;
806 *pdata
= (uint8_t *)inbuf
+ 4 + data_ofs
;
811 static NTSTATUS
cli_trans_pull_blob(TALLOC_CTX
*mem_ctx
,
812 struct trans_recvblob
*blob
,
813 uint32_t total
, uint32_t thistime
,
814 uint8_t *buf
, uint32_t displacement
)
816 if (blob
->data
== NULL
) {
817 if (total
> blob
->max
) {
818 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
821 blob
->data
= TALLOC_ARRAY(mem_ctx
, uint8_t, total
);
822 if (blob
->data
== NULL
) {
823 return NT_STATUS_NO_MEMORY
;
827 if (total
> blob
->total
) {
828 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
832 memcpy(blob
->data
+ displacement
, buf
, thistime
);
833 blob
->received
+= thistime
;
839 static void cli_trans_format(struct cli_trans_state
*state
, uint8_t *pwct
,
843 struct iovec
*iov
= state
->iov
;
844 uint8_t *pad
= state
->pad
;
845 uint16_t *vwv
= state
->vwv
;
846 uint16_t param_offset
;
847 uint16_t this_param
= 0;
848 uint16_t this_data
= 0;
849 uint32_t useable_space
;
854 if ((state
->param_sent
!= 0) || (state
->data_sent
!= 0)) {
855 /* The secondary commands are one after the primary ones */
859 param_offset
= smb_size
- 4;
864 iov
[0].iov_base
= (void *)pad
;
866 iov
[1].iov_base
= (void *)state
->pipe_name_conv
;
867 iov
[1].iov_len
= state
->pipe_name_conv_len
;
868 wct
= 14 + state
->num_setup
;
869 param_offset
+= iov
[0].iov_len
+ iov
[1].iov_len
;
874 pad
[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
876 iov
[0].iov_base
= (void *)pad
;
878 wct
= 14 + state
->num_setup
;
889 wct
= 19 + state
->num_setup
;
896 useable_space
= state
->cli
->max_xmit
- smb_size
- sizeof(uint16_t)*wct
;
898 if (state
->param_sent
< state
->num_param
) {
899 this_param
= MIN(state
->num_param
- state
->param_sent
,
901 iov
[0].iov_base
= (void *)(state
->param
+ state
->param_sent
);
902 iov
[0].iov_len
= this_param
;
906 if (state
->data_sent
< state
->num_data
) {
907 this_data
= MIN(state
->num_data
- state
->data_sent
,
908 useable_space
- this_param
);
909 iov
[0].iov_base
= (void *)(state
->data
+ state
->data_sent
);
910 iov
[0].iov_len
= this_data
;
914 param_offset
+= wct
* sizeof(uint16_t);
916 DEBUG(10, ("num_setup=%u, max_setup=%u, "
917 "param_total=%u, this_param=%u, max_param=%u, "
918 "data_total=%u, this_data=%u, max_data=%u, "
919 "param_offset=%u, param_disp=%u, data_disp=%u\n",
920 (unsigned)state
->num_setup
, (unsigned)state
->max_setup
,
921 (unsigned)state
->num_param
, (unsigned)this_param
,
922 (unsigned)state
->rparam
.max
,
923 (unsigned)state
->num_data
, (unsigned)this_data
,
924 (unsigned)state
->rdata
.max
,
925 (unsigned)param_offset
,
926 (unsigned)state
->param_sent
, (unsigned)state
->data_sent
));
931 SSVAL(vwv
+ 0, 0, state
->num_param
);
932 SSVAL(vwv
+ 1, 0, state
->num_data
);
933 SSVAL(vwv
+ 2, 0, state
->rparam
.max
);
934 SSVAL(vwv
+ 3, 0, state
->rdata
.max
);
935 SCVAL(vwv
+ 4, 0, state
->max_setup
);
936 SCVAL(vwv
+ 4, 1, 0); /* reserved */
937 SSVAL(vwv
+ 5, 0, state
->flags
);
938 SIVAL(vwv
+ 6, 0, 0); /* timeout */
939 SSVAL(vwv
+ 8, 0, 0); /* reserved */
940 SSVAL(vwv
+ 9, 0, this_param
);
941 SSVAL(vwv
+10, 0, param_offset
);
942 SSVAL(vwv
+11, 0, this_data
);
943 SSVAL(vwv
+12, 0, param_offset
+ this_param
);
944 SCVAL(vwv
+13, 0, state
->num_setup
);
945 SCVAL(vwv
+13, 1, 0); /* reserved */
946 memcpy(vwv
+ 14, state
->setup
,
947 sizeof(uint16_t) * state
->num_setup
);
951 SSVAL(vwv
+ 0, 0, state
->num_param
);
952 SSVAL(vwv
+ 1, 0, state
->num_data
);
953 SSVAL(vwv
+ 2, 0, this_param
);
954 SSVAL(vwv
+ 3, 0, param_offset
);
955 SSVAL(vwv
+ 4, 0, state
->param_sent
);
956 SSVAL(vwv
+ 5, 0, this_data
);
957 SSVAL(vwv
+ 6, 0, param_offset
+ this_param
);
958 SSVAL(vwv
+ 7, 0, state
->data_sent
);
959 if (cmd
== SMBtranss2
) {
960 SSVAL(vwv
+ 8, 0, state
->fid
);
964 SCVAL(vwv
, 0, state
->max_setup
);
965 SSVAL(vwv
, 1, 0); /* reserved */
966 SIVAL(vwv
, 3, state
->num_param
);
967 SIVAL(vwv
, 7, state
->num_data
);
968 SIVAL(vwv
, 11, state
->rparam
.max
);
969 SIVAL(vwv
, 15, state
->rdata
.max
);
970 SIVAL(vwv
, 19, this_param
);
971 SIVAL(vwv
, 23, param_offset
);
972 SIVAL(vwv
, 27, this_data
);
973 SIVAL(vwv
, 31, param_offset
+ this_param
);
974 SCVAL(vwv
, 35, state
->num_setup
);
975 SSVAL(vwv
, 36, state
->function
);
976 memcpy(vwv
+ 19, state
->setup
,
977 sizeof(uint16_t) * state
->num_setup
);
980 SSVAL(vwv
, 0, 0); /* reserved */
981 SCVAL(vwv
, 2, 0); /* reserved */
982 SIVAL(vwv
, 3, state
->num_param
);
983 SIVAL(vwv
, 7, state
->num_data
);
984 SIVAL(vwv
, 11, this_param
);
985 SIVAL(vwv
, 15, param_offset
);
986 SIVAL(vwv
, 19, state
->param_sent
);
987 SIVAL(vwv
, 23, this_data
);
988 SIVAL(vwv
, 27, param_offset
+ this_param
);
989 SIVAL(vwv
, 31, state
->data_sent
);
990 SCVAL(vwv
, 35, 0); /* reserved */
994 state
->param_sent
+= this_param
;
995 state
->data_sent
+= this_data
;
998 *piov_count
= iov
- state
->iov
;
1001 static void cli_trans_done(struct tevent_req
*subreq
);
1003 struct tevent_req
*cli_trans_send(
1004 TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
1005 struct cli_state
*cli
, uint8_t cmd
,
1006 const char *pipe_name
, uint16_t fid
, uint16_t function
, int flags
,
1007 uint16_t *setup
, uint8_t num_setup
, uint8_t max_setup
,
1008 uint8_t *param
, uint32_t num_param
, uint32_t max_param
,
1009 uint8_t *data
, uint32_t num_data
, uint32_t max_data
)
1011 struct tevent_req
*req
, *subreq
;
1012 struct cli_trans_state
*state
;
1017 req
= tevent_req_create(mem_ctx
, &state
, struct cli_trans_state
);
1022 if ((cmd
== SMBtrans
) || (cmd
== SMBtrans2
)) {
1023 if ((num_param
> 0xffff) || (max_param
> 0xffff)
1024 || (num_data
> 0xffff) || (max_data
> 0xffff)) {
1025 DEBUG(3, ("Attempt to send invalid trans2 request "
1026 "(setup %u, params %u/%u, data %u/%u)\n",
1027 (unsigned)num_setup
,
1028 (unsigned)num_param
, (unsigned)max_param
,
1029 (unsigned)num_data
, (unsigned)max_data
));
1030 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1031 return tevent_req_post(req
, ev
);
1036 * The largest wct will be for nttrans (19+num_setup). Make sure we
1037 * don't overflow state->vwv in cli_trans_format.
1040 if ((num_setup
+ 19) > ARRAY_SIZE(state
->vwv
)) {
1041 tevent_req_nterror(req
, NT_STATUS_INVALID_PARAMETER
);
1042 return tevent_req_post(req
, ev
);
1048 state
->flags
= flags
;
1049 state
->num_rsetup
= 0;
1050 state
->rsetup
= NULL
;
1051 ZERO_STRUCT(state
->rparam
);
1052 ZERO_STRUCT(state
->rdata
);
1054 if ((pipe_name
!= NULL
)
1055 && (!convert_string_talloc(state
, CH_UNIX
,
1056 cli_ucs2(cli
) ? CH_UTF16LE
: CH_DOS
,
1057 pipe_name
, strlen(pipe_name
) + 1,
1058 &state
->pipe_name_conv
,
1059 &state
->pipe_name_conv_len
, true))) {
1060 tevent_req_nterror(req
, NT_STATUS_NO_MEMORY
);
1061 return tevent_req_post(req
, ev
);
1063 state
->fid
= fid
; /* trans2 */
1064 state
->function
= function
; /* nttrans */
1066 state
->setup
= setup
;
1067 state
->num_setup
= num_setup
;
1068 state
->max_setup
= max_setup
;
1070 state
->param
= param
;
1071 state
->num_param
= num_param
;
1072 state
->param_sent
= 0;
1073 state
->rparam
.max
= max_param
;
1076 state
->num_data
= num_data
;
1077 state
->data_sent
= 0;
1078 state
->rdata
.max
= max_data
;
1080 cli_trans_format(state
, &wct
, &iov_count
);
1082 subreq
= cli_smb_req_create(state
, ev
, cli
, cmd
, 0, wct
, state
->vwv
,
1083 iov_count
, state
->iov
);
1084 if (tevent_req_nomem(subreq
, req
)) {
1085 return tevent_req_post(req
, ev
);
1087 state
->mid
= cli_smb_req_mid(subreq
);
1088 status
= cli_smb_req_send(subreq
);
1089 if (!NT_STATUS_IS_OK(status
)) {
1090 tevent_req_nterror(req
, status
);
1091 return tevent_req_post(req
, state
->ev
);
1093 cli_state_seqnum_persistent(cli
, state
->mid
);
1094 tevent_req_set_callback(subreq
, cli_trans_done
, req
);
1098 static void cli_trans_done(struct tevent_req
*subreq
)
1100 struct tevent_req
*req
= tevent_req_callback_data(
1101 subreq
, struct tevent_req
);
1102 struct cli_trans_state
*state
= tevent_req_data(
1103 req
, struct cli_trans_state
);
1111 uint8_t num_setup
= 0;
1112 uint16_t *setup
= NULL
;
1113 uint32_t total_param
= 0;
1114 uint32_t num_param
= 0;
1115 uint32_t param_disp
= 0;
1116 uint32_t total_data
= 0;
1117 uint32_t num_data
= 0;
1118 uint32_t data_disp
= 0;
1119 uint8_t *param
= NULL
;
1120 uint8_t *data
= NULL
;
1122 status
= cli_smb_recv(subreq
, state
, &inbuf
, 0, &wct
, &vwv
,
1123 &num_bytes
, &bytes
);
1125 * Do not TALLOC_FREE(subreq) here, we might receive more than
1126 * one response for the same mid.
1130 * We can receive something like STATUS_MORE_ENTRIES, so don't use
1131 * !NT_STATUS_IS_OK(status) here.
1134 if (NT_STATUS_IS_ERR(status
)) {
1138 sent_all
= ((state
->param_sent
== state
->num_param
)
1139 && (state
->data_sent
== state
->num_data
));
1141 status
= cli_pull_trans(
1142 inbuf
, wct
, vwv
, num_bytes
, bytes
,
1143 state
->cmd
, !sent_all
, &num_setup
, &setup
,
1144 &total_param
, &num_param
, ¶m_disp
, ¶m
,
1145 &total_data
, &num_data
, &data_disp
, &data
);
1147 if (!NT_STATUS_IS_OK(status
)) {
1154 TALLOC_FREE(subreq
);
1156 cli_trans_format(state
, &wct
, &iov_count
);
1158 subreq
= cli_smb_req_create(state
, state
->ev
, state
->cli
,
1159 state
->cmd
+ 1, 0, wct
, state
->vwv
,
1160 iov_count
, state
->iov
);
1161 if (tevent_req_nomem(subreq
, req
)) {
1164 cli_smb_req_set_mid(subreq
, state
->mid
);
1166 status
= cli_smb_req_send(subreq
);
1168 if (!NT_STATUS_IS_OK(status
)) {
1171 tevent_req_set_callback(subreq
, cli_trans_done
, req
);
1175 status
= cli_trans_pull_blob(
1176 state
, &state
->rparam
, total_param
, num_param
, param
,
1179 if (!NT_STATUS_IS_OK(status
)) {
1180 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status
)));
1184 status
= cli_trans_pull_blob(
1185 state
, &state
->rdata
, total_data
, num_data
, data
,
1188 if (!NT_STATUS_IS_OK(status
)) {
1189 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status
)));
1193 if ((state
->rparam
.total
== state
->rparam
.received
)
1194 && (state
->rdata
.total
== state
->rdata
.received
)) {
1195 state
->recv_flags2
= SVAL(inbuf
, smb_flg2
);
1196 TALLOC_FREE(subreq
);
1197 cli_state_seqnum_remove(state
->cli
, state
->mid
);
1198 tevent_req_done(req
);
1204 if (!cli_smb_req_set_pending(subreq
)) {
1205 status
= NT_STATUS_NO_MEMORY
;
1211 cli_state_seqnum_remove(state
->cli
, state
->mid
);
1212 TALLOC_FREE(subreq
);
1213 tevent_req_nterror(req
, status
);
1216 NTSTATUS
cli_trans_recv(struct tevent_req
*req
, TALLOC_CTX
*mem_ctx
,
1217 uint16_t *recv_flags2
,
1218 uint16_t **setup
, uint8_t min_setup
,
1220 uint8_t **param
, uint32_t min_param
,
1221 uint32_t *num_param
,
1222 uint8_t **data
, uint32_t min_data
,
1225 struct cli_trans_state
*state
= tevent_req_data(
1226 req
, struct cli_trans_state
);
1229 if (tevent_req_is_nterror(req
, &status
)) {
1233 if ((state
->num_rsetup
< min_setup
)
1234 || (state
->rparam
.total
< min_param
)
1235 || (state
->rdata
.total
< min_data
)) {
1236 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1239 if (recv_flags2
!= NULL
) {
1240 *recv_flags2
= state
->recv_flags2
;
1243 if (setup
!= NULL
) {
1244 *setup
= talloc_move(mem_ctx
, &state
->rsetup
);
1245 *num_setup
= state
->num_rsetup
;
1247 TALLOC_FREE(state
->rsetup
);
1250 if (param
!= NULL
) {
1251 *param
= talloc_move(mem_ctx
, &state
->rparam
.data
);
1252 *num_param
= state
->rparam
.total
;
1254 TALLOC_FREE(state
->rparam
.data
);
1258 *data
= talloc_move(mem_ctx
, &state
->rdata
.data
);
1259 *num_data
= state
->rdata
.total
;
1261 TALLOC_FREE(state
->rdata
.data
);
1264 return NT_STATUS_OK
;
1267 NTSTATUS
cli_trans(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
1269 const char *pipe_name
, uint16_t fid
, uint16_t function
,
1271 uint16_t *setup
, uint8_t num_setup
, uint8_t max_setup
,
1272 uint8_t *param
, uint32_t num_param
, uint32_t max_param
,
1273 uint8_t *data
, uint32_t num_data
, uint32_t max_data
,
1274 uint16_t *recv_flags2
,
1275 uint16_t **rsetup
, uint8_t min_rsetup
, uint8_t *num_rsetup
,
1276 uint8_t **rparam
, uint32_t min_rparam
, uint32_t *num_rparam
,
1277 uint8_t **rdata
, uint32_t min_rdata
, uint32_t *num_rdata
)
1279 TALLOC_CTX
*frame
= talloc_stackframe();
1280 struct event_context
*ev
;
1281 struct tevent_req
*req
;
1282 NTSTATUS status
= NT_STATUS_OK
;
1284 if (cli_has_async_calls(cli
)) {
1286 * Can't use sync call while an async call is in flight
1288 status
= NT_STATUS_INVALID_PARAMETER
;
1292 ev
= event_context_init(frame
);
1294 status
= NT_STATUS_NO_MEMORY
;
1298 req
= cli_trans_send(frame
, ev
, cli
, trans_cmd
,
1299 pipe_name
, fid
, function
, flags
,
1300 setup
, num_setup
, max_setup
,
1301 param
, num_param
, max_param
,
1302 data
, num_data
, max_data
);
1304 status
= NT_STATUS_NO_MEMORY
;
1308 if (!tevent_req_poll(req
, ev
)) {
1309 status
= map_nt_error_from_unix(errno
);
1313 status
= cli_trans_recv(req
, mem_ctx
, recv_flags2
,
1314 rsetup
, min_rsetup
, num_rsetup
,
1315 rparam
, min_rparam
, num_rparam
,
1316 rdata
, min_rdata
, num_rdata
);
1319 if (!NT_STATUS_IS_OK(status
)) {
1320 cli_set_error(cli
, status
);