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/>.
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 /* Note we're in a trans state. Save the sequence
98 * numbers for replies. */
99 client_set_trans_sign_state_on(cli
, mid
);
101 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
102 /* receive interim response */
103 if (!cli_receive_smb(cli
) || cli_is_error(cli
)) {
104 client_set_trans_sign_state_off(cli
, mid
);
108 tot_data
= this_ldata
;
109 tot_param
= this_lparam
;
111 while (tot_data
< ldata
|| tot_param
< lparam
) {
112 this_lparam
= MIN(lparam
-tot_param
,cli
->max_xmit
- 500); /* hack */
113 this_ldata
= MIN(ldata
-tot_data
,cli
->max_xmit
- (500+this_lparam
));
115 cli_set_message(cli
->outbuf
,trans
==SMBtrans
?8:9,0,True
);
116 SCVAL(cli
->outbuf
,smb_com
,(trans
==SMBtrans
? SMBtranss
: SMBtranss2
));
118 outparam
= smb_buf(cli
->outbuf
);
119 outdata
= outparam
+this_lparam
;
121 /* secondary request */
122 SSVAL(cli
->outbuf
,smb_tpscnt
,lparam
); /* tpscnt */
123 SSVAL(cli
->outbuf
,smb_tdscnt
,ldata
); /* tdscnt */
124 SSVAL(cli
->outbuf
,smb_spscnt
,this_lparam
); /* pscnt */
125 SSVAL(cli
->outbuf
,smb_spsoff
,smb_offset(outparam
,cli
->outbuf
)); /* psoff */
126 SSVAL(cli
->outbuf
,smb_spsdisp
,tot_param
); /* psdisp */
127 SSVAL(cli
->outbuf
,smb_sdscnt
,this_ldata
); /* dscnt */
128 SSVAL(cli
->outbuf
,smb_sdsoff
,smb_offset(outdata
,cli
->outbuf
)); /* dsoff */
129 SSVAL(cli
->outbuf
,smb_sdsdisp
,tot_data
); /* dsdisp */
130 if (trans
==SMBtrans2
)
131 SSVALS(cli
->outbuf
,smb_sfid
,fid
); /* fid */
132 if (this_lparam
) /* param[] */
133 memcpy(outparam
,param
+tot_param
,this_lparam
);
134 if (this_ldata
) /* data[] */
135 memcpy(outdata
,data
+tot_data
,this_ldata
);
136 cli_setup_bcc(cli
, outdata
+this_ldata
);
138 show_msg(cli
->outbuf
);
140 client_set_trans_sign_state_off(cli
, mid
);
142 if (!cli_send_smb(cli
)) {
145 client_set_trans_sign_state_on(cli
, mid
);
147 tot_data
+= this_ldata
;
148 tot_param
+= this_lparam
;
155 /****************************************************************************
156 Receive a SMB trans or trans2 response allocating the necessary memory.
157 ****************************************************************************/
159 bool cli_receive_trans(struct cli_state
*cli
,int trans
,
160 char **param
, unsigned int *param_len
,
161 char **data
, unsigned int *data_len
)
163 unsigned int total_data
=0;
164 unsigned int total_param
=0;
165 unsigned int this_data
,this_param
;
169 *data_len
= *param_len
= 0;
171 if (!cli_receive_smb(cli
)) {
175 show_msg(cli
->inbuf
);
178 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
179 DEBUG(0,("Expected %s response, got command 0x%02x\n",
180 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
181 CVAL(cli
->inbuf
,smb_com
)));
186 * An NT RPC pipe call can return ERRDOS, ERRmoredata
187 * to a trans call. This is not an error and should not
188 * be treated as such. Note that STATUS_NO_MORE_FILES is
189 * returned when a trans2 findfirst/next finishes.
190 * When setting up an encrypted transport we can also
191 * see NT_STATUS_MORE_PROCESSING_REQUIRED here.
193 * Vista returns NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT if the folder
194 * "<share>/Users/All Users" is enumerated. This is a special pseudo
195 * folder, and the response does not have parameters (nor a parameter
198 status
= cli_nt_error(cli
);
200 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
201 if (NT_STATUS_IS_ERR(status
) ||
202 NT_STATUS_EQUAL(status
,STATUS_NO_MORE_FILES
) ||
203 NT_STATUS_EQUAL(status
,NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT
)) {
208 /* parse out the lengths */
209 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
210 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
214 /* We know adding 2 is safe as total_data is an
216 *data
= (char *)SMB_REALLOC(*data
,total_data
+2);
218 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
223 if (total_param
!=0) {
224 /* We know adding 2 is safe as total_param is an
226 *param
= (char *)SMB_REALLOC(*param
,total_param
+2);
228 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
234 this_data
= SVAL(cli
->inbuf
,smb_drcnt
);
235 this_param
= SVAL(cli
->inbuf
,smb_prcnt
);
237 if (this_data
+ *data_len
> total_data
||
238 this_param
+ *param_len
> total_param
) {
239 DEBUG(1,("Data overflow in cli_receive_trans\n"));
243 if (this_data
+ *data_len
< this_data
||
244 this_data
+ *data_len
< *data_len
||
245 this_param
+ *param_len
< this_param
||
246 this_param
+ *param_len
< *param_len
) {
247 DEBUG(1,("Data overflow in cli_receive_trans\n"));
252 unsigned int data_offset_out
= SVAL(cli
->inbuf
,smb_drdisp
);
253 unsigned int data_offset_in
= SVAL(cli
->inbuf
,smb_droff
);
255 if (data_offset_out
> total_data
||
256 data_offset_out
+ this_data
> total_data
||
257 data_offset_out
+ this_data
< data_offset_out
||
258 data_offset_out
+ this_data
< this_data
) {
259 DEBUG(1,("Data overflow in cli_receive_trans\n"));
262 if (data_offset_in
> cli
->bufsize
||
263 data_offset_in
+ this_data
> cli
->bufsize
||
264 data_offset_in
+ this_data
< data_offset_in
||
265 data_offset_in
+ this_data
< this_data
) {
266 DEBUG(1,("Data overflow in cli_receive_trans\n"));
270 memcpy(*data
+ data_offset_out
, smb_base(cli
->inbuf
) + data_offset_in
, this_data
);
273 unsigned int param_offset_out
= SVAL(cli
->inbuf
,smb_prdisp
);
274 unsigned int param_offset_in
= SVAL(cli
->inbuf
,smb_proff
);
276 if (param_offset_out
> total_param
||
277 param_offset_out
+ this_param
> total_param
||
278 param_offset_out
+ this_param
< param_offset_out
||
279 param_offset_out
+ this_param
< this_param
) {
280 DEBUG(1,("Param overflow in cli_receive_trans\n"));
283 if (param_offset_in
> cli
->bufsize
||
284 param_offset_in
+ this_param
> cli
->bufsize
||
285 param_offset_in
+ this_param
< param_offset_in
||
286 param_offset_in
+ this_param
< this_param
) {
287 DEBUG(1,("Param overflow in cli_receive_trans\n"));
291 memcpy(*param
+ param_offset_out
, smb_base(cli
->inbuf
) + param_offset_in
, this_param
);
293 *data_len
+= this_data
;
294 *param_len
+= this_param
;
296 if (total_data
<= *data_len
&& total_param
<= *param_len
) {
301 if (!cli_receive_smb(cli
)) {
305 show_msg(cli
->inbuf
);
308 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
309 DEBUG(0,("Expected %s response, got command 0x%02x\n",
310 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
311 CVAL(cli
->inbuf
,smb_com
)));
314 if (!NT_STATUS_EQUAL(status
, NT_STATUS_MORE_PROCESSING_REQUIRED
)) {
315 if (NT_STATUS_IS_ERR(cli_nt_error(cli
))) {
320 /* parse out the total lengths again - they can shrink! */
321 if (SVAL(cli
->inbuf
,smb_tdrcnt
) < total_data
)
322 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
323 if (SVAL(cli
->inbuf
,smb_tprcnt
) < total_param
)
324 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
326 if (total_data
<= *data_len
&& total_param
<= *param_len
) {
335 /* Ensure the last 2 bytes of param and data are 2 null
336 * bytes. These are malloc'ed, but not included in any
337 * length counts. This allows cli_XX string reading functions
338 * to safely null terminate. */
340 SSVAL(*data
,total_data
,0);
343 SSVAL(*param
,total_param
,0);
347 client_set_trans_sign_state_off(cli
, SVAL(cli
->inbuf
,smb_mid
));
351 /****************************************************************************
352 Send a SMB nttrans request.
353 ****************************************************************************/
355 bool cli_send_nt_trans(struct cli_state
*cli
,
358 uint16
*setup
, unsigned int lsetup
, unsigned int msetup
,
359 char *param
, unsigned int lparam
, unsigned int mparam
,
360 char *data
, unsigned int ldata
, unsigned int mdata
)
363 unsigned int this_ldata
,this_lparam
;
364 unsigned int tot_data
=0,tot_param
=0;
366 char *outdata
,*outparam
;
368 this_lparam
= MIN(lparam
,cli
->max_xmit
- (500+lsetup
*2)); /* hack */
369 this_ldata
= MIN(ldata
,cli
->max_xmit
- (500+lsetup
*2+this_lparam
));
371 memset(cli
->outbuf
,'\0',smb_size
);
372 cli_set_message(cli
->outbuf
,19+lsetup
,0,True
);
373 SCVAL(cli
->outbuf
,smb_com
,SMBnttrans
);
374 SSVAL(cli
->outbuf
,smb_tid
, cli
->cnum
);
375 cli_setup_packet(cli
);
378 * Save the mid we're using. We need this for finding
384 outparam
= smb_buf(cli
->outbuf
)+3;
385 outdata
= outparam
+this_lparam
;
387 /* primary request */
388 SCVAL(cli
->outbuf
,smb_nt_MaxSetupCount
,msetup
);
389 SCVAL(cli
->outbuf
,smb_nt_Flags
,flags
);
390 SIVAL(cli
->outbuf
,smb_nt_TotalParameterCount
, lparam
);
391 SIVAL(cli
->outbuf
,smb_nt_TotalDataCount
, ldata
);
392 SIVAL(cli
->outbuf
,smb_nt_MaxParameterCount
, mparam
);
393 SIVAL(cli
->outbuf
,smb_nt_MaxDataCount
, mdata
);
394 SIVAL(cli
->outbuf
,smb_nt_ParameterCount
, this_lparam
);
395 SIVAL(cli
->outbuf
,smb_nt_ParameterOffset
, smb_offset(outparam
,cli
->outbuf
));
396 SIVAL(cli
->outbuf
,smb_nt_DataCount
, this_ldata
);
397 SIVAL(cli
->outbuf
,smb_nt_DataOffset
, smb_offset(outdata
,cli
->outbuf
));
398 SIVAL(cli
->outbuf
,smb_nt_SetupCount
, lsetup
);
399 SIVAL(cli
->outbuf
,smb_nt_Function
, function
);
400 for (i
=0;i
<lsetup
;i
++) /* setup[] */
401 SSVAL(cli
->outbuf
,smb_nt_SetupStart
+i
*2,setup
[i
]);
403 if (this_lparam
) /* param[] */
404 memcpy(outparam
,param
,this_lparam
);
405 if (this_ldata
) /* data[] */
406 memcpy(outdata
,data
,this_ldata
);
408 cli_setup_bcc(cli
, outdata
+this_ldata
);
410 show_msg(cli
->outbuf
);
411 if (!cli_send_smb(cli
)) {
415 /* Note we're in a trans state. Save the sequence
416 * numbers for replies. */
417 client_set_trans_sign_state_on(cli
, mid
);
419 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
420 /* receive interim response */
421 if (!cli_receive_smb(cli
) || cli_is_error(cli
)) {
422 client_set_trans_sign_state_off(cli
, mid
);
426 tot_data
= this_ldata
;
427 tot_param
= this_lparam
;
429 while (tot_data
< ldata
|| tot_param
< lparam
) {
430 this_lparam
= MIN(lparam
-tot_param
,cli
->max_xmit
- 500); /* hack */
431 this_ldata
= MIN(ldata
-tot_data
,cli
->max_xmit
- (500+this_lparam
));
433 cli_set_message(cli
->outbuf
,18,0,True
);
434 SCVAL(cli
->outbuf
,smb_com
,SMBnttranss
);
436 /* XXX - these should probably be aligned */
437 outparam
= smb_buf(cli
->outbuf
);
438 outdata
= outparam
+this_lparam
;
440 /* secondary request */
441 SIVAL(cli
->outbuf
,smb_nts_TotalParameterCount
,lparam
);
442 SIVAL(cli
->outbuf
,smb_nts_TotalDataCount
,ldata
);
443 SIVAL(cli
->outbuf
,smb_nts_ParameterCount
,this_lparam
);
444 SIVAL(cli
->outbuf
,smb_nts_ParameterOffset
,smb_offset(outparam
,cli
->outbuf
));
445 SIVAL(cli
->outbuf
,smb_nts_ParameterDisplacement
,tot_param
);
446 SIVAL(cli
->outbuf
,smb_nts_DataCount
,this_ldata
);
447 SIVAL(cli
->outbuf
,smb_nts_DataOffset
,smb_offset(outdata
,cli
->outbuf
));
448 SIVAL(cli
->outbuf
,smb_nts_DataDisplacement
,tot_data
);
449 if (this_lparam
) /* param[] */
450 memcpy(outparam
,param
+tot_param
,this_lparam
);
451 if (this_ldata
) /* data[] */
452 memcpy(outdata
,data
+tot_data
,this_ldata
);
453 cli_setup_bcc(cli
, outdata
+this_ldata
);
455 show_msg(cli
->outbuf
);
457 client_set_trans_sign_state_off(cli
, mid
);
459 if (!cli_send_smb(cli
)) {
462 client_set_trans_sign_state_on(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
;
487 *data_len
= *param_len
= 0;
489 if (!cli_receive_smb(cli
)) {
493 show_msg(cli
->inbuf
);
496 if (CVAL(cli
->inbuf
,smb_com
) != SMBnttrans
) {
497 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
498 CVAL(cli
->inbuf
,smb_com
)));
503 * An NT RPC pipe call can return ERRDOS, ERRmoredata
504 * to a trans call. This is not an error and should not
505 * be treated as such.
507 if (cli_is_dos_error(cli
)) {
508 cli_dos_error(cli
, &eclass
, &ecode
);
509 if (!(eclass
== ERRDOS
&& ecode
== ERRmoredata
)) {
515 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
517 if (cli_is_nt_error(cli
)) {
518 if (!NT_STATUS_EQUAL(cli_nt_error(cli
),
519 NT_STATUS_BUFFER_TOO_SMALL
)) {
524 /* parse out the lengths */
525 total_data
= IVAL(cli
->inbuf
,smb_ntr_TotalDataCount
);
526 total_param
= IVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
);
527 /* Only allow 16 megs. */
528 if (total_param
> 16*1024*1024) {
529 DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n",
533 if (total_data
> 16*1024*1024) {
534 DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n",
541 /* We know adding 2 is safe as total_data is less
542 * than 16mb (above). */
543 *data
= (char *)SMB_REALLOC(*data
,total_data
+2);
545 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data
));
551 /* We know adding 2 is safe as total_param is less
552 * than 16mb (above). */
553 *param
= (char *)SMB_REALLOC(*param
,total_param
+2);
555 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param
));
561 this_data
= SVAL(cli
->inbuf
,smb_ntr_DataCount
);
562 this_param
= SVAL(cli
->inbuf
,smb_ntr_ParameterCount
);
564 if (this_data
+ *data_len
> total_data
||
565 this_param
+ *param_len
> total_param
) {
566 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
570 if (this_data
+ *data_len
< this_data
||
571 this_data
+ *data_len
< *data_len
||
572 this_param
+ *param_len
< this_param
||
573 this_param
+ *param_len
< *param_len
) {
574 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
579 unsigned int data_offset_out
= SVAL(cli
->inbuf
,smb_ntr_DataDisplacement
);
580 unsigned int data_offset_in
= SVAL(cli
->inbuf
,smb_ntr_DataOffset
);
582 if (data_offset_out
> total_data
||
583 data_offset_out
+ this_data
> total_data
||
584 data_offset_out
+ this_data
< data_offset_out
||
585 data_offset_out
+ this_data
< this_data
) {
586 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
589 if (data_offset_in
> cli
->bufsize
||
590 data_offset_in
+ this_data
> cli
->bufsize
||
591 data_offset_in
+ this_data
< data_offset_in
||
592 data_offset_in
+ this_data
< this_data
) {
593 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
597 memcpy(*data
+ data_offset_out
, smb_base(cli
->inbuf
) + data_offset_in
, this_data
);
601 unsigned int param_offset_out
= SVAL(cli
->inbuf
,smb_ntr_ParameterDisplacement
);
602 unsigned int param_offset_in
= SVAL(cli
->inbuf
,smb_ntr_ParameterOffset
);
604 if (param_offset_out
> total_param
||
605 param_offset_out
+ this_param
> total_param
||
606 param_offset_out
+ this_param
< param_offset_out
||
607 param_offset_out
+ this_param
< this_param
) {
608 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
611 if (param_offset_in
> cli
->bufsize
||
612 param_offset_in
+ this_param
> cli
->bufsize
||
613 param_offset_in
+ this_param
< param_offset_in
||
614 param_offset_in
+ this_param
< this_param
) {
615 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
619 memcpy(*param
+ param_offset_out
, smb_base(cli
->inbuf
) + param_offset_in
, this_param
);
622 *data_len
+= this_data
;
623 *param_len
+= this_param
;
625 if (total_data
<= *data_len
&& total_param
<= *param_len
) {
630 if (!cli_receive_smb(cli
)) {
634 show_msg(cli
->inbuf
);
637 if (CVAL(cli
->inbuf
,smb_com
) != SMBnttrans
) {
638 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
639 CVAL(cli
->inbuf
,smb_com
)));
642 if (cli_is_dos_error(cli
)) {
643 cli_dos_error(cli
, &eclass
, &ecode
);
644 if(!(eclass
== ERRDOS
&& ecode
== ERRmoredata
)) {
649 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
651 if (cli_is_nt_error(cli
)) {
652 if (!NT_STATUS_EQUAL(cli_nt_error(cli
),
653 NT_STATUS_BUFFER_TOO_SMALL
)) {
658 /* parse out the total lengths again - they can shrink! */
659 if (IVAL(cli
->inbuf
,smb_ntr_TotalDataCount
) < total_data
)
660 total_data
= IVAL(cli
->inbuf
,smb_ntr_TotalDataCount
);
661 if (IVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
) < total_param
)
662 total_param
= IVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
);
664 if (total_data
<= *data_len
&& total_param
<= *param_len
) {
673 /* Ensure the last 2 bytes of param and data are 2 null
674 * bytes. These are malloc'ed, but not included in any
675 * length counts. This allows cli_XX string reading functions
676 * to safely null terminate. */
678 SSVAL(*data
,total_data
,0);
681 SSVAL(*param
,total_param
,0);
685 client_set_trans_sign_state_off(cli
, SVAL(cli
->inbuf
,smb_mid
));
689 struct trans_recvblob
{
691 uint32_t max
, total
, received
;
694 struct cli_trans_state
{
695 struct cli_state
*cli
;
696 struct event_context
*ev
;
699 const char *pipe_name
;
704 uint8_t num_setup
, max_setup
;
706 uint32_t num_param
, param_sent
;
708 uint32_t num_data
, data_sent
;
712 struct trans_recvblob rparam
;
713 struct trans_recvblob rdata
;
715 TALLOC_CTX
*secondary_request_ctx
;
718 static void cli_trans_recv_helper(struct async_req
*req
);
720 static struct async_req
*cli_ship_trans(TALLOC_CTX
*mem_ctx
,
721 struct cli_trans_state
*state
)
724 struct async_req
*result
= NULL
;
725 struct cli_request
*cli_req
;
728 uint8_t *bytes
= NULL
;
729 uint16_t param_offset
;
730 uint16_t this_param
= 0;
731 uint16_t this_data
= 0;
732 uint32_t useable_space
;
736 frame
= talloc_stackframe();
740 if ((state
->param_sent
!= 0) || (state
->data_sent
!= 0)) {
741 /* The secondary commands are one after the primary ones */
745 param_offset
= smb_size
- 4;
747 bytes
= TALLOC_ARRAY(talloc_tos(), uint8_t, 0); /* padding */
755 bytes
= (uint8_t *)talloc_append_blob(talloc_tos(), bytes
,
756 data_blob_const(pad
, 1));
760 bytes
= smb_bytes_push_str(bytes
, cli_ucs2(state
->cli
),
762 strlen(state
->pipe_name
)+1, NULL
);
766 wct
= 14 + state
->num_setup
;
767 param_offset
+= talloc_get_size(bytes
);
771 pad
[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
773 bytes
= (uint8_t *)talloc_append_blob(talloc_tos(), bytes
,
774 data_blob_const(pad
, 3));
778 wct
= 14 + state
->num_setup
;
779 param_offset
+= talloc_get_size(bytes
);
788 wct
= 19 + state
->num_setup
;
797 useable_space
= state
->cli
->max_xmit
- smb_size
- sizeof(uint16_t)*wct
;
799 if (state
->param_sent
< state
->num_param
) {
800 this_param
= MIN(state
->num_param
- state
->param_sent
,
804 if (state
->data_sent
< state
->num_data
) {
805 this_data
= MIN(state
->num_data
- state
->data_sent
,
806 useable_space
- this_param
);
809 vwv
= TALLOC_ARRAY(talloc_tos(), uint16_t, wct
);
813 param_offset
+= wct
* sizeof(uint16_t);
815 DEBUG(10, ("num_setup=%u, max_setup=%u, "
816 "param_total=%u, this_param=%u, max_param=%u, "
817 "data_total=%u, this_data=%u, max_data=%u, "
818 "param_offset=%u, param_disp=%u, data_disp=%u\n",
819 (unsigned)state
->num_setup
, (unsigned)state
->max_setup
,
820 (unsigned)state
->num_param
, (unsigned)this_param
,
821 (unsigned)state
->rparam
.max
,
822 (unsigned)state
->num_data
, (unsigned)this_data
,
823 (unsigned)state
->rdata
.max
,
824 (unsigned)param_offset
,
825 (unsigned)state
->param_sent
, (unsigned)state
->data_sent
));
830 SSVAL(vwv
+ 0, 0, state
->num_param
);
831 SSVAL(vwv
+ 1, 0, state
->num_data
);
832 SSVAL(vwv
+ 2, 0, state
->rparam
.max
);
833 SSVAL(vwv
+ 3, 0, state
->rdata
.max
);
834 SCVAL(vwv
+ 4, 0, state
->max_setup
);
835 SCVAL(vwv
+ 4, 1, 0); /* reserved */
836 SSVAL(vwv
+ 5, 0, state
->flags
);
837 SIVAL(vwv
+ 6, 0, 0); /* timeout */
838 SSVAL(vwv
+ 8, 0, 0); /* reserved */
839 SSVAL(vwv
+ 9, 0, this_param
);
840 SSVAL(vwv
+10, 0, param_offset
);
841 SSVAL(vwv
+11, 0, this_data
);
842 SSVAL(vwv
+12, 0, param_offset
+ this_param
);
843 SCVAL(vwv
+13, 0, state
->num_setup
);
844 SCVAL(vwv
+13, 1, 0); /* reserved */
845 memcpy(vwv
+ 14, state
->setup
,
846 sizeof(uint16_t) * state
->num_setup
);
850 SSVAL(vwv
+ 0, 0, state
->num_param
);
851 SSVAL(vwv
+ 1, 0, state
->num_data
);
852 SSVAL(vwv
+ 2, 0, this_param
);
853 SSVAL(vwv
+ 3, 0, param_offset
);
854 SSVAL(vwv
+ 4, 0, state
->param_sent
);
855 SSVAL(vwv
+ 5, 0, this_data
);
856 SSVAL(vwv
+ 6, 0, param_offset
+ this_param
);
857 SSVAL(vwv
+ 7, 0, state
->data_sent
);
858 if (cmd
== SMBtranss2
) {
859 SSVAL(vwv
+ 8, 0, state
->fid
);
863 SCVAL(vwv
, 0, state
->max_setup
);
864 SSVAL(vwv
, 1, 0); /* reserved */
865 SIVAL(vwv
, 3, state
->num_param
);
866 SIVAL(vwv
, 7, state
->num_data
);
867 SIVAL(vwv
, 11, state
->rparam
.max
);
868 SIVAL(vwv
, 15, state
->rdata
.max
);
869 SIVAL(vwv
, 19, this_param
);
870 SIVAL(vwv
, 23, param_offset
);
871 SIVAL(vwv
, 27, this_data
);
872 SIVAL(vwv
, 31, param_offset
+ this_param
);
873 SCVAL(vwv
, 35, state
->num_setup
);
874 SSVAL(vwv
, 36, state
->function
);
875 memcpy(vwv
+ 19, state
->setup
,
876 sizeof(uint16_t) * state
->num_setup
);
879 SSVAL(vwv
, 0, 0); /* reserved */
880 SCVAL(vwv
, 2, 0); /* reserved */
881 SIVAL(vwv
, 3, state
->num_param
);
882 SIVAL(vwv
, 7, state
->num_data
);
883 SIVAL(vwv
, 11, this_param
);
884 SIVAL(vwv
, 15, param_offset
);
885 SIVAL(vwv
, 19, state
->param_sent
);
886 SIVAL(vwv
, 23, this_data
);
887 SIVAL(vwv
, 27, param_offset
+ this_param
);
888 SIVAL(vwv
, 31, state
->data_sent
);
889 SCVAL(vwv
, 35, 0); /* reserved */
893 bytes
= (uint8_t *)talloc_append_blob(
895 data_blob_const(state
->param
+ state
->param_sent
, this_param
));
899 state
->param_sent
+= this_param
;
901 bytes
= (uint8_t *)talloc_append_blob(
903 data_blob_const(state
->data
+ state
->data_sent
, this_data
));
907 state
->data_sent
+= this_data
;
909 if ((cmd
== SMBtrans
) || (cmd
== SMBtrans2
) || (cmd
== SMBnttrans
)) {
911 * Primary request, retrieve our mid
913 result
= cli_request_send(mem_ctx
, state
->ev
, state
->cli
,
915 talloc_get_size(bytes
), bytes
);
916 if (result
== NULL
) {
919 cli_req
= talloc_get_type_abort(result
->private_data
,
921 state
->mid
= cli_req
->mid
;
923 uint16_t num_bytes
= talloc_get_size(bytes
);
925 * Secondary request, we have to fix up the mid. Thus we do
926 * the chain_cork/chain/uncork ourselves.
928 if (!cli_chain_cork(state
->cli
, state
->ev
,
929 wct
* sizeof(uint16_t) + num_bytes
+ 3)) {
932 result
= cli_request_send(mem_ctx
, state
->ev
, state
->cli
, cmd
,
933 0, wct
, vwv
, 0, num_bytes
, bytes
);
934 if (result
== NULL
) {
937 cli_req
= talloc_get_type_abort(result
->private_data
,
939 cli_req
->recv_helper
.fn
= cli_trans_recv_helper
;
940 cli_req
->recv_helper
.priv
= state
;
941 cli_req
->mid
= state
->mid
;
942 client_set_trans_sign_state_off(state
->cli
, state
->mid
);
943 cli_chain_uncork(state
->cli
);
946 client_set_trans_sign_state_on(state
->cli
, state
->mid
);
953 static void cli_trans_ship_rest(struct async_req
*req
,
954 struct cli_trans_state
*state
)
956 state
->secondary_request_ctx
= talloc_new(state
);
957 if (state
->secondary_request_ctx
== NULL
) {
958 async_req_nterror(req
, NT_STATUS_NO_MEMORY
);
962 while ((state
->param_sent
< state
->num_param
)
963 || (state
->data_sent
< state
->num_data
)) {
964 struct async_req
*cli_req
;
966 cli_req
= cli_ship_trans(state
->secondary_request_ctx
, state
);
967 if (cli_req
== NULL
) {
968 async_req_nterror(req
, NT_STATUS_NO_MEMORY
);
974 static NTSTATUS
cli_pull_trans(struct async_req
*req
,
975 struct cli_request
*cli_req
,
976 uint8_t smb_cmd
, bool expect_first_reply
,
977 uint8_t *pnum_setup
, uint16_t **psetup
,
978 uint32_t *ptotal_param
, uint32_t *pnum_param
,
979 uint32_t *pparam_disp
, uint8_t **pparam
,
980 uint32_t *ptotal_data
, uint32_t *pnum_data
,
981 uint32_t *pdata_disp
, uint8_t **pdata
)
983 uint32_t param_ofs
, data_ofs
;
990 status
= cli_pull_reply(req
, &wct
, &vwv
, &num_bytes
, &bytes
);
993 * We can receive something like STATUS_MORE_ENTRIES, so don't use
994 * !NT_STATUS_IS_OK(status) here.
997 if (NT_STATUS_IS_ERR(status
)) {
1001 if (expect_first_reply
) {
1002 if ((wct
!= 0) || (num_bytes
!= 0)) {
1003 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1005 return NT_STATUS_OK
;
1012 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1014 *ptotal_param
= SVAL(vwv
+ 0, 0);
1015 *ptotal_data
= SVAL(vwv
+ 1, 0);
1016 *pnum_param
= SVAL(vwv
+ 3, 0);
1017 param_ofs
= SVAL(vwv
+ 4, 0);
1018 *pparam_disp
= SVAL(vwv
+ 5, 0);
1019 *pnum_data
= SVAL(vwv
+ 6, 0);
1020 data_ofs
= SVAL(vwv
+ 7, 0);
1021 *pdata_disp
= SVAL(vwv
+ 8, 0);
1022 *pnum_setup
= CVAL(vwv
+ 9, 0);
1023 if (wct
< 10 + (*pnum_setup
)) {
1024 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1031 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1033 *ptotal_param
= IVAL(vwv
, 3);
1034 *ptotal_data
= IVAL(vwv
, 7);
1035 *pnum_param
= IVAL(vwv
, 11);
1036 param_ofs
= IVAL(vwv
, 15);
1037 *pparam_disp
= IVAL(vwv
, 19);
1038 *pnum_data
= IVAL(vwv
, 23);
1039 data_ofs
= IVAL(vwv
, 27);
1040 *pdata_disp
= IVAL(vwv
, 31);
1041 *pnum_setup
= CVAL(vwv
, 35);
1046 return NT_STATUS_INTERNAL_ERROR
;
1050 * Check for buffer overflows. data_ofs needs to be checked against
1051 * the incoming buffer length, data_disp against the total
1052 * length. Likewise for param_ofs/param_disp.
1055 if (trans_oob(smb_len(cli_req
->inbuf
), param_ofs
, *pnum_param
)
1056 || trans_oob(*ptotal_param
, *pparam_disp
, *pnum_param
)
1057 || trans_oob(smb_len(cli_req
->inbuf
), data_ofs
, *pnum_data
)
1058 || trans_oob(*ptotal_data
, *pdata_disp
, *pnum_data
)) {
1059 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1062 *pparam
= (uint8_t *)cli_req
->inbuf
+ 4 + param_ofs
;
1063 *pdata
= (uint8_t *)cli_req
->inbuf
+ 4 + data_ofs
;
1065 return NT_STATUS_OK
;
1068 static NTSTATUS
cli_trans_pull_blob(TALLOC_CTX
*mem_ctx
,
1069 struct trans_recvblob
*blob
,
1070 uint32_t total
, uint32_t thistime
,
1071 uint8_t *buf
, uint32_t displacement
)
1073 if (blob
->data
== NULL
) {
1074 if (total
> blob
->max
) {
1075 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1077 blob
->total
= total
;
1078 blob
->data
= TALLOC_ARRAY(mem_ctx
, uint8_t, total
);
1079 if (blob
->data
== NULL
) {
1080 return NT_STATUS_NO_MEMORY
;
1084 if (total
> blob
->total
) {
1085 return NT_STATUS_INVALID_NETWORK_RESPONSE
;
1089 memcpy(blob
->data
+ displacement
, buf
, thistime
);
1090 blob
->received
+= thistime
;
1093 return NT_STATUS_OK
;
1096 static void cli_trans_recv_helper(struct async_req
*req
)
1098 struct cli_request
*cli_req
= talloc_get_type_abort(
1099 req
->private_data
, struct cli_request
);
1100 struct cli_trans_state
*state
= talloc_get_type_abort(
1101 cli_req
->recv_helper
.priv
, struct cli_trans_state
);
1102 uint8_t num_setup
= 0;
1103 uint16_t *setup
= NULL
;
1104 uint32_t total_param
= 0;
1105 uint32_t num_param
= 0;
1106 uint32_t param_disp
= 0;
1107 uint32_t total_data
= 0;
1108 uint32_t num_data
= 0;
1109 uint32_t data_disp
= 0;
1110 uint8_t *param
= NULL
;
1111 uint8_t *data
= NULL
;
1115 sent_all
= (state
->param_sent
== state
->num_param
)
1116 && (state
->data_sent
== state
->num_data
);
1118 status
= cli_pull_trans(
1119 req
, cli_req
, state
->cmd
, !sent_all
, &num_setup
, &setup
,
1120 &total_param
, &num_param
, ¶m_disp
, ¶m
,
1121 &total_data
, &num_data
, &data_disp
, &data
);
1124 * We can receive something like STATUS_MORE_ENTRIES, so don't use
1125 * !NT_STATUS_IS_OK(status) here.
1128 if (NT_STATUS_IS_ERR(status
)) {
1129 async_req_nterror(req
, status
);
1134 cli_trans_ship_rest(req
, state
);
1139 * We've just received a real response. This means that we don't need
1140 * the secondary cli_request structures anymore, they have all been
1141 * shipped to the server.
1143 TALLOC_FREE(state
->secondary_request_ctx
);
1145 if (num_setup
!= 0) {
1146 TALLOC_FREE(state
->rsetup
);
1147 state
->rsetup
= (uint16_t *)TALLOC_MEMDUP(
1148 state
, setup
, sizeof(uint16_t) * num_setup
);
1149 if (state
->rsetup
== NULL
) {
1150 async_req_nterror(req
, NT_STATUS_NO_MEMORY
);
1155 status
= cli_trans_pull_blob(
1156 state
, &state
->rparam
, total_param
, num_param
, param
,
1159 if (!NT_STATUS_IS_OK(status
)) {
1160 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status
)));
1161 async_req_nterror(req
, status
);
1165 status
= cli_trans_pull_blob(
1166 state
, &state
->rdata
, total_data
, num_data
, data
,
1169 if (!NT_STATUS_IS_OK(status
)) {
1170 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status
)));
1171 async_req_nterror(req
, status
);
1175 if ((state
->rparam
.total
== state
->rparam
.received
)
1176 && (state
->rdata
.total
== state
->rdata
.received
)) {
1177 client_set_trans_sign_state_off(state
->cli
, state
->mid
);
1178 async_req_done(req
);
1182 struct async_req
*cli_trans_send(
1183 TALLOC_CTX
*mem_ctx
, struct event_context
*ev
,
1184 struct cli_state
*cli
, uint8_t trans_cmd
,
1185 const char *pipe_name
, uint16_t fid
, uint16_t function
, int flags
,
1186 uint16_t *setup
, uint8_t num_setup
, uint8_t max_setup
,
1187 uint8_t *param
, uint32_t num_param
, uint32_t max_param
,
1188 uint8_t *data
, uint32_t num_data
, uint32_t max_data
)
1190 struct async_req
*req
;
1191 struct cli_request
*cli_req
;
1192 struct cli_trans_state
*state
;
1195 * We can't use it in a chained request chain, we'd get the offset
1196 * calculations wrong.
1199 if (cli_in_chain(cli
)) {
1203 if ((trans_cmd
== SMBtrans
) || (trans_cmd
== SMBtrans2
)) {
1204 if ((num_param
> 0xffff) || (max_param
> 0xffff)
1205 || (num_data
> 0xffff) || (max_data
> 0xffff)) {
1206 DEBUG(3, ("Attempt to send invalid trans2 request "
1207 "(setup %u, params %u/%u, data %u/%u)\n",
1208 (unsigned)num_setup
,
1209 (unsigned)num_param
, (unsigned)max_param
,
1210 (unsigned)num_data
, (unsigned)max_data
));
1215 state
= talloc(mem_ctx
, struct cli_trans_state
);
1216 if (state
== NULL
) {
1222 state
->cmd
= trans_cmd
;
1223 state
->num_rsetup
= 0;
1224 state
->rsetup
= NULL
;
1225 ZERO_STRUCT(state
->rparam
);
1226 ZERO_STRUCT(state
->rdata
);
1227 state
->secondary_request_ctx
= NULL
;
1229 if (trans_cmd
== SMBtrans
) {
1230 state
->pipe_name
= talloc_strdup(state
, pipe_name
);
1231 if (state
->pipe_name
== NULL
) {
1235 if (trans_cmd
== SMBtrans2
) {
1238 if (trans_cmd
== SMBnttrans
) {
1239 state
->function
= function
;
1242 state
->flags
= flags
;
1244 if (setup
!= NULL
) {
1245 state
->setup
= (uint16_t *)TALLOC_MEMDUP(
1246 state
, setup
, sizeof(*setup
) * num_setup
);
1247 if (state
->setup
== NULL
) {
1250 state
->num_setup
= num_setup
;
1252 state
->setup
= NULL
;
1253 state
->num_setup
= 0;
1256 state
->max_setup
= max_setup
;
1258 if (param
!= NULL
) {
1259 state
->param
= (uint8_t *)TALLOC_MEMDUP(state
, param
,
1261 if (state
->param
== NULL
) {
1264 state
->num_param
= num_param
;
1266 state
->param
= NULL
;
1267 state
->num_param
= 0;
1270 state
->param_sent
= 0;
1271 state
->rparam
.max
= max_param
;
1274 state
->data
= (uint8_t *)TALLOC_MEMDUP(state
, data
, num_data
);
1275 if (state
->data
== NULL
) {
1278 state
->num_data
= num_data
;
1281 state
->num_data
= 0;
1284 state
->data_sent
= 0;
1285 state
->rdata
.max
= max_data
;
1287 req
= cli_ship_trans(state
, state
);
1292 cli_req
= talloc_get_type_abort(req
->private_data
, struct cli_request
);
1293 cli_req
->recv_helper
.fn
= cli_trans_recv_helper
;
1294 cli_req
->recv_helper
.priv
= state
;
1303 NTSTATUS
cli_trans_recv(struct async_req
*req
, TALLOC_CTX
*mem_ctx
,
1304 uint16_t **setup
, uint8_t *num_setup
,
1305 uint8_t **param
, uint32_t *num_param
,
1306 uint8_t **data
, uint32_t *num_data
)
1308 struct cli_request
*cli_req
= talloc_get_type_abort(
1309 req
->private_data
, struct cli_request
);
1310 struct cli_trans_state
*state
= talloc_get_type_abort(
1311 cli_req
->recv_helper
.priv
, struct cli_trans_state
);
1314 if (async_req_is_nterror(req
, &status
)) {
1318 if (setup
!= NULL
) {
1319 *setup
= talloc_move(mem_ctx
, &state
->rsetup
);
1320 *num_setup
= state
->num_rsetup
;
1322 TALLOC_FREE(state
->rsetup
);
1325 if (param
!= NULL
) {
1326 *param
= talloc_move(mem_ctx
, &state
->rparam
.data
);
1327 *num_param
= state
->rparam
.total
;
1329 TALLOC_FREE(state
->rparam
.data
);
1333 *data
= talloc_move(mem_ctx
, &state
->rdata
.data
);
1334 *num_data
= state
->rdata
.total
;
1336 TALLOC_FREE(state
->rdata
.data
);
1339 return NT_STATUS_OK
;
1342 NTSTATUS
cli_trans(TALLOC_CTX
*mem_ctx
, struct cli_state
*cli
,
1344 const char *pipe_name
, uint16_t fid
, uint16_t function
,
1346 uint16_t *setup
, uint8_t num_setup
, uint8_t max_setup
,
1347 uint8_t *param
, uint32_t num_param
, uint32_t max_param
,
1348 uint8_t *data
, uint32_t num_data
, uint32_t max_data
,
1349 uint16_t **rsetup
, uint8_t *num_rsetup
,
1350 uint8_t **rparam
, uint32_t *num_rparam
,
1351 uint8_t **rdata
, uint32_t *num_rdata
)
1353 TALLOC_CTX
*frame
= talloc_stackframe();
1354 struct event_context
*ev
;
1355 struct async_req
*req
;
1356 NTSTATUS status
= NT_STATUS_NO_MEMORY
;
1358 if (cli
->fd_event
!= NULL
) {
1360 * Can't use sync call while an async call is in flight
1362 cli_set_error(cli
, NT_STATUS_INVALID_PARAMETER
);
1366 ev
= event_context_init(frame
);
1371 req
= cli_trans_send(frame
, ev
, cli
, trans_cmd
,
1372 pipe_name
, fid
, function
, flags
,
1373 setup
, num_setup
, max_setup
,
1374 param
, num_param
, max_param
,
1375 data
, num_data
, max_data
);
1380 while (req
->state
< ASYNC_REQ_DONE
) {
1381 event_loop_once(ev
);
1384 status
= cli_trans_recv(req
, mem_ctx
, rsetup
, num_rsetup
,
1385 rparam
, num_rparam
, rdata
, num_rdata
);