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