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 ****************************************************************************/
29 BOOL
cli_send_trans(struct cli_state
*cli
, int trans
,
30 const char *pipe_name
,
32 uint16
*setup
, int lsetup
, int msetup
,
33 char *param
, int lparam
, int mparam
,
34 char *data
, int ldata
, int mdata
)
37 int this_ldata
,this_lparam
;
38 int tot_data
=0,tot_param
=0;
39 char *outdata
,*outparam
;
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 pipe_name_len
= clistr_push(cli
, smb_buf(cli
->outbuf
), pipe_name
, -1, STR_TERMINATE
);
56 outparam
= smb_buf(cli
->outbuf
)+(trans
==SMBtrans
? pipe_name_len
: 3);
57 outdata
= outparam
+this_lparam
;
60 SSVAL(cli
->outbuf
,smb_tpscnt
,lparam
); /* tpscnt */
61 SSVAL(cli
->outbuf
,smb_tdscnt
,ldata
); /* tdscnt */
62 SSVAL(cli
->outbuf
,smb_mprcnt
,mparam
); /* mprcnt */
63 SSVAL(cli
->outbuf
,smb_mdrcnt
,mdata
); /* mdrcnt */
64 SCVAL(cli
->outbuf
,smb_msrcnt
,msetup
); /* msrcnt */
65 SSVAL(cli
->outbuf
,smb_flags
,flags
); /* flags */
66 SIVAL(cli
->outbuf
,smb_timeout
,0); /* timeout */
67 SSVAL(cli
->outbuf
,smb_pscnt
,this_lparam
); /* pscnt */
68 SSVAL(cli
->outbuf
,smb_psoff
,smb_offset(outparam
,cli
->outbuf
)); /* psoff */
69 SSVAL(cli
->outbuf
,smb_dscnt
,this_ldata
); /* dscnt */
70 SSVAL(cli
->outbuf
,smb_dsoff
,smb_offset(outdata
,cli
->outbuf
)); /* dsoff */
71 SCVAL(cli
->outbuf
,smb_suwcnt
,lsetup
); /* suwcnt */
72 for (i
=0;i
<lsetup
;i
++) /* setup[] */
73 SSVAL(cli
->outbuf
,smb_setup
+i
*2,setup
[i
]);
74 p
= smb_buf(cli
->outbuf
);
75 if (trans
!= SMBtrans
) {
76 *p
++ = 0; /* put in a null smb_name */
77 *p
++ = 'D'; *p
++ = ' '; /* observed in OS/2 */
79 if (this_lparam
) /* param[] */
80 memcpy(outparam
,param
,this_lparam
);
81 if (this_ldata
) /* data[] */
82 memcpy(outdata
,data
,this_ldata
);
83 cli_setup_bcc(cli
, outdata
+this_ldata
);
85 show_msg(cli
->outbuf
);
88 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
89 /* receive interim response */
90 if (!cli_receive_smb(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
);
128 tot_data
+= this_ldata
;
129 tot_param
+= this_lparam
;
137 /****************************************************************************
138 receive a SMB trans or trans2 response allocating the necessary memory
139 ****************************************************************************/
140 BOOL
cli_receive_trans(struct cli_state
*cli
,int trans
,
141 char **param
, int *param_len
,
142 char **data
, int *data_len
)
146 int this_data
,this_param
;
151 *data_len
= *param_len
= 0;
153 if (!cli_receive_smb(cli
))
156 show_msg(cli
->inbuf
);
159 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
160 DEBUG(0,("Expected %s response, got command 0x%02x\n",
161 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
162 CVAL(cli
->inbuf
,smb_com
)));
167 * An NT RPC pipe call can return ERRDOS, ERRmoredata
168 * to a trans call. This is not an error and should not
169 * be treated as such.
171 status
= cli_nt_error(cli
);
173 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"));
213 memcpy(*data
+ SVAL(cli
->inbuf
,smb_drdisp
),
214 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_droff
),
217 memcpy(*param
+ SVAL(cli
->inbuf
,smb_prdisp
),
218 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_proff
),
220 *data_len
+= this_data
;
221 *param_len
+= this_param
;
223 /* parse out the total lengths again - they can shrink! */
224 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
225 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
227 if (total_data
<= *data_len
&& total_param
<= *param_len
)
230 if (!cli_receive_smb(cli
))
233 show_msg(cli
->inbuf
);
236 if (CVAL(cli
->inbuf
,smb_com
) != trans
) {
237 DEBUG(0,("Expected %s response, got command 0x%02x\n",
238 trans
==SMBtrans
?"SMBtrans":"SMBtrans2",
239 CVAL(cli
->inbuf
,smb_com
)));
242 if (NT_STATUS_IS_ERR(cli_nt_error(cli
))) {
253 /****************************************************************************
254 send a SMB nttrans request
255 ****************************************************************************/
256 BOOL
cli_send_nt_trans(struct cli_state
*cli
,
259 uint16
*setup
, int lsetup
, int msetup
,
260 char *param
, int lparam
, int mparam
,
261 char *data
, int ldata
, int mdata
)
264 int this_ldata
,this_lparam
;
265 int tot_data
=0,tot_param
=0;
266 char *outdata
,*outparam
;
268 this_lparam
= MIN(lparam
,cli
->max_xmit
- (500+lsetup
*2)); /* hack */
269 this_ldata
= MIN(ldata
,cli
->max_xmit
- (500+lsetup
*2+this_lparam
));
271 memset(cli
->outbuf
,'\0',smb_size
);
272 set_message(cli
->outbuf
,19+lsetup
,0,True
);
273 SCVAL(cli
->outbuf
,smb_com
,SMBnttrans
);
274 SSVAL(cli
->outbuf
,smb_tid
, cli
->cnum
);
275 cli_setup_packet(cli
);
277 outparam
= smb_buf(cli
->outbuf
)+3;
278 outdata
= outparam
+this_lparam
;
280 /* primary request */
281 SCVAL(cli
->outbuf
,smb_nt_MaxSetupCount
,msetup
);
282 SCVAL(cli
->outbuf
,smb_nt_Flags
,flags
);
283 SIVAL(cli
->outbuf
,smb_nt_TotalParameterCount
, lparam
);
284 SIVAL(cli
->outbuf
,smb_nt_TotalDataCount
, ldata
);
285 SIVAL(cli
->outbuf
,smb_nt_MaxParameterCount
, mparam
);
286 SIVAL(cli
->outbuf
,smb_nt_MaxDataCount
, mdata
);
287 SIVAL(cli
->outbuf
,smb_nt_ParameterCount
, this_lparam
);
288 SIVAL(cli
->outbuf
,smb_nt_ParameterOffset
, smb_offset(outparam
,cli
->outbuf
));
289 SIVAL(cli
->outbuf
,smb_nt_DataCount
, this_ldata
);
290 SIVAL(cli
->outbuf
,smb_nt_DataOffset
, smb_offset(outdata
,cli
->outbuf
));
291 SIVAL(cli
->outbuf
,smb_nt_SetupCount
, lsetup
);
292 SIVAL(cli
->outbuf
,smb_nt_Function
, function
);
293 for (i
=0;i
<lsetup
;i
++) /* setup[] */
294 SSVAL(cli
->outbuf
,smb_nt_SetupStart
+i
*2,setup
[i
]);
296 if (this_lparam
) /* param[] */
297 memcpy(outparam
,param
,this_lparam
);
298 if (this_ldata
) /* data[] */
299 memcpy(outdata
,data
,this_ldata
);
301 cli_setup_bcc(cli
, outdata
+this_ldata
);
303 show_msg(cli
->outbuf
);
306 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
307 /* receive interim response */
308 if (!cli_receive_smb(cli
) ||
313 tot_data
= this_ldata
;
314 tot_param
= this_lparam
;
316 while (tot_data
< ldata
|| tot_param
< lparam
) {
317 this_lparam
= MIN(lparam
-tot_param
,cli
->max_xmit
- 500); /* hack */
318 this_ldata
= MIN(ldata
-tot_data
,cli
->max_xmit
- (500+this_lparam
));
320 set_message(cli
->outbuf
,18,0,True
);
321 SCVAL(cli
->outbuf
,smb_com
,SMBnttranss
);
323 /* XXX - these should probably be aligned */
324 outparam
= smb_buf(cli
->outbuf
);
325 outdata
= outparam
+this_lparam
;
327 /* secondary request */
328 SIVAL(cli
->outbuf
,smb_nts_TotalParameterCount
,lparam
);
329 SIVAL(cli
->outbuf
,smb_nts_TotalDataCount
,ldata
);
330 SIVAL(cli
->outbuf
,smb_nts_ParameterCount
,this_lparam
);
331 SIVAL(cli
->outbuf
,smb_nts_ParameterOffset
,smb_offset(outparam
,cli
->outbuf
));
332 SIVAL(cli
->outbuf
,smb_nts_ParameterDisplacement
,tot_param
);
333 SIVAL(cli
->outbuf
,smb_nts_DataCount
,this_ldata
);
334 SIVAL(cli
->outbuf
,smb_nts_DataOffset
,smb_offset(outdata
,cli
->outbuf
));
335 SIVAL(cli
->outbuf
,smb_nts_DataDisplacement
,tot_data
);
336 if (this_lparam
) /* param[] */
337 memcpy(outparam
,param
+tot_param
,this_lparam
);
338 if (this_ldata
) /* data[] */
339 memcpy(outdata
,data
+tot_data
,this_ldata
);
340 cli_setup_bcc(cli
, outdata
+this_ldata
);
342 show_msg(cli
->outbuf
);
345 tot_data
+= this_ldata
;
346 tot_param
+= this_lparam
;
355 /****************************************************************************
356 receive a SMB nttrans response allocating the necessary memory
357 ****************************************************************************/
358 BOOL
cli_receive_nt_trans(struct cli_state
*cli
,
359 char **param
, int *param_len
,
360 char **data
, int *data_len
)
364 int this_data
,this_param
;
370 *data_len
= *param_len
= 0;
372 if (!cli_receive_smb(cli
))
375 show_msg(cli
->inbuf
);
378 if (CVAL(cli
->inbuf
,smb_com
) != SMBnttrans
) {
379 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
380 CVAL(cli
->inbuf
,smb_com
)));
385 * An NT RPC pipe call can return ERRDOS, ERRmoredata
386 * to a trans call. This is not an error and should not
387 * be treated as such.
389 if (cli_is_dos_error(cli
)) {
390 cli_dos_error(cli
, &eclass
, &ecode
);
391 if (cli
->nt_pipe_fnum
== 0 || !(eclass
== ERRDOS
&& ecode
== ERRmoredata
))
395 /* parse out the lengths */
396 total_data
= SVAL(cli
->inbuf
,smb_ntr_TotalDataCount
);
397 total_param
= SVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
);
401 tdata
= Realloc(*data
,total_data
);
403 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data
));
411 tparam
= Realloc(*param
,total_param
);
413 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param
));
421 this_data
= SVAL(cli
->inbuf
,smb_ntr_DataCount
);
422 this_param
= SVAL(cli
->inbuf
,smb_ntr_ParameterCount
);
424 if (this_data
+ *data_len
> total_data
||
425 this_param
+ *param_len
> total_param
) {
426 DEBUG(1,("Data overflow in cli_receive_trans\n"));
431 memcpy(*data
+ SVAL(cli
->inbuf
,smb_ntr_DataDisplacement
),
432 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_ntr_DataOffset
),
435 memcpy(*param
+ SVAL(cli
->inbuf
,smb_ntr_ParameterDisplacement
),
436 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_ntr_ParameterOffset
),
438 *data_len
+= this_data
;
439 *param_len
+= this_param
;
441 /* parse out the total lengths again - they can shrink! */
442 total_data
= SVAL(cli
->inbuf
,smb_ntr_TotalDataCount
);
443 total_param
= SVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
);
445 if (total_data
<= *data_len
&& total_param
<= *param_len
)
448 if (!cli_receive_smb(cli
))
451 show_msg(cli
->inbuf
);
454 if (CVAL(cli
->inbuf
,smb_com
) != SMBnttrans
) {
455 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
456 CVAL(cli
->inbuf
,smb_com
)));
459 if (cli_is_dos_error(cli
)) {
460 cli_dos_error(cli
, &eclass
, &ecode
);
461 if(cli
->nt_pipe_fnum
== 0 ||
462 !(eclass
== ERRDOS
&& ecode
== ERRmoredata
))