removed two unneeded files after Richard backed out these changes.
[Samba.git] / source / libsmb / clitrans.c
blobbd8647421b2fb5a5c0a5f6f8994a9f97492ebc75
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 client transaction calls
5 Copyright (C) Andrew Tridgell 1994-1998
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #define NO_SYSLOG
24 #include "includes.h"
27 /****************************************************************************
28 send a SMB trans or trans2 request
29 ****************************************************************************/
30 BOOL cli_send_trans(struct cli_state *cli, int trans,
31 const char *pipe_name,
32 int fid, int flags,
33 uint16 *setup, int lsetup, int msetup,
34 char *param, int lparam, int mparam,
35 char *data, int ldata, int mdata)
37 int i;
38 int this_ldata,this_lparam;
39 int tot_data=0,tot_param=0;
40 char *outdata,*outparam;
41 char *p;
42 int pipe_name_len=0;
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);
53 if (pipe_name) {
54 pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE|STR_CONVERT);
57 outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
58 outdata = outparam+this_lparam;
60 /* primary request */
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 cli_send_smb(cli);
89 if (this_ldata < ldata || this_lparam < lparam) {
90 /* receive interim response */
91 if (!cli_receive_smb(cli) ||
92 cli_is_error(cli)) {
93 return(False);
96 tot_data = this_ldata;
97 tot_param = this_lparam;
99 while (tot_data < ldata || tot_param < lparam) {
100 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
101 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
103 set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
104 SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
106 outparam = smb_buf(cli->outbuf);
107 outdata = outparam+this_lparam;
109 /* secondary request */
110 SSVAL(cli->outbuf,smb_tpscnt,lparam); /* tpscnt */
111 SSVAL(cli->outbuf,smb_tdscnt,ldata); /* tdscnt */
112 SSVAL(cli->outbuf,smb_spscnt,this_lparam); /* pscnt */
113 SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
114 SSVAL(cli->outbuf,smb_spsdisp,tot_param); /* psdisp */
115 SSVAL(cli->outbuf,smb_sdscnt,this_ldata); /* dscnt */
116 SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
117 SSVAL(cli->outbuf,smb_sdsdisp,tot_data); /* dsdisp */
118 if (trans==SMBtrans2)
119 SSVALS(cli->outbuf,smb_sfid,fid); /* fid */
120 if (this_lparam) /* param[] */
121 memcpy(outparam,param+tot_param,this_lparam);
122 if (this_ldata) /* data[] */
123 memcpy(outdata,data+tot_data,this_ldata);
124 cli_setup_bcc(cli, outdata+this_ldata);
126 show_msg(cli->outbuf);
127 cli_send_smb(cli);
129 tot_data += this_ldata;
130 tot_param += this_lparam;
134 return(True);
138 /****************************************************************************
139 receive a SMB trans or trans2 response allocating the necessary memory
140 ****************************************************************************/
141 BOOL cli_receive_trans(struct cli_state *cli,int trans,
142 char **param, int *param_len,
143 char **data, int *data_len)
145 int total_data=0;
146 int total_param=0;
147 int this_data,this_param;
148 NTSTATUS status;
149 char *tdata;
150 char *tparam;
152 *data_len = *param_len = 0;
154 if (!cli_receive_smb(cli))
155 return False;
157 show_msg(cli->inbuf);
159 /* sanity check */
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)));
164 return(False);
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)) {
175 return False;
178 /* parse out the lengths */
179 total_data = SVAL(cli->inbuf,smb_tdrcnt);
180 total_param = SVAL(cli->inbuf,smb_tprcnt);
182 /* allocate it */
183 if (total_data!=0) {
184 tdata = Realloc(*data,total_data);
185 if (!tdata) {
186 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
187 return False;
189 else
190 *data = tdata;
193 if (total_param!=0) {
194 tparam = Realloc(*param,total_param);
195 if (!tparam) {
196 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
197 return False;
199 else
200 *param = tparam;
203 while (1) {
204 this_data = SVAL(cli->inbuf,smb_drcnt);
205 this_param = SVAL(cli->inbuf,smb_prcnt);
207 if (this_data + *data_len > total_data ||
208 this_param + *param_len > total_param) {
209 DEBUG(1,("Data overflow in cli_receive_trans\n"));
210 return False;
213 if (this_data)
214 memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
215 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
216 this_data);
217 if (this_param)
218 memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
219 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
220 this_param);
221 *data_len += this_data;
222 *param_len += this_param;
224 /* parse out the total lengths again - they can shrink! */
225 total_data = SVAL(cli->inbuf,smb_tdrcnt);
226 total_param = SVAL(cli->inbuf,smb_tprcnt);
228 if (total_data <= *data_len && total_param <= *param_len)
229 break;
231 if (!cli_receive_smb(cli))
232 return False;
234 show_msg(cli->inbuf);
236 /* sanity check */
237 if (CVAL(cli->inbuf,smb_com) != trans) {
238 DEBUG(0,("Expected %s response, got command 0x%02x\n",
239 trans==SMBtrans?"SMBtrans":"SMBtrans2",
240 CVAL(cli->inbuf,smb_com)));
241 return(False);
243 if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
244 return(False);
248 return(True);
254 /****************************************************************************
255 send a SMB nttrans request
256 ****************************************************************************/
257 BOOL cli_send_nt_trans(struct cli_state *cli,
258 int function,
259 int flags,
260 uint16 *setup, int lsetup, int msetup,
261 char *param, int lparam, int mparam,
262 char *data, int ldata, int mdata)
264 int i;
265 int this_ldata,this_lparam;
266 int tot_data=0,tot_param=0;
267 char *outdata,*outparam;
269 this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
270 this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
272 memset(cli->outbuf,'\0',smb_size);
273 set_message(cli->outbuf,19+lsetup,0,True);
274 SCVAL(cli->outbuf,smb_com,SMBnttrans);
275 SSVAL(cli->outbuf,smb_tid, cli->cnum);
276 cli_setup_packet(cli);
278 outparam = smb_buf(cli->outbuf)+3;
279 outdata = outparam+this_lparam;
281 /* primary request */
282 SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
283 SCVAL(cli->outbuf,smb_nt_Flags,flags);
284 SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
285 SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
286 SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
287 SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
288 SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
289 SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
290 SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
291 SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
292 SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
293 SIVAL(cli->outbuf,smb_nt_Function, function);
294 for (i=0;i<lsetup;i++) /* setup[] */
295 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
297 if (this_lparam) /* param[] */
298 memcpy(outparam,param,this_lparam);
299 if (this_ldata) /* data[] */
300 memcpy(outdata,data,this_ldata);
302 cli_setup_bcc(cli, outdata+this_ldata);
304 show_msg(cli->outbuf);
305 cli_send_smb(cli);
307 if (this_ldata < ldata || this_lparam < lparam) {
308 /* receive interim response */
309 if (!cli_receive_smb(cli) ||
310 cli_is_error(cli)) {
311 return(False);
314 tot_data = this_ldata;
315 tot_param = this_lparam;
317 while (tot_data < ldata || tot_param < lparam) {
318 this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
319 this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
321 set_message(cli->outbuf,18,0,True);
322 SCVAL(cli->outbuf,smb_com,SMBnttranss);
324 /* XXX - these should probably be aligned */
325 outparam = smb_buf(cli->outbuf);
326 outdata = outparam+this_lparam;
328 /* secondary request */
329 SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
330 SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
331 SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
332 SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
333 SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
334 SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
335 SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
336 SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
337 if (this_lparam) /* param[] */
338 memcpy(outparam,param+tot_param,this_lparam);
339 if (this_ldata) /* data[] */
340 memcpy(outdata,data+tot_data,this_ldata);
341 cli_setup_bcc(cli, outdata+this_ldata);
343 show_msg(cli->outbuf);
344 cli_send_smb(cli);
346 tot_data += this_ldata;
347 tot_param += this_lparam;
351 return(True);
356 /****************************************************************************
357 receive a SMB nttrans response allocating the necessary memory
358 ****************************************************************************/
359 BOOL cli_receive_nt_trans(struct cli_state *cli,
360 char **param, int *param_len,
361 char **data, int *data_len)
363 int total_data=0;
364 int total_param=0;
365 int this_data,this_param;
366 uint8 eclass;
367 uint32 ecode;
368 char *tdata;
369 char *tparam;
371 *data_len = *param_len = 0;
373 if (!cli_receive_smb(cli))
374 return False;
376 show_msg(cli->inbuf);
378 /* sanity check */
379 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
380 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
381 CVAL(cli->inbuf,smb_com)));
382 return(False);
386 * An NT RPC pipe call can return ERRDOS, ERRmoredata
387 * to a trans call. This is not an error and should not
388 * be treated as such.
390 if (cli_is_dos_error(cli)) {
391 cli_dos_error(cli, &eclass, &ecode);
392 if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
393 return(False);
396 /* parse out the lengths */
397 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
398 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
400 /* allocate it */
401 if (total_data) {
402 tdata = Realloc(*data,total_data);
403 if (!tdata) {
404 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
405 return False;
406 } else {
407 *data = tdata;
411 if (total_param) {
412 tparam = Realloc(*param,total_param);
413 if (!tparam) {
414 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
415 return False;
416 } else {
417 *param = tparam;
421 while (1) {
422 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
423 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
425 if (this_data + *data_len > total_data ||
426 this_param + *param_len > total_param) {
427 DEBUG(1,("Data overflow in cli_receive_trans\n"));
428 return False;
431 if (this_data)
432 memcpy(*data + SVAL(cli->inbuf,smb_ntr_DataDisplacement),
433 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_ntr_DataOffset),
434 this_data);
435 if (this_param)
436 memcpy(*param + SVAL(cli->inbuf,smb_ntr_ParameterDisplacement),
437 smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_ntr_ParameterOffset),
438 this_param);
439 *data_len += this_data;
440 *param_len += this_param;
442 /* parse out the total lengths again - they can shrink! */
443 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
444 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
446 if (total_data <= *data_len && total_param <= *param_len)
447 break;
449 if (!cli_receive_smb(cli))
450 return False;
452 show_msg(cli->inbuf);
454 /* sanity check */
455 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
456 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
457 CVAL(cli->inbuf,smb_com)));
458 return(False);
460 if (cli_is_dos_error(cli)) {
461 cli_dos_error(cli, &eclass, &ecode);
462 if(cli->nt_pipe_fnum == 0 ||
463 !(eclass == ERRDOS && ecode == ERRmoredata))
464 return(False);
468 return(True);