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