to use the same macros in the client and server rename the CLISTR_
[samba.git] / source / libsmb / clitrans.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 3.0
4    client transaction calls
5    Copyright (C) Andrew Tridgell 1994-1998
6    
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.
11    
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.
16    
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.
20 */
21
22 #define NO_SYSLOG
23
24 #include "includes.h"
25
26
27 /****************************************************************************
28   send a SMB trans or trans2 request
29   ****************************************************************************/
30 BOOL cli_send_trans(struct cli_state *cli, int trans, 
31                     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)
36 {
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;
43
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));
46
47         memset(cli->outbuf,'\0',smb_size);
48         set_message(cli->outbuf,14+lsetup,0,True);
49         CVAL(cli->outbuf,smb_com) = trans;
50         SSVAL(cli->outbuf,smb_tid, cli->cnum);
51         cli_setup_packet(cli);
52
53         if (pipe_name) {
54                 pipe_name_len = clistr_push_size(cli, smb_buf(cli->outbuf), 
55                                                  pipe_name, -1, 
56                                                  STR_TERMINATE);
57         }
58
59         outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
60         outdata = outparam+this_lparam;
61
62         /* primary request */
63         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
64         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
65         SSVAL(cli->outbuf,smb_mprcnt,mparam);   /* mprcnt */
66         SSVAL(cli->outbuf,smb_mdrcnt,mdata);    /* mdrcnt */
67         SCVAL(cli->outbuf,smb_msrcnt,msetup);   /* msrcnt */
68         SSVAL(cli->outbuf,smb_flags,flags);     /* flags */
69         SIVAL(cli->outbuf,smb_timeout,0);               /* timeout */
70         SSVAL(cli->outbuf,smb_pscnt,this_lparam);       /* pscnt */
71         SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
72         SSVAL(cli->outbuf,smb_dscnt,this_ldata);        /* dscnt */
73         SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
74         SCVAL(cli->outbuf,smb_suwcnt,lsetup);   /* suwcnt */
75         for (i=0;i<lsetup;i++)          /* setup[] */
76                 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
77         p = smb_buf(cli->outbuf);
78         if (trans==SMBtrans) {
79                 clistr_push(cli, p, pipe_name, -1, STR_TERMINATE);
80         } else {
81                 *p++ = 0;  /* put in a null smb_name */
82                 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
83         }
84         if (this_lparam)                        /* param[] */
85                 memcpy(outparam,param,this_lparam);
86         if (this_ldata)                 /* data[] */
87                 memcpy(outdata,data,this_ldata);
88         cli_setup_bcc(cli, outdata+this_ldata);
89
90         show_msg(cli->outbuf);
91         cli_send_smb(cli);
92
93         if (this_ldata < ldata || this_lparam < lparam) {
94                 /* receive interim response */
95                 if (!cli_receive_smb(cli) || 
96                     CVAL(cli->inbuf,smb_rcls) != 0) {
97                         return(False);
98                 }      
99
100                 tot_data = this_ldata;
101                 tot_param = this_lparam;
102                 
103                 while (tot_data < ldata || tot_param < lparam)  {
104                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
105                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
106
107                         set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
108                         CVAL(cli->outbuf,smb_com) = trans==SMBtrans ? SMBtranss : SMBtranss2;
109                         
110                         outparam = smb_buf(cli->outbuf);
111                         outdata = outparam+this_lparam;
112                         
113                         /* secondary request */
114                         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
115                         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
116                         SSVAL(cli->outbuf,smb_spscnt,this_lparam);      /* pscnt */
117                         SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
118                         SSVAL(cli->outbuf,smb_spsdisp,tot_param);       /* psdisp */
119                         SSVAL(cli->outbuf,smb_sdscnt,this_ldata);       /* dscnt */
120                         SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
121                         SSVAL(cli->outbuf,smb_sdsdisp,tot_data);        /* dsdisp */
122                         if (trans==SMBtrans2)
123                                 SSVALS(cli->outbuf,smb_sfid,fid);               /* fid */
124                         if (this_lparam)                        /* param[] */
125                                 memcpy(outparam,param+tot_param,this_lparam);
126                         if (this_ldata)                 /* data[] */
127                                 memcpy(outdata,data+tot_data,this_ldata);
128                         cli_setup_bcc(cli, outdata+this_ldata);
129                         
130                         show_msg(cli->outbuf);
131                         cli_send_smb(cli);
132                         
133                         tot_data += this_ldata;
134                         tot_param += this_lparam;
135                 }
136         }
137
138         return(True);
139 }
140
141
142 /****************************************************************************
143   receive a SMB trans or trans2 response allocating the necessary memory
144   ****************************************************************************/
145 BOOL cli_receive_trans(struct cli_state *cli,int trans,
146                               char **param, int *param_len,
147                               char **data, int *data_len)
148 {
149         int total_data=0;
150         int total_param=0;
151         int this_data,this_param;
152         uint8 eclass;
153         uint32 ecode;
154
155         *data_len = *param_len = 0;
156
157         if (!cli_receive_smb(cli))
158                 return False;
159
160         show_msg(cli->inbuf);
161         
162         /* sanity check */
163         if (CVAL(cli->inbuf,smb_com) != trans) {
164                 DEBUG(0,("Expected %s response, got command 0x%02x\n",
165                          trans==SMBtrans?"SMBtrans":"SMBtrans2", 
166                          CVAL(cli->inbuf,smb_com)));
167                 return(False);
168         }
169
170         /*
171          * An NT RPC pipe call can return ERRDOS, ERRmoredata
172          * to a trans call. This is not an error and should not
173          * be treated as such.
174          */
175
176         if (cli_error(cli, &eclass, &ecode, NULL))
177         {
178         if(cli->nt_pipe_fnum == 0)
179                         return(False);
180
181         if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
182                         if (eclass != 0 && (ecode != (0x80000000 | STATUS_BUFFER_OVERFLOW)))
183                                 return(False);
184                 }
185         }
186
187         /* parse out the lengths */
188         total_data = SVAL(cli->inbuf,smb_tdrcnt);
189         total_param = SVAL(cli->inbuf,smb_tprcnt);
190
191         /* allocate it */
192         *data = Realloc(*data,total_data);
193         *param = Realloc(*param,total_param);
194
195         while (1)  {
196                 this_data = SVAL(cli->inbuf,smb_drcnt);
197                 this_param = SVAL(cli->inbuf,smb_prcnt);
198
199                 if (this_data + *data_len > total_data ||
200                     this_param + *param_len > total_param) {
201                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
202                         return False;
203                 }
204
205                 if (this_data)
206                         memcpy(*data + SVAL(cli->inbuf,smb_drdisp),
207                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_droff),
208                                this_data);
209                 if (this_param)
210                         memcpy(*param + SVAL(cli->inbuf,smb_prdisp),
211                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_proff),
212                                this_param);
213                 *data_len += this_data;
214                 *param_len += this_param;
215
216                 /* parse out the total lengths again - they can shrink! */
217                 total_data = SVAL(cli->inbuf,smb_tdrcnt);
218                 total_param = SVAL(cli->inbuf,smb_tprcnt);
219                 
220                 if (total_data <= *data_len && total_param <= *param_len)
221                         break;
222                 
223                 if (!cli_receive_smb(cli))
224                         return False;
225
226                 show_msg(cli->inbuf);
227                 
228                 /* sanity check */
229                 if (CVAL(cli->inbuf,smb_com) != trans) {
230                         DEBUG(0,("Expected %s response, got command 0x%02x\n",
231                                  trans==SMBtrans?"SMBtrans":"SMBtrans2", 
232                                  CVAL(cli->inbuf,smb_com)));
233                         return(False);
234                 }
235                 if (cli_error(cli, &eclass, &ecode, NULL))
236                 {
237                 if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
238                                 return(False);
239                 }
240         }
241         
242         return(True);
243 }
244
245
246
247
248 /****************************************************************************
249   send a SMB nttrans request
250   ****************************************************************************/
251 BOOL cli_send_nt_trans(struct cli_state *cli, 
252                        int function, 
253                        int flags,
254                        uint16 *setup, int lsetup, int msetup,
255                        char *param, int lparam, int mparam,
256                        char *data, int ldata, int mdata)
257 {
258         int i;
259         int this_ldata,this_lparam;
260         int tot_data=0,tot_param=0;
261         char *outdata,*outparam;
262
263         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
264         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
265
266         memset(cli->outbuf,'\0',smb_size);
267         set_message(cli->outbuf,19+lsetup,0,True);
268         CVAL(cli->outbuf,smb_com) = SMBnttrans;
269         SSVAL(cli->outbuf,smb_tid, cli->cnum);
270         cli_setup_packet(cli);
271
272         outparam = smb_buf(cli->outbuf)+3;
273         outdata = outparam+this_lparam;
274
275         /* primary request */
276         SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
277         SCVAL(cli->outbuf,smb_nt_Flags,flags);
278         SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
279         SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
280         SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
281         SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
282         SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
283         SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
284         SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
285         SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
286         SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
287         SIVAL(cli->outbuf,smb_nt_Function, function);
288         for (i=0;i<lsetup;i++)          /* setup[] */
289                 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
290         
291         if (this_lparam)                        /* param[] */
292                 memcpy(outparam,param,this_lparam);
293         if (this_ldata)                 /* data[] */
294                 memcpy(outdata,data,this_ldata);
295
296         cli_setup_bcc(cli, outdata+this_ldata);
297
298         show_msg(cli->outbuf);
299         cli_send_smb(cli);
300
301         if (this_ldata < ldata || this_lparam < lparam) {
302                 /* receive interim response */
303                 if (!cli_receive_smb(cli) || 
304                     CVAL(cli->inbuf,smb_rcls) != 0) {
305                         return(False);
306                 }      
307
308                 tot_data = this_ldata;
309                 tot_param = this_lparam;
310                 
311                 while (tot_data < ldata || tot_param < lparam)  {
312                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
313                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
314
315                         set_message(cli->outbuf,18,0,True);
316                         CVAL(cli->outbuf,smb_com) = SMBnttranss;
317
318                         /* XXX - these should probably be aligned */
319                         outparam = smb_buf(cli->outbuf);
320                         outdata = outparam+this_lparam;
321                         
322                         /* secondary request */
323                         SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
324                         SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
325                         SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
326                         SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
327                         SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
328                         SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
329                         SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
330                         SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
331                         if (this_lparam)                        /* param[] */
332                                 memcpy(outparam,param+tot_param,this_lparam);
333                         if (this_ldata)                 /* data[] */
334                                 memcpy(outdata,data+tot_data,this_ldata);
335                         cli_setup_bcc(cli, outdata+this_ldata);
336                         
337                         show_msg(cli->outbuf);
338                         cli_send_smb(cli);
339                         
340                         tot_data += this_ldata;
341                         tot_param += this_lparam;
342                 }
343         }
344
345         return(True);
346 }
347
348
349
350 /****************************************************************************
351   receive a SMB nttrans response allocating the necessary memory
352   ****************************************************************************/
353 BOOL cli_receive_nt_trans(struct cli_state *cli,
354                           char **param, int *param_len,
355                           char **data, int *data_len)
356 {
357         int total_data=0;
358         int total_param=0;
359         int this_data,this_param;
360         uint8 eclass;
361         uint32 ecode;
362
363         *data_len = *param_len = 0;
364
365         if (!cli_receive_smb(cli))
366                 return False;
367
368         show_msg(cli->inbuf);
369         
370         /* sanity check */
371         if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
372                 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
373                          CVAL(cli->inbuf,smb_com)));
374                 return(False);
375         }
376
377         /*
378          * An NT RPC pipe call can return ERRDOS, ERRmoredata
379          * to a trans call. This is not an error and should not
380          * be treated as such.
381          */
382         if (cli_error(cli, &eclass, &ecode, NULL)) {
383                 if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
384                         return(False);
385         }
386
387         /* parse out the lengths */
388         total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
389         total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
390
391         /* allocate it */
392         *data = Realloc(*data,total_data);
393         *param = Realloc(*param,total_param);
394
395         while (1)  {
396                 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
397                 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
398
399                 if (this_data + *data_len > total_data ||
400                     this_param + *param_len > total_param) {
401                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
402                         return False;
403                 }
404
405                 if (this_data)
406                         memcpy(*data + SVAL(cli->inbuf,smb_ntr_DataDisplacement),
407                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_ntr_DataOffset),
408                                this_data);
409                 if (this_param)
410                         memcpy(*param + SVAL(cli->inbuf,smb_ntr_ParameterDisplacement),
411                                smb_base(cli->inbuf) + SVAL(cli->inbuf,smb_ntr_ParameterOffset),
412                                this_param);
413                 *data_len += this_data;
414                 *param_len += this_param;
415
416                 /* parse out the total lengths again - they can shrink! */
417                 total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
418                 total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
419                 
420                 if (total_data <= *data_len && total_param <= *param_len)
421                         break;
422                 
423                 if (!cli_receive_smb(cli))
424                         return False;
425
426                 show_msg(cli->inbuf);
427                 
428                 /* sanity check */
429                 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
430                         DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
431                                  CVAL(cli->inbuf,smb_com)));
432                         return(False);
433                 }
434                 if (cli_error(cli, &eclass, &ecode, NULL)) {
435                         if(cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
436                                 return(False);
437                 }
438         }
439         
440         return(True);
441 }