docs: fix two typos in the mount.cifs manpage
[Samba.git] / source / libsmb / clitrans.c
blob441f5a0a8925b493ce27859fe6ee3de552fd0cce
1 /*
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.
21 #include "includes.h"
24 /****************************************************************************
25 Send a SMB trans or trans2 request.
26 ****************************************************************************/
28 BOOL cli_send_trans(struct cli_state *cli, int trans,
29 const char *pipe_name,
30 int fid, int flags,
31 uint16 *setup, unsigned int lsetup, unsigned int msetup,
32 const char *param, unsigned int lparam, unsigned int mparam,
33 const char *data, unsigned int ldata, unsigned int mdata)
35 unsigned int i;
36 unsigned int this_ldata,this_lparam;
37 unsigned int tot_data=0,tot_param=0;
38 char *outdata,*outparam;
39 char *p;
40 int pipe_name_len=0;
41 uint16 mid;
43 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
44 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
46 memset(cli->outbuf,'\0',smb_size);
47 set_message(cli->outbuf,14+lsetup,0,True);
48 SCVAL(cli->outbuf,smb_com,trans);
49 SSVAL(cli->outbuf,smb_tid, cli->cnum);
50 cli_setup_packet(cli);
53 * Save the mid we're using. We need this for finding
54 * signing replies.
57 mid = cli->mid;
59 if (pipe_name) {
60 pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE);
63 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
64 outdata = outparam+this_lparam;
66 /* primary request */
67 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
68 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
69 SSVAL(cli->outbuf,smb_mprcnt,mparam); /* mprcnt */
70 SSVAL(cli->outbuf,smb_mdrcnt,mdata); /* mdrcnt */
71 SCVAL(cli->outbuf,smb_msrcnt,msetup); /* msrcnt */
72 SSVAL(cli->outbuf,smb_flags,flags); /* flags */
73 SIVAL(cli->outbuf,smb_timeout,0); /* timeout */
74 SSVAL(cli->outbuf,smb_pscnt,this_lparam); /* pscnt */
75 SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
76 SSVAL(cli->outbuf,smb_dscnt,this_ldata); /* dscnt */
77 SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
78 SCVAL(cli->outbuf,smb_suwcnt,lsetup); /* suwcnt */
79 for (i=0;i<lsetup;i++) /* setup[] */
80 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
81 p = smb_buf(cli->outbuf);
82 if (trans != SMBtrans) {
83 *p++ = 0; /* put in a null smb_name */
84 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
86 if (this_lparam) /* param[] */
87 memcpy(outparam,param,this_lparam);
88 if (this_ldata) /* data[] */
89 memcpy(outdata,data,this_ldata);
90 cli_setup_bcc(cli, outdata+this_ldata);
92 show_msg(cli->outbuf);
94 if (!cli_send_smb(cli)) {
95 return False;
98 /* Note we're in a trans state. Save the sequence
99 * numbers for replies. */
100 client_set_trans_sign_state_on(cli, mid);
102 if (this_ldata < ldata || this_lparam < lparam) {
103 /* receive interim response */
104 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
105 client_set_trans_sign_state_off(cli, mid);
106 return(False);
109 tot_data = this_ldata;
110 tot_param = this_lparam;
112 while (tot_data < ldata || tot_param < lparam) {
113 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
114 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
116 client_set_trans_sign_state_off(cli, mid);
117 client_set_trans_sign_state_on(cli, mid);
119 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
120 SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
122 outparam = smb_buf(cli->outbuf);
123 outdata = outparam+this_lparam;
125 /* secondary request */
126 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
127 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
128 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
129 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
130 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
131 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
132 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
133 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
134 if (trans==SMBtrans2)
135 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
136 if (this_lparam) /* param[] */
137 memcpy(outparam,param+tot_param,this_lparam);
138 if (this_ldata) /* data[] */
139 memcpy(outdata,data+tot_data,this_ldata);
140 cli_setup_bcc(cli, outdata+this_ldata);
143 * Save the mid we're using. We need this for finding
144 * signing replies.
146 mid = cli->mid;
148 show_msg(cli->outbuf);
149 if (!cli_send_smb(cli)) {
150 client_set_trans_sign_state_off(cli, mid);
151 return False;
154 /* Ensure we use the same mid for the secondaries. */
155 cli->mid = mid;
157 tot_data += this_ldata;
158 tot_param += this_lparam;
162 return(True);
165 /****************************************************************************
166 Receive a SMB trans or trans2 response allocating the necessary memory.
167 ****************************************************************************/
169 BOOL cli_receive_trans(struct cli_state *cli,int trans,
170 char **param, unsigned int *param_len,
171 char **data, unsigned int *data_len)
173 unsigned int total_data=0;
174 unsigned int total_param=0;
175 unsigned int this_data,this_param;
176 NTSTATUS status;
177 BOOL ret = False;
179 *data_len = *param_len = 0;
181 if (!cli_receive_smb(cli)) {
182 return False;
185 show_msg(cli->inbuf);
187 /* sanity check */
188 if (CVAL(cli->inbuf,smb_com) != trans) {
189 DEBUG(0,("Expected %s response, got command 0x%02x\n",
190 trans==SMBtrans?"SMBtrans":"SMBtrans2",
191 CVAL(cli->inbuf,smb_com)));
192 return False;
196 * An NT RPC pipe call can return ERRDOS, ERRmoredata
197 * to a trans call. This is not an error and should not
198 * be treated as such. Note that STATUS_NO_MORE_FILES is
199 * returned when a trans2 findfirst/next finishes.
201 status = cli_nt_error(cli);
203 if (NT_STATUS_IS_ERR(status) ||
204 NT_STATUS_EQUAL(status,STATUS_NO_MORE_FILES) ||
205 NT_STATUS_EQUAL(status,STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
206 goto out;
209 /* parse out the lengths */
210 total_data = SVAL(cli->inbuf,smb_tdrcnt);
211 total_param = SVAL(cli->inbuf,smb_tprcnt);
213 /* allocate it */
214 if (total_data!=0) {
215 *data = (char *)SMB_REALLOC(*data,total_data);
216 if (!(*data)) {
217 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
218 goto out;
222 if (total_param!=0) {
223 *param = (char *)SMB_REALLOC(*param,total_param);
224 if (!(*param)) {
225 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
226 goto out;
230 for (;;) {
231 this_data = SVAL(cli->inbuf,smb_drcnt);
232 this_param = SVAL(cli->inbuf,smb_prcnt);
234 if (this_data + *data_len > total_data ||
235 this_param + *param_len > total_param) {
236 DEBUG(1,("Data overflow in cli_receive_trans\n"));
237 goto out;
240 if (this_data + *data_len < this_data ||
241 this_data + *data_len < *data_len ||
242 this_param + *param_len < this_param ||
243 this_param + *param_len < *param_len) {
244 DEBUG(1,("Data overflow in cli_receive_trans\n"));
245 goto out;
248 if (this_data) {
249 unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
250 unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
252 if (data_offset_out > total_data ||
253 data_offset_out + this_data > total_data ||
254 data_offset_out + this_data < data_offset_out ||
255 data_offset_out + this_data < this_data) {
256 DEBUG(1,("Data overflow in cli_receive_trans\n"));
257 goto out;
259 if (data_offset_in > cli->bufsize ||
260 data_offset_in + this_data > cli->bufsize ||
261 data_offset_in + this_data < data_offset_in ||
262 data_offset_in + this_data < this_data) {
263 DEBUG(1,("Data overflow in cli_receive_trans\n"));
264 goto out;
267 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
269 if (this_param) {
270 unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
271 unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
273 if (param_offset_out > total_param ||
274 param_offset_out + this_param > total_param ||
275 param_offset_out + this_param < param_offset_out ||
276 param_offset_out + this_param < this_param) {
277 DEBUG(1,("Param overflow in cli_receive_trans\n"));
278 goto out;
280 if (param_offset_in > cli->bufsize ||
281 param_offset_in + this_param > cli->bufsize ||
282 param_offset_in + this_param < param_offset_in ||
283 param_offset_in + this_param < this_param) {
284 DEBUG(1,("Param overflow in cli_receive_trans\n"));
285 goto out;
288 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
290 *data_len += this_data;
291 *param_len += this_param;
293 if (total_data <= *data_len && total_param <= *param_len) {
294 ret = True;
295 break;
298 if (!cli_receive_smb(cli)) {
299 goto out;
302 show_msg(cli->inbuf);
304 /* sanity check */
305 if (CVAL(cli->inbuf,smb_com) != trans) {
306 DEBUG(0,("Expected %s response, got command 0x%02x\n",
307 trans==SMBtrans?"SMBtrans":"SMBtrans2",
308 CVAL(cli->inbuf,smb_com)));
309 goto out;
311 if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
312 goto out;
315 /* parse out the total lengths again - they can shrink! */
316 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
317 total_data = SVAL(cli->inbuf,smb_tdrcnt);
318 if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
319 total_param = SVAL(cli->inbuf,smb_tprcnt);
321 if (total_data <= *data_len && total_param <= *param_len) {
322 ret = True;
323 break;
327 out:
329 client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
330 return ret;
333 /****************************************************************************
334 Send a SMB nttrans request.
335 ****************************************************************************/
337 BOOL cli_send_nt_trans(struct cli_state *cli,
338 int function,
339 int flags,
340 uint16 *setup, unsigned int lsetup, unsigned int msetup,
341 char *param, unsigned int lparam, unsigned int mparam,
342 char *data, unsigned int ldata, unsigned int mdata)
344 unsigned int i;
345 unsigned int this_ldata,this_lparam;
346 unsigned int tot_data=0,tot_param=0;
347 uint16 mid;
348 char *outdata,*outparam;
350 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
351 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
353 memset(cli->outbuf,'\0',smb_size);
354 set_message(cli->outbuf,19+lsetup,0,True);
355 SCVAL(cli->outbuf,smb_com,SMBnttrans);
356 SSVAL(cli->outbuf,smb_tid, cli->cnum);
357 cli_setup_packet(cli);
360 * Save the mid we're using. We need this for finding
361 * signing replies.
364 mid = cli->mid;
366 outparam = smb_buf(cli->outbuf)+3;
367 outdata = outparam+this_lparam;
369 /* primary request */
370 SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
371 SCVAL(cli->outbuf,smb_nt_Flags,flags);
372 SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
373 SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
374 SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
375 SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
376 SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
377 SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
378 SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
379 SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
380 SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
381 SIVAL(cli->outbuf,smb_nt_Function, function);
382 for (i=0;i<lsetup;i++) /* setup[] */
383 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
385 if (this_lparam) /* param[] */
386 memcpy(outparam,param,this_lparam);
387 if (this_ldata) /* data[] */
388 memcpy(outdata,data,this_ldata);
390 cli_setup_bcc(cli, outdata+this_ldata);
392 show_msg(cli->outbuf);
393 if (!cli_send_smb(cli)) {
394 return False;
397 /* Note we're in a trans state. Save the sequence
398 * numbers for replies. */
399 client_set_trans_sign_state_on(cli, mid);
401 if (this_ldata < ldata || this_lparam < lparam) {
402 /* receive interim response */
403 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
404 client_set_trans_sign_state_off(cli, mid);
405 return(False);
408 tot_data = this_ldata;
409 tot_param = this_lparam;
411 while (tot_data < ldata || tot_param < lparam) {
412 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
413 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
415 set_message(cli->outbuf,18,0,True);
416 SCVAL(cli->outbuf,smb_com,SMBnttranss);
418 /* XXX - these should probably be aligned */
419 outparam = smb_buf(cli->outbuf);
420 outdata = outparam+this_lparam;
422 /* secondary request */
423 SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
424 SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
425 SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
426 SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
427 SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
428 SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
429 SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
430 SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
431 if (this_lparam) /* param[] */
432 memcpy(outparam,param+tot_param,this_lparam);
433 if (this_ldata) /* data[] */
434 memcpy(outdata,data+tot_data,this_ldata);
435 cli_setup_bcc(cli, outdata+this_ldata);
438 * Save the mid we're using. We need this for finding
439 * signing replies.
441 mid = cli->mid;
443 show_msg(cli->outbuf);
445 if (!cli_send_smb(cli)) {
446 client_set_trans_sign_state_off(cli, mid);
447 return False;
450 /* Ensure we use the same mid for the secondaries. */
451 cli->mid = mid;
453 tot_data += this_ldata;
454 tot_param += this_lparam;
458 return(True);
461 /****************************************************************************
462 Receive a SMB nttrans response allocating the necessary memory.
463 ****************************************************************************/
465 BOOL cli_receive_nt_trans(struct cli_state *cli,
466 char **param, unsigned int *param_len,
467 char **data, unsigned int *data_len)
469 unsigned int total_data=0;
470 unsigned int total_param=0;
471 unsigned int this_data,this_param;
472 uint8 eclass;
473 uint32 ecode;
474 BOOL ret = False;
476 *data_len = *param_len = 0;
478 if (!cli_receive_smb(cli)) {
479 return False;
482 show_msg(cli->inbuf);
484 /* sanity check */
485 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
486 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
487 CVAL(cli->inbuf,smb_com)));
488 return(False);
492 * An NT RPC pipe call can return ERRDOS, ERRmoredata
493 * to a trans call. This is not an error and should not
494 * be treated as such.
496 if (cli_is_dos_error(cli)) {
497 cli_dos_error(cli, &eclass, &ecode);
498 if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
499 goto out;
504 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
506 if (cli_is_nt_error(cli)) {
507 if (!NT_STATUS_EQUAL(cli_nt_error(cli),
508 NT_STATUS_BUFFER_TOO_SMALL)) {
509 goto out;
513 /* parse out the lengths */
514 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
515 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
517 /* allocate it */
518 if (total_data) {
519 *data = (char *)SMB_REALLOC(*data,total_data);
520 if (!(*data)) {
521 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
522 goto out;
526 if (total_param) {
527 *param = (char *)SMB_REALLOC(*param,total_param);
528 if (!(*param)) {
529 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
530 goto out;
534 while (1) {
535 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
536 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
538 if (this_data + *data_len > total_data ||
539 this_param + *param_len > total_param) {
540 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
541 goto out;
544 if (this_data + *data_len < this_data ||
545 this_data + *data_len < *data_len ||
546 this_param + *param_len < this_param ||
547 this_param + *param_len < *param_len) {
548 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
549 goto out;
552 if (this_data) {
553 unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
554 unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
556 if (data_offset_out > total_data ||
557 data_offset_out + this_data > total_data ||
558 data_offset_out + this_data < data_offset_out ||
559 data_offset_out + this_data < this_data) {
560 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
561 goto out;
563 if (data_offset_in > cli->bufsize ||
564 data_offset_in + this_data > cli->bufsize ||
565 data_offset_in + this_data < data_offset_in ||
566 data_offset_in + this_data < this_data) {
567 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
568 goto out;
571 memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
574 if (this_param) {
575 unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
576 unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
578 if (param_offset_out > total_param ||
579 param_offset_out + this_param > total_param ||
580 param_offset_out + this_param < param_offset_out ||
581 param_offset_out + this_param < this_param) {
582 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
583 goto out;
585 if (param_offset_in > cli->bufsize ||
586 param_offset_in + this_param > cli->bufsize ||
587 param_offset_in + this_param < param_offset_in ||
588 param_offset_in + this_param < this_param) {
589 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
590 goto out;
593 memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
596 *data_len += this_data;
597 *param_len += this_param;
599 if (total_data <= *data_len && total_param <= *param_len) {
600 ret = True;
601 break;
604 if (!cli_receive_smb(cli)) {
605 goto out;
608 show_msg(cli->inbuf);
610 /* sanity check */
611 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
612 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
613 CVAL(cli->inbuf,smb_com)));
614 goto out;
616 if (cli_is_dos_error(cli)) {
617 cli_dos_error(cli, &eclass, &ecode);
618 if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
619 goto out;
623 * Likewise for NT_STATUS_BUFFER_TOO_SMALL
625 if (cli_is_nt_error(cli)) {
626 if (!NT_STATUS_EQUAL(cli_nt_error(cli),
627 NT_STATUS_BUFFER_TOO_SMALL)) {
628 goto out;
632 /* parse out the total lengths again - they can shrink! */
633 if (SVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
634 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
635 if (SVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
636 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
638 if (total_data <= *data_len && total_param <= *param_len) {
639 ret = True;
640 break;
644 out:
646 client_set_trans_sign_state_off(cli, SVAL(cli->inbuf,smb_mid));
647 return ret;