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);
139 * Save the mid we're using. We need this for finding
144 show_msg(cli->outbuf);
145 if (!cli_send_smb(cli)) {
146 client_set_trans_sign_state_off(cli, mid);
150 /* Ensure we use the same mid for the secondaries. */
153 tot_data += this_ldata;
154 tot_param += this_lparam;
161 /****************************************************************************
162 Receive a SMB trans or trans2 response allocating the necessary memory.
163 ****************************************************************************/
165 bool cli_receive_trans(struct cli_state *cli,int trans,
166 char **param, unsigned int *param_len,
167 char **data, unsigned int *data_len)
169 unsigned int total_data=0;
170 unsigned int total_param=0;
171 unsigned int this_data,this_param;
175 *data_len = *param_len = 0;
177 if (!cli_receive_smb(cli)) {
181 show_msg(cli->inbuf);
184 if (CVAL(cli->inbuf,smb_com) != trans) {
185 DEBUG(0,("Expected %s response, got command 0x%02x\n",
186 trans==SMBtrans?"SMBtrans":"SMBtrans2",
187 CVAL(cli->inbuf,smb_com)));
192 * An NT RPC pipe call can return ERRDOS, ERRmoredata
193 * to a trans call. This is not an error and should not
194 * be treated as such. Note that STATUS_NO_MORE_FILES is
195 * returned when a trans2 findfirst/next finishes.
196 * When setting up an encrypted transport we can also
197 * see NT_STATUS_MORE_PROCESSING_REQUIRED here.
199 * Vista returns NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT if the folder
200 * "<share>/Users/All Users" is enumerated. This is a special pseudo
201 * folder, and the response does not have parameters (nor a parameter
204 status = cli_nt_error(cli);
206 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
207 if (NT_STATUS_IS_ERR(status) ||
208 NT_STATUS_EQUAL(status,STATUS_NO_MORE_FILES) ||
209 NT_STATUS_EQUAL(status,NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
214 /* parse out the lengths */
215 total_data = SVAL(cli->inbuf,smb_tdrcnt);
216 total_param = SVAL(cli->inbuf,smb_tprcnt);
220 /* We know adding 2 is safe as total_data is an
222 *data = (char *)SMB_REALLOC(*data,total_data+2);
224 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
229 if (total_param!=0) {
230 /* We know adding 2 is safe as total_param is an
232 *param = (char *)SMB_REALLOC(*param,total_param+2);
234 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
240 this_data = SVAL(cli->inbuf,smb_drcnt);
241 this_param = SVAL(cli->inbuf,smb_prcnt);
243 if (this_data + *data_len > total_data ||
244 this_param + *param_len > total_param) {
245 DEBUG(1,("Data overflow in cli_receive_trans\n"));
249 if (this_data + *data_len < this_data ||
250 this_data + *data_len < *data_len ||
251 this_param + *param_len < this_param ||
252 this_param + *param_len < *param_len) {
253 DEBUG(1,("Data overflow in cli_receive_trans\n"));
258 unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
259 unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
261 if (data_offset_out > total_data ||
262 data_offset_out + this_data > total_data ||
263 data_offset_out + this_data < data_offset_out ||
264 data_offset_out + this_data < this_data) {
265 DEBUG(1,("Data overflow in cli_receive_trans\n"));
268 if (data_offset_in > cli->bufsize ||
269 data_offset_in + this_data > cli->bufsize ||
270 data_offset_in + this_data < data_offset_in ||
271 data_offset_in + this_data < this_data) {
272 DEBUG(1,("Data overflow in cli_receive_trans\n"));
276 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
279 unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
280 unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
282 if (param_offset_out > total_param ||
283 param_offset_out + this_param > total_param ||
284 param_offset_out + this_param < param_offset_out ||
285 param_offset_out + this_param < this_param) {
286 DEBUG(1,("Param overflow in cli_receive_trans\n"));
289 if (param_offset_in > cli->bufsize ||
290 param_offset_in + this_param > cli->bufsize ||
291 param_offset_in + this_param < param_offset_in ||
292 param_offset_in + this_param < this_param) {
293 DEBUG(1,("Param overflow in cli_receive_trans\n"));
297 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
299 *data_len += this_data;
300 *param_len += this_param;
302 if (total_data <= *data_len && total_param <= *param_len) {
307 if (!cli_receive_smb(cli)) {
311 show_msg(cli->inbuf);
314 if (CVAL(cli->inbuf,smb_com) != trans) {
315 DEBUG(0,("Expected %s response, got command 0x%02x\n",
316 trans==SMBtrans?"SMBtrans":"SMBtrans2",
317 CVAL(cli->inbuf,smb_com)));
320 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
321 if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
326 /* parse out the total lengths again - they can shrink! */
327 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
328 total_data = SVAL(cli->inbuf,smb_tdrcnt);
329 if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
330 total_param = SVAL(cli->inbuf,smb_tprcnt);
332 if (total_data <= *data_len && total_param <= *param_len) {
341 /* Ensure the last 2 bytes of param and data are 2 null
342 * bytes. These are malloc'ed, but not included in any
343 * length counts. This allows cli_XX string reading functions
344 * to safely null terminate. */
346 SSVAL(*data,total_data,0);
349 SSVAL(*param,total_param,0);
353 client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
357 /****************************************************************************
358 Send a SMB nttrans request.
359 ****************************************************************************/
361 bool cli_send_nt_trans(struct cli_state *cli,
364 uint16 *setup, unsigned int lsetup, unsigned int msetup,
365 char *param, unsigned int lparam, unsigned int mparam,
366 char *data, unsigned int ldata, unsigned int mdata)
369 unsigned int this_ldata,this_lparam;
370 unsigned int tot_data=0,tot_param=0;
372 char *outdata,*outparam;
374 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
375 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
377 memset(cli->outbuf,'\0',smb_size);
378 cli_set_message(cli->outbuf,19+lsetup,0,True);
379 SCVAL(cli->outbuf,smb_com,SMBnttrans);
380 SSVAL(cli->outbuf,smb_tid, cli->cnum);
381 cli_setup_packet(cli);
384 * Save the mid we're using. We need this for finding
390 outparam = smb_buf(cli->outbuf)+3;
391 outdata = outparam+this_lparam;
393 /* primary request */
394 SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
395 SCVAL(cli->outbuf,smb_nt_Flags,flags);
396 SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
397 SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
398 SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
399 SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
400 SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
401 SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
402 SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
403 SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
404 SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
405 SIVAL(cli->outbuf,smb_nt_Function, function);
406 for (i=0;i<lsetup;i++) /* setup[] */
407 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
409 if (this_lparam) /* param[] */
410 memcpy(outparam,param,this_lparam);
411 if (this_ldata) /* data[] */
412 memcpy(outdata,data,this_ldata);
414 cli_setup_bcc(cli, outdata+this_ldata);
416 show_msg(cli->outbuf);
417 if (!cli_send_smb(cli)) {
421 /* Note we're in a trans state. Save the sequence
422 * numbers for replies. */
423 client_set_trans_sign_state_on(cli, mid);
425 if (this_ldata < ldata || this_lparam < lparam) {
426 /* receive interim response */
427 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
428 client_set_trans_sign_state_off(cli, mid);
432 tot_data = this_ldata;
433 tot_param = this_lparam;
435 while (tot_data < ldata || tot_param < lparam) {
436 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
437 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
439 cli_set_message(cli->outbuf,18,0,True);
440 SCVAL(cli->outbuf,smb_com,SMBnttranss);
442 /* XXX - these should probably be aligned */
443 outparam = smb_buf(cli->outbuf);
444 outdata = outparam+this_lparam;
446 /* secondary request */
447 SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
448 SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
449 SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
450 SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
451 SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
452 SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
453 SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
454 SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
455 if (this_lparam) /* param[] */
456 memcpy(outparam,param+tot_param,this_lparam);
457 if (this_ldata) /* data[] */
458 memcpy(outdata,data+tot_data,this_ldata);
459 cli_setup_bcc(cli, outdata+this_ldata);
462 * Save the mid we're using. We need this for finding
467 show_msg(cli->outbuf);
469 if (!cli_send_smb(cli)) {
470 client_set_trans_sign_state_off(cli, mid);
474 /* Ensure we use the same mid for the secondaries. */
477 tot_data += this_ldata;
478 tot_param += this_lparam;
485 /****************************************************************************
486 Receive a SMB nttrans response allocating the necessary memory.
487 ****************************************************************************/
489 bool cli_receive_nt_trans(struct cli_state *cli,
490 char **param, unsigned int *param_len,
491 char **data, unsigned int *data_len)
493 unsigned int total_data=0;
494 unsigned int total_param=0;
495 unsigned int this_data,this_param;
500 *data_len = *param_len = 0;
502 if (!cli_receive_smb(cli)) {
506 show_msg(cli->inbuf);
509 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
510 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
511 CVAL(cli->inbuf,smb_com)));
516 * An NT RPC pipe call can return ERRDOS, ERRmoredata
517 * to a trans call. This is not an error and should not
518 * be treated as such.
520 if (cli_is_dos_error(cli)) {
521 cli_dos_error(cli, &eclass, &ecode);
522 if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
528 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
530 if (cli_is_nt_error(cli)) {
531 if (!NT_STATUS_EQUAL(cli_nt_error(cli),
532 NT_STATUS_BUFFER_TOO_SMALL)) {
537 /* parse out the lengths */
538 total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
539 total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
540 /* Only allow 16 megs. */
541 if (total_param > 16*1024*1024) {
542 DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n",
546 if (total_data > 16*1024*1024) {
547 DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n",
554 /* We know adding 2 is safe as total_data is less
555 * than 16mb (above). */
556 *data = (char *)SMB_REALLOC(*data,total_data+2);
558 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
564 /* We know adding 2 is safe as total_param is less
565 * than 16mb (above). */
566 *param = (char *)SMB_REALLOC(*param,total_param+2);
568 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
574 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
575 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
577 if (this_data + *data_len > total_data ||
578 this_param + *param_len > total_param) {
579 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
583 if (this_data + *data_len < this_data ||
584 this_data + *data_len < *data_len ||
585 this_param + *param_len < this_param ||
586 this_param + *param_len < *param_len) {
587 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
592 unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
593 unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
595 if (data_offset_out > total_data ||
596 data_offset_out + this_data > total_data ||
597 data_offset_out + this_data < data_offset_out ||
598 data_offset_out + this_data < this_data) {
599 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
602 if (data_offset_in > cli->bufsize ||
603 data_offset_in + this_data > cli->bufsize ||
604 data_offset_in + this_data < data_offset_in ||
605 data_offset_in + this_data < this_data) {
606 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
610 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
614 unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
615 unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
617 if (param_offset_out > total_param ||
618 param_offset_out + this_param > total_param ||
619 param_offset_out + this_param < param_offset_out ||
620 param_offset_out + this_param < this_param) {
621 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
624 if (param_offset_in > cli->bufsize ||
625 param_offset_in + this_param > cli->bufsize ||
626 param_offset_in + this_param < param_offset_in ||
627 param_offset_in + this_param < this_param) {
628 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
632 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
635 *data_len += this_data;
636 *param_len += this_param;
638 if (total_data <= *data_len && total_param <= *param_len) {
643 if (!cli_receive_smb(cli)) {
647 show_msg(cli->inbuf);
650 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
651 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
652 CVAL(cli->inbuf,smb_com)));
655 if (cli_is_dos_error(cli)) {
656 cli_dos_error(cli, &eclass, &ecode);
657 if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
662 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
664 if (cli_is_nt_error(cli)) {
665 if (!NT_STATUS_EQUAL(cli_nt_error(cli),
666 NT_STATUS_BUFFER_TOO_SMALL)) {
671 /* parse out the total lengths again - they can shrink! */
672 if (IVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
673 total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
674 if (IVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
675 total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
677 if (total_data <= *data_len && total_param <= *param_len) {
686 /* Ensure the last 2 bytes of param and data are 2 null
687 * bytes. These are malloc'ed, but not included in any
688 * length counts. This allows cli_XX string reading functions
689 * to safely null terminate. */
691 SSVAL(*data,total_data,0);
694 SSVAL(*param,total_param,0);
698 client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));