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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /****************************************************************************
27 Send a SMB trans or trans2 request.
28 ****************************************************************************/
30 BOOL cli_send_trans(struct cli_state *cli, int trans,
31 const char *pipe_name,
33 uint16 *setup, unsigned int lsetup, unsigned int msetup,
34 const char *param, unsigned int lparam, unsigned int mparam,
35 const char *data, unsigned int ldata, unsigned int mdata)
38 unsigned int this_ldata,this_lparam;
39 unsigned int tot_data=0,tot_param=0;
40 char *outdata,*outparam;
45 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
46 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
48 memset(cli->outbuf,'\0',smb_size);
49 set_message(cli->outbuf,14+lsetup,0,True);
50 SCVAL(cli->outbuf,smb_com,trans);
51 SSVAL(cli->outbuf,smb_tid, cli->cnum);
52 cli_setup_packet(cli);
56 pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE);
59 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
60 outdata = outparam+this_lparam;
63 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
64 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
65 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
66 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
67 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
68 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
69 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
70 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
71 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
72 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
73 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
74 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
75 for (i=0;i<lsetup;i++) /* setup[] */
76 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
77 p = smb_buf(cli->outbuf);
78 if (trans != SMBtrans) {
79 *p++ = 0; /* put in a null smb_name */
80 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
82 if (this_lparam) /* param[] */
83 memcpy(outparam,param,this_lparam);
84 if (this_ldata) /* data[] */
85 memcpy(outdata,data,this_ldata);
86 cli_setup_bcc(cli, outdata+this_ldata);
88 show_msg(cli->outbuf);
90 cli_signing_trans_start(cli);
91 if (!cli_send_smb(cli))
94 if (this_ldata < ldata || this_lparam < lparam) {
95 /* receive interim response */
96 if (!cli_receive_smb(cli) || cli_is_error(cli))
99 tot_data = this_ldata;
100 tot_param = this_lparam;
102 while (tot_data < ldata || tot_param < lparam) {
103 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
104 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
106 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
107 SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
109 outparam = smb_buf(cli->outbuf);
110 outdata = outparam+this_lparam;
112 /* secondary request */
113 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
114 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
115 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
116 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
117 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
118 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
119 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
120 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
121 if (trans==SMBtrans2)
122 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
123 if (this_lparam) /* param[] */
124 memcpy(outparam,param+tot_param,this_lparam);
125 if (this_ldata) /* data[] */
126 memcpy(outdata,data+tot_data,this_ldata);
127 cli_setup_bcc(cli, outdata+this_ldata);
129 /* Ensure this packet has the same MID as
130 * the primary. Important in signing. JRA. */
133 show_msg(cli->outbuf);
134 if (!cli_send_smb(cli))
137 tot_data += this_ldata;
138 tot_param += this_lparam;
145 /****************************************************************************
146 Receive a SMB trans or trans2 response allocating the necessary memory.
147 ****************************************************************************/
149 BOOL cli_receive_trans(struct cli_state *cli,int trans,
150 char **param, unsigned int *param_len,
151 char **data, unsigned int *data_len)
153 unsigned int total_data=0;
154 unsigned int total_param=0;
155 unsigned int this_data,this_param;
160 *data_len = *param_len = 0;
162 if (!cli_receive_smb(cli))
165 show_msg(cli->inbuf);
168 if (CVAL(cli->inbuf,smb_com) != trans) {
169 DEBUG(0,("Expected %s response, got command 0x%02x\n",
170 trans==SMBtrans?"SMBtrans":"SMBtrans2",
171 CVAL(cli->inbuf,smb_com)));
176 * An NT RPC pipe call can return ERRDOS, ERRmoredata
177 * to a trans call. This is not an error and should not
178 * be treated as such.
180 status = cli_nt_error(cli);
182 if (NT_STATUS_IS_ERR(status))
185 /* parse out the lengths */
186 total_data = SVAL(cli->inbuf,smb_tdrcnt);
187 total_param = SVAL(cli->inbuf,smb_tprcnt);
191 tdata = Realloc(*data,total_data);
193 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
200 if (total_param!=0) {
201 tparam = Realloc(*param,total_param);
203 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
211 this_data = SVAL(cli->inbuf,smb_drcnt);
212 this_param = SVAL(cli->inbuf,smb_prcnt);
214 if (this_data + *data_len > total_data ||
215 this_param + *param_len > total_param) {
216 DEBUG(1,("Data overflow in cli_receive_trans\n"));
220 if (this_data + *data_len < this_data ||
221 this_data + *data_len < *data_len ||
222 this_param + *param_len < this_param ||
223 this_param + *param_len < *param_len) {
224 DEBUG(1,("Data overflow in cli_receive_trans\n"));
229 unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
230 unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
232 if (data_offset_out > total_data ||
233 data_offset_out + this_data > total_data ||
234 data_offset_out + this_data < data_offset_out ||
235 data_offset_out + this_data < this_data) {
236 DEBUG(1,("Data overflow in cli_receive_trans\n"));
239 if (data_offset_in > cli->bufsize ||
240 data_offset_in + this_data > cli->bufsize ||
241 data_offset_in + this_data < data_offset_in ||
242 data_offset_in + this_data < this_data) {
243 DEBUG(1,("Data overflow in cli_receive_trans\n"));
247 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
250 unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
251 unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
253 if (param_offset_out > total_param ||
254 param_offset_out + this_param > total_param ||
255 param_offset_out + this_param < param_offset_out ||
256 param_offset_out + this_param < this_param) {
257 DEBUG(1,("Param overflow in cli_receive_trans\n"));
260 if (param_offset_in > cli->bufsize ||
261 param_offset_in + this_param > cli->bufsize ||
262 param_offset_in + this_param < param_offset_in ||
263 param_offset_in + this_param < this_param) {
264 DEBUG(1,("Param overflow in cli_receive_trans\n"));
268 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
270 *data_len += this_data;
271 *param_len += this_param;
273 if (total_data <= *data_len && total_param <= *param_len)
276 if (!cli_receive_smb(cli))
279 show_msg(cli->inbuf);
282 if (CVAL(cli->inbuf,smb_com) != trans) {
283 DEBUG(0,("Expected %s response, got command 0x%02x\n",
284 trans==SMBtrans?"SMBtrans":"SMBtrans2",
285 CVAL(cli->inbuf,smb_com)));
288 if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
292 /* parse out the total lengths again - they can shrink! */
293 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
294 total_data = SVAL(cli->inbuf,smb_tdrcnt);
295 if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
296 total_param = SVAL(cli->inbuf,smb_tprcnt);
298 if (total_data <= *data_len && total_param <= *param_len)
303 cli_signing_trans_stop(cli);
307 /****************************************************************************
308 Send a SMB nttrans request.
309 ****************************************************************************/
311 BOOL cli_send_nt_trans(struct cli_state *cli,
314 uint16 *setup, unsigned int lsetup, unsigned int msetup,
315 char *param, unsigned int lparam, unsigned int mparam,
316 char *data, unsigned int ldata, unsigned int mdata)
319 unsigned int this_ldata,this_lparam;
320 unsigned int tot_data=0,tot_param=0;
322 char *outdata,*outparam;
324 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
325 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
327 memset(cli->outbuf,'\0',smb_size);
328 set_message(cli->outbuf,19+lsetup,0,True);
329 SCVAL(cli->outbuf,smb_com,SMBnttrans);
330 SSVAL(cli->outbuf,smb_tid, cli->cnum);
331 cli_setup_packet(cli);
334 outparam = smb_buf(cli->outbuf)+3;
335 outdata = outparam+this_lparam;
337 /* primary request */
338 SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
339 SCVAL(cli->outbuf,smb_nt_Flags,flags);
340 SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
341 SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
342 SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
343 SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
344 SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
345 SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
346 SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
347 SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
348 SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
349 SIVAL(cli->outbuf,smb_nt_Function, function);
350 for (i=0;i<lsetup;i++) /* setup[] */
351 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
353 if (this_lparam) /* param[] */
354 memcpy(outparam,param,this_lparam);
355 if (this_ldata) /* data[] */
356 memcpy(outdata,data,this_ldata);
358 cli_setup_bcc(cli, outdata+this_ldata);
360 show_msg(cli->outbuf);
361 cli_signing_trans_start(cli);
362 if (!cli_send_smb(cli))
365 if (this_ldata < ldata || this_lparam < lparam) {
366 /* receive interim response */
367 if (!cli_receive_smb(cli) || cli_is_error(cli))
370 tot_data = this_ldata;
371 tot_param = this_lparam;
373 while (tot_data < ldata || tot_param < lparam) {
374 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
375 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
377 set_message(cli->outbuf,18,0,True);
378 SCVAL(cli->outbuf,smb_com,SMBnttranss);
380 /* XXX - these should probably be aligned */
381 outparam = smb_buf(cli->outbuf);
382 outdata = outparam+this_lparam;
384 /* secondary request */
385 SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
386 SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
387 SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
388 SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
389 SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
390 SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
391 SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
392 SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
393 if (this_lparam) /* param[] */
394 memcpy(outparam,param+tot_param,this_lparam);
395 if (this_ldata) /* data[] */
396 memcpy(outdata,data+tot_data,this_ldata);
397 cli_setup_bcc(cli, outdata+this_ldata);
399 /* Ensure this packet has the same MID as
400 * the primary. Important in signing. JRA. */
403 show_msg(cli->outbuf);
405 if (!cli_send_smb(cli))
408 tot_data += this_ldata;
409 tot_param += this_lparam;
418 /****************************************************************************
419 receive a SMB nttrans response allocating the necessary memory
420 ****************************************************************************/
422 BOOL cli_receive_nt_trans(struct cli_state *cli,
423 char **param, unsigned int *param_len,
424 char **data, unsigned int *data_len)
426 unsigned int total_data=0;
427 unsigned int total_param=0;
428 unsigned int this_data,this_param;
434 *data_len = *param_len = 0;
436 if (!cli_receive_smb(cli))
439 show_msg(cli->inbuf);
442 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
443 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
444 CVAL(cli->inbuf,smb_com)));
449 * An NT RPC pipe call can return ERRDOS, ERRmoredata
450 * to a trans call. This is not an error and should not
451 * be treated as such.
453 if (cli_is_dos_error(cli)) {
454 cli_dos_error(cli, &eclass, &ecode);
455 if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
459 /* parse out the lengths */
460 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
461 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
465 tdata = Realloc(*data,total_data);
467 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
475 tparam = Realloc(*param,total_param);
477 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
485 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
486 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
488 if (this_data + *data_len > total_data ||
489 this_param + *param_len > total_param) {
490 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
494 if (this_data + *data_len < this_data ||
495 this_data + *data_len < *data_len ||
496 this_param + *param_len < this_param ||
497 this_param + *param_len < *param_len) {
498 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
503 unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
504 unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
506 if (data_offset_out > total_data ||
507 data_offset_out + this_data > total_data ||
508 data_offset_out + this_data < data_offset_out ||
509 data_offset_out + this_data < this_data) {
510 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
513 if (data_offset_in > cli->bufsize ||
514 data_offset_in + this_data > cli->bufsize ||
515 data_offset_in + this_data < data_offset_in ||
516 data_offset_in + this_data < this_data) {
517 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
521 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
525 unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
526 unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
528 if (param_offset_out > total_param ||
529 param_offset_out + this_param > total_param ||
530 param_offset_out + this_param < param_offset_out ||
531 param_offset_out + this_param < this_param) {
532 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
535 if (param_offset_in > cli->bufsize ||
536 param_offset_in + this_param > cli->bufsize ||
537 param_offset_in + this_param < param_offset_in ||
538 param_offset_in + this_param < this_param) {
539 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
543 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
546 *data_len += this_data;
547 *param_len += this_param;
549 if (total_data <= *data_len && total_param <= *param_len)
552 if (!cli_receive_smb(cli))
555 show_msg(cli->inbuf);
558 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
559 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
560 CVAL(cli->inbuf,smb_com)));
563 if (cli_is_dos_error(cli)) {
564 cli_dos_error(cli, &eclass, &ecode);
565 if(cli->nt_pipe_fnum == 0 ||
566 !(eclass == ERRDOS && ecode == ERRmoredata))
569 /* parse out the total lengths again - they can shrink! */
570 if (SVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
571 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
572 if (SVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
573 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
575 if (total_data <= *data_len && total_param <= *param_len)
579 cli_signing_trans_stop(cli);