2 Unix SMB/Netbios implementation.
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.
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
,
33 uint16
*setup
, int lsetup
, int msetup
,
34 char *param
, int lparam
, int mparam
,
35 char *data
, int ldata
, int mdata
)
38 int this_ldata
,this_lparam
;
39 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
);
89 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
90 /* receive interim response */
91 if (!cli_receive_smb(cli
) ||
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
);
129 tot_data
+= this_ldata
;
130 tot_param
+= this_lparam
;
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
)
147 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
)) {
178 /* parse out the lengths */
179 total_data
= SVAL(cli
->inbuf
,smb_tdrcnt
);
180 total_param
= SVAL(cli
->inbuf
,smb_tprcnt
);
184 tdata
= Realloc(*data
,total_data
);
186 DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
193 if (total_param
!=0) {
194 tparam
= Realloc(*param
,total_param
);
196 DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
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"));
214 memcpy(*data
+ SVAL(cli
->inbuf
,smb_drdisp
),
215 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_droff
),
218 memcpy(*param
+ SVAL(cli
->inbuf
,smb_prdisp
),
219 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_proff
),
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
)
231 if (!cli_receive_smb(cli
))
234 show_msg(cli
->inbuf
);
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
)));
243 if (NT_STATUS_IS_ERR(cli_nt_error(cli
))) {
254 /****************************************************************************
255 send a SMB nttrans request
256 ****************************************************************************/
257 BOOL
cli_send_nt_trans(struct cli_state
*cli
,
260 uint16
*setup
, int lsetup
, int msetup
,
261 char *param
, int lparam
, int mparam
,
262 char *data
, int ldata
, int mdata
)
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
);
307 if (this_ldata
< ldata
|| this_lparam
< lparam
) {
308 /* receive interim response */
309 if (!cli_receive_smb(cli
) ||
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
);
346 tot_data
+= this_ldata
;
347 tot_param
+= this_lparam
;
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
)
365 int this_data
,this_param
;
371 *data_len
= *param_len
= 0;
373 if (!cli_receive_smb(cli
))
376 show_msg(cli
->inbuf
);
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
)));
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
))
396 /* parse out the lengths */
397 total_data
= SVAL(cli
->inbuf
,smb_ntr_TotalDataCount
);
398 total_param
= SVAL(cli
->inbuf
,smb_ntr_TotalParameterCount
);
402 tdata
= Realloc(*data
,total_data
);
404 DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data
));
412 tparam
= Realloc(*param
,total_param
);
414 DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param
));
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"));
432 memcpy(*data
+ SVAL(cli
->inbuf
,smb_ntr_DataDisplacement
),
433 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_ntr_DataOffset
),
436 memcpy(*param
+ SVAL(cli
->inbuf
,smb_ntr_ParameterDisplacement
),
437 smb_base(cli
->inbuf
) + SVAL(cli
->inbuf
,smb_ntr_ParameterOffset
),
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
)
449 if (!cli_receive_smb(cli
))
452 show_msg(cli
->inbuf
);
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
)));
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
))