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 char *param, unsigned int lparam, unsigned int mparam,
35 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;
44 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
45 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
47 memset(cli->outbuf,'\0',smb_size);
48 set_message(cli->outbuf,14+lsetup,0,True);
49 SCVAL(cli->outbuf,smb_com,trans);
50 SSVAL(cli->outbuf,smb_tid, cli->cnum);
51 cli_setup_packet(cli);
54 pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE);
57 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
58 outdata = outparam+this_lparam;
61 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
62 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
63 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
64 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
65 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
66 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
67 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
68 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
69 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
70 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
71 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
72 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
73 for (i=0;i<lsetup;i++) /* setup[] */
74 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
75 p = smb_buf(cli->outbuf);
76 if (trans != SMBtrans) {
77 *p++ = 0; /* put in a null smb_name */
78 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
80 if (this_lparam) /* param[] */
81 memcpy(outparam,param,this_lparam);
82 if (this_ldata) /* data[] */
83 memcpy(outdata,data,this_ldata);
84 cli_setup_bcc(cli, outdata+this_ldata);
86 show_msg(cli->outbuf);
87 if (!cli_send_smb(cli))
90 if (this_ldata < ldata || this_lparam < lparam) {
91 /* receive interim response */
92 if (!cli_receive_smb(cli) || cli_is_error(cli))
95 tot_data = this_ldata;
96 tot_param = this_lparam;
98 while (tot_data < ldata || tot_param < lparam) {
99 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
100 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
102 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
103 SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
105 outparam = smb_buf(cli->outbuf);
106 outdata = outparam+this_lparam;
108 /* secondary request */
109 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
110 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
111 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
112 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
113 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
114 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
115 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
116 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
117 if (trans==SMBtrans2)
118 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
119 if (this_lparam) /* param[] */
120 memcpy(outparam,param+tot_param,this_lparam);
121 if (this_ldata) /* data[] */
122 memcpy(outdata,data+tot_data,this_ldata);
123 cli_setup_bcc(cli, outdata+this_ldata);
125 show_msg(cli->outbuf);
126 if (!cli_send_smb(cli))
129 tot_data += this_ldata;
130 tot_param += this_lparam;
137 /****************************************************************************
138 Receive a SMB trans or trans2 response allocating the necessary memory.
139 ****************************************************************************/
141 BOOL cli_receive_trans(struct cli_state *cli,int trans,
142 char **param, unsigned int *param_len,
143 char **data, unsigned int *data_len)
145 unsigned int total_data=0;
146 unsigned int total_param=0;
147 unsigned int this_data,this_param;
152 *data_len = *param_len = 0;
154 if (!cli_receive_smb(cli))
157 show_msg(cli->inbuf);
160 if (CVAL(cli->inbuf,smb_com) != trans) {
161 DEBUG(0,("Expected %s response, got command 0x%02x\n",
162 trans==SMBtrans?"SMBtrans":"SMBtrans2",
163 CVAL(cli->inbuf,smb_com)));
168 * An NT RPC pipe call can return ERRDOS, ERRmoredata
169 * to a trans call. This is not an error and should not
170 * be treated as such.
172 status = cli_nt_error(cli);
174 if (NT_STATUS_IS_ERR(status))
177 /* parse out the lengths */
178 total_data = SVAL(cli->inbuf,smb_tdrcnt);
179 total_param = SVAL(cli->inbuf,smb_tprcnt);
183 tdata = Realloc(*data,total_data);
185 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
192 if (total_param!=0) {
193 tparam = Realloc(*param,total_param);
195 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
203 this_data = SVAL(cli->inbuf,smb_drcnt);
204 this_param = SVAL(cli->inbuf,smb_prcnt);
206 if (this_data + *data_len > total_data ||
207 this_param + *param_len > total_param) {
208 DEBUG(1,("Data overflow in cli_receive_trans\n"));
212 if (this_data + *data_len < this_data ||
213 this_data + *data_len < *data_len ||
214 this_param + *param_len < this_param ||
215 this_param + *param_len < *param_len) {
216 DEBUG(1,("Data overflow in cli_receive_trans\n"));
221 unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
222 unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
224 if (data_offset_out > total_data ||
225 data_offset_out + this_data > total_data ||
226 data_offset_out + this_data < data_offset_out ||
227 data_offset_out + this_data < this_data) {
228 DEBUG(1,("Data overflow in cli_receive_trans\n"));
231 if (data_offset_in > cli->bufsize ||
232 data_offset_in + this_data > cli->bufsize ||
233 data_offset_in + this_data < data_offset_in ||
234 data_offset_in + this_data < this_data) {
235 DEBUG(1,("Data overflow in cli_receive_trans\n"));
239 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
242 unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
243 unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
245 if (param_offset_out > total_param ||
246 param_offset_out + this_param > total_param ||
247 param_offset_out + this_param < param_offset_out ||
248 param_offset_out + this_param < this_param) {
249 DEBUG(1,("Param overflow in cli_receive_trans\n"));
252 if (param_offset_in > cli->bufsize ||
253 param_offset_in + this_param > cli->bufsize ||
254 param_offset_in + this_param < param_offset_in ||
255 param_offset_in + this_param < this_param) {
256 DEBUG(1,("Param overflow in cli_receive_trans\n"));
260 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
262 *data_len += this_data;
263 *param_len += this_param;
265 if (total_data <= *data_len && total_param <= *param_len)
268 if (!cli_receive_smb(cli))
271 show_msg(cli->inbuf);
274 if (CVAL(cli->inbuf,smb_com) != trans) {
275 DEBUG(0,("Expected %s response, got command 0x%02x\n",
276 trans==SMBtrans?"SMBtrans":"SMBtrans2",
277 CVAL(cli->inbuf,smb_com)));
280 if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
284 /* parse out the total lengths again - they can shrink! */
285 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
286 total_data = SVAL(cli->inbuf,smb_tdrcnt);
287 if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
288 total_param = SVAL(cli->inbuf,smb_tprcnt);
290 if (total_data <= *data_len && total_param <= *param_len)
298 /****************************************************************************
299 Send a SMB nttrans request.
300 ****************************************************************************/
302 BOOL cli_send_nt_trans(struct cli_state *cli,
305 uint16 *setup, unsigned int lsetup, unsigned int msetup,
306 char *param, unsigned int lparam, unsigned int mparam,
307 char *data, unsigned int ldata, unsigned int mdata)
310 unsigned int this_ldata,this_lparam;
311 unsigned int tot_data=0,tot_param=0;
312 char *outdata,*outparam;
314 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
315 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
317 memset(cli->outbuf,'\0',smb_size);
318 set_message(cli->outbuf,19+lsetup,0,True);
319 SCVAL(cli->outbuf,smb_com,SMBnttrans);
320 SSVAL(cli->outbuf,smb_tid, cli->cnum);
321 cli_setup_packet(cli);
323 outparam = smb_buf(cli->outbuf)+3;
324 outdata = outparam+this_lparam;
326 /* primary request */
327 SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
328 SCVAL(cli->outbuf,smb_nt_Flags,flags);
329 SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
330 SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
331 SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
332 SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
333 SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
334 SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
335 SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
336 SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
337 SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
338 SIVAL(cli->outbuf,smb_nt_Function, function);
339 for (i=0;i<lsetup;i++) /* setup[] */
340 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
342 if (this_lparam) /* param[] */
343 memcpy(outparam,param,this_lparam);
344 if (this_ldata) /* data[] */
345 memcpy(outdata,data,this_ldata);
347 cli_setup_bcc(cli, outdata+this_ldata);
349 show_msg(cli->outbuf);
350 if (!cli_send_smb(cli))
353 if (this_ldata < ldata || this_lparam < lparam) {
354 /* receive interim response */
355 if (!cli_receive_smb(cli) || cli_is_error(cli))
358 tot_data = this_ldata;
359 tot_param = this_lparam;
361 while (tot_data < ldata || tot_param < lparam) {
362 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
363 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
365 set_message(cli->outbuf,18,0,True);
366 SCVAL(cli->outbuf,smb_com,SMBnttranss);
368 /* XXX - these should probably be aligned */
369 outparam = smb_buf(cli->outbuf);
370 outdata = outparam+this_lparam;
372 /* secondary request */
373 SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
374 SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
375 SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
376 SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
377 SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
378 SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
379 SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
380 SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
381 if (this_lparam) /* param[] */
382 memcpy(outparam,param+tot_param,this_lparam);
383 if (this_ldata) /* data[] */
384 memcpy(outdata,data+tot_data,this_ldata);
385 cli_setup_bcc(cli, outdata+this_ldata);
387 show_msg(cli->outbuf);
388 if (!cli_send_smb(cli))
391 tot_data += this_ldata;
392 tot_param += this_lparam;
401 /****************************************************************************
402 receive a SMB nttrans response allocating the necessary memory
403 ****************************************************************************/
405 BOOL cli_receive_nt_trans(struct cli_state *cli,
406 char **param, unsigned int *param_len,
407 char **data, unsigned int *data_len)
409 unsigned int total_data=0;
410 unsigned int total_param=0;
411 unsigned int this_data,this_param;
417 *data_len = *param_len = 0;
419 if (!cli_receive_smb(cli))
422 show_msg(cli->inbuf);
425 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
426 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
427 CVAL(cli->inbuf,smb_com)));
432 * An NT RPC pipe call can return ERRDOS, ERRmoredata
433 * to a trans call. This is not an error and should not
434 * be treated as such.
436 if (cli_is_dos_error(cli)) {
437 cli_dos_error(cli, &eclass, &ecode);
438 if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
442 /* parse out the lengths */
443 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
444 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
448 tdata = Realloc(*data,total_data);
450 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
458 tparam = Realloc(*param,total_param);
460 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
468 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
469 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
471 if (this_data + *data_len > total_data ||
472 this_param + *param_len > total_param) {
473 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
477 if (this_data + *data_len < this_data ||
478 this_data + *data_len < *data_len ||
479 this_param + *param_len < this_param ||
480 this_param + *param_len < *param_len) {
481 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
486 unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
487 unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
489 if (data_offset_out > total_data ||
490 data_offset_out + this_data > total_data ||
491 data_offset_out + this_data < data_offset_out ||
492 data_offset_out + this_data < this_data) {
493 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
496 if (data_offset_in > cli->bufsize ||
497 data_offset_in + this_data > cli->bufsize ||
498 data_offset_in + this_data < data_offset_in ||
499 data_offset_in + this_data < this_data) {
500 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
504 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
508 unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
509 unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
511 if (param_offset_out > total_param ||
512 param_offset_out + this_param > total_param ||
513 param_offset_out + this_param < param_offset_out ||
514 param_offset_out + this_param < this_param) {
515 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
518 if (param_offset_in > cli->bufsize ||
519 param_offset_in + this_param > cli->bufsize ||
520 param_offset_in + this_param < param_offset_in ||
521 param_offset_in + this_param < this_param) {
522 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
526 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
529 *data_len += this_data;
530 *param_len += this_param;
532 if (total_data <= *data_len && total_param <= *param_len)
535 if (!cli_receive_smb(cli))
538 show_msg(cli->inbuf);
541 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
542 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
543 CVAL(cli->inbuf,smb_com)));
546 if (cli_is_dos_error(cli)) {
547 cli_dos_error(cli, &eclass, &ecode);
548 if(cli->nt_pipe_fnum == 0 ||
549 !(eclass == ERRDOS && ecode == ERRmoredata))
552 /* parse out the total lengths again - they can shrink! */
553 if (SVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
554 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
555 if (SVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
556 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
558 if (total_data <= *data_len && total_param <= *param_len)