Correct fix (removed the earlier band-aid) for what I thought was a signing
[samba.git] / source / libsmb / clitrans.c
1 /* 
2    Unix SMB/CIFS implementation.
3    client transaction calls
4    Copyright (C) Andrew Tridgell 1994-1998
5    
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.
10    
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.
15    
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.
19 */
20
21 #define NO_SYSLOG
22
23 #include "includes.h"
24
25
26 /****************************************************************************
27  Send a SMB trans or trans2 request.
28 ****************************************************************************/
29
30 BOOL cli_send_trans(struct cli_state *cli, int trans, 
31                     const char *pipe_name, 
32                     int fid, int flags,
33                     uint16 *setup, unsigned int lsetup, unsigned int msetup,
34                     const char *param, unsigned int lparam, unsigned int mparam,
35                     const char *data, unsigned int ldata, unsigned int mdata)
36 {
37         unsigned int i;
38         unsigned int this_ldata,this_lparam;
39         unsigned int tot_data=0,tot_param=0;
40         char *outdata,*outparam;
41         char *p;
42         int pipe_name_len=0;
43         uint16 mid;
44
45         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
46         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
47
48         memset(cli->outbuf,'\0',smb_size);
49         set_message(cli->outbuf,14+lsetup,0,True);
50         SCVAL(cli->outbuf,smb_com,trans);
51         SSVAL(cli->outbuf,smb_tid, cli->cnum);
52         cli_setup_packet(cli);
53         mid = cli->mid;
54
55         if (pipe_name) {
56                 pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, 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                 *p++ = 0;  /* put in a null smb_name */
80                 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
81         }
82         if (this_lparam)                        /* param[] */
83                 memcpy(outparam,param,this_lparam);
84         if (this_ldata)                 /* data[] */
85                 memcpy(outdata,data,this_ldata);
86         cli_setup_bcc(cli, outdata+this_ldata);
87
88         show_msg(cli->outbuf);
89
90         cli_signing_trans_start(cli);
91         if (!cli_send_smb(cli))
92                 return False;
93
94         if (this_ldata < ldata || this_lparam < lparam) {
95                 /* receive interim response */
96                 if (!cli_receive_smb(cli) || cli_is_error(cli))
97                         return(False);
98
99                 tot_data = this_ldata;
100                 tot_param = this_lparam;
101                 
102                 while (tot_data < ldata || tot_param < lparam)  {
103                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
104                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
105
106                         set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
107                         SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
108                         
109                         outparam = smb_buf(cli->outbuf);
110                         outdata = outparam+this_lparam;
111                         
112                         /* secondary request */
113                         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
114                         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
115                         SSVAL(cli->outbuf,smb_spscnt,this_lparam);      /* pscnt */
116                         SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
117                         SSVAL(cli->outbuf,smb_spsdisp,tot_param);       /* psdisp */
118                         SSVAL(cli->outbuf,smb_sdscnt,this_ldata);       /* dscnt */
119                         SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
120                         SSVAL(cli->outbuf,smb_sdsdisp,tot_data);        /* dsdisp */
121                         if (trans==SMBtrans2)
122                                 SSVALS(cli->outbuf,smb_sfid,fid);               /* fid */
123                         if (this_lparam)                        /* param[] */
124                                 memcpy(outparam,param+tot_param,this_lparam);
125                         if (this_ldata)                 /* data[] */
126                                 memcpy(outdata,data+tot_data,this_ldata);
127                         cli_setup_bcc(cli, outdata+this_ldata);
128                         
129                         /* Ensure this packet has the same MID as
130                          * the primary. Important in signing. JRA. */
131                         cli->mid = mid;
132
133                         show_msg(cli->outbuf);
134                         if (!cli_send_smb(cli))
135                                 return False;
136                         
137                         tot_data += this_ldata;
138                         tot_param += this_lparam;
139                 }
140         }
141
142         return(True);
143 }
144
145 /****************************************************************************
146  Receive a SMB trans or trans2 response allocating the necessary memory.
147 ****************************************************************************/
148
149 BOOL cli_receive_trans(struct cli_state *cli,int trans,
150                               char **param, unsigned int *param_len,
151                               char **data, unsigned int *data_len)
152 {
153         unsigned int total_data=0;
154         unsigned int total_param=0;
155         unsigned int this_data,this_param;
156         NTSTATUS status;
157         char *tdata;
158         char *tparam;
159
160         *data_len = *param_len = 0;
161
162         if (!cli_receive_smb(cli))
163                 return False;
164
165         show_msg(cli->inbuf);
166         
167         /* sanity check */
168         if (CVAL(cli->inbuf,smb_com) != trans) {
169                 DEBUG(0,("Expected %s response, got command 0x%02x\n",
170                          trans==SMBtrans?"SMBtrans":"SMBtrans2", 
171                          CVAL(cli->inbuf,smb_com)));
172                 return(False);
173         }
174
175         /*
176          * An NT RPC pipe call can return ERRDOS, ERRmoredata
177          * to a trans call. This is not an error and should not
178          * be treated as such.
179          */
180         status = cli_nt_error(cli);
181         
182         if (NT_STATUS_IS_ERR(status))
183                 return False;
184
185         /* parse out the lengths */
186         total_data = SVAL(cli->inbuf,smb_tdrcnt);
187         total_param = SVAL(cli->inbuf,smb_tprcnt);
188
189         /* allocate it */
190         if (total_data!=0) {
191                 tdata = Realloc(*data,total_data);
192                 if (!tdata) {
193                         DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
194                         return False;
195                 }
196                 else
197                         *data = tdata;
198         }
199
200         if (total_param!=0) {
201                 tparam = Realloc(*param,total_param);
202                 if (!tparam) {
203                         DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
204                         return False;
205                 }
206                 else
207                         *param = tparam;
208         }
209
210         for (;;)  {
211                 this_data = SVAL(cli->inbuf,smb_drcnt);
212                 this_param = SVAL(cli->inbuf,smb_prcnt);
213
214                 if (this_data + *data_len > total_data ||
215                     this_param + *param_len > total_param) {
216                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
217                         return False;
218                 }
219
220                 if (this_data + *data_len < this_data ||
221                                 this_data + *data_len < *data_len ||
222                                 this_param + *param_len < this_param ||
223                                 this_param + *param_len < *param_len) {
224                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
225                         return False;
226                 }
227
228                 if (this_data) {
229                         unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
230                         unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
231
232                         if (data_offset_out > total_data ||
233                                         data_offset_out + this_data > total_data ||
234                                         data_offset_out + this_data < data_offset_out ||
235                                         data_offset_out + this_data < this_data) {
236                                 DEBUG(1,("Data overflow in cli_receive_trans\n"));
237                                 return False;
238                         }
239                         if (data_offset_in > cli->bufsize ||
240                                         data_offset_in + this_data >  cli->bufsize ||
241                                         data_offset_in + this_data < data_offset_in ||
242                                         data_offset_in + this_data < this_data) {
243                                 DEBUG(1,("Data overflow in cli_receive_trans\n"));
244                                 return False;
245                         }
246
247                         memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
248                 }
249                 if (this_param) {
250                         unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
251                         unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
252
253                         if (param_offset_out > total_param ||
254                                         param_offset_out + this_param > total_param ||
255                                         param_offset_out + this_param < param_offset_out ||
256                                         param_offset_out + this_param < this_param) {
257                                 DEBUG(1,("Param overflow in cli_receive_trans\n"));
258                                 return False;
259                         }
260                         if (param_offset_in > cli->bufsize ||
261                                         param_offset_in + this_param >  cli->bufsize ||
262                                         param_offset_in + this_param < param_offset_in ||
263                                         param_offset_in + this_param < this_param) {
264                                 DEBUG(1,("Param overflow in cli_receive_trans\n"));
265                                 return False;
266                         }
267
268                         memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
269                 }
270                 *data_len += this_data;
271                 *param_len += this_param;
272
273                 if (total_data <= *data_len && total_param <= *param_len)
274                         break;
275                 
276                 if (!cli_receive_smb(cli))
277                         return False;
278
279                 show_msg(cli->inbuf);
280                 
281                 /* sanity check */
282                 if (CVAL(cli->inbuf,smb_com) != trans) {
283                         DEBUG(0,("Expected %s response, got command 0x%02x\n",
284                                  trans==SMBtrans?"SMBtrans":"SMBtrans2", 
285                                  CVAL(cli->inbuf,smb_com)));
286                         return(False);
287                 }
288                 if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
289                         return(False);
290                 }
291
292                 /* parse out the total lengths again - they can shrink! */
293                 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
294                         total_data = SVAL(cli->inbuf,smb_tdrcnt);
295                 if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
296                         total_param = SVAL(cli->inbuf,smb_tprcnt);
297                 
298                 if (total_data <= *data_len && total_param <= *param_len)
299                         break;
300                 
301         }
302         
303         cli_signing_trans_stop(cli);
304         return(True);
305 }
306
307 /****************************************************************************
308  Send a SMB nttrans request.
309 ****************************************************************************/
310
311 BOOL cli_send_nt_trans(struct cli_state *cli, 
312                        int function, 
313                        int flags,
314                        uint16 *setup, unsigned int lsetup, unsigned int msetup,
315                        char *param, unsigned int lparam, unsigned int mparam,
316                        char *data, unsigned int ldata, unsigned int mdata)
317 {
318         unsigned int i;
319         unsigned int this_ldata,this_lparam;
320         unsigned int tot_data=0,tot_param=0;
321         uint16 mid;
322         char *outdata,*outparam;
323
324         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
325         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
326
327         memset(cli->outbuf,'\0',smb_size);
328         set_message(cli->outbuf,19+lsetup,0,True);
329         SCVAL(cli->outbuf,smb_com,SMBnttrans);
330         SSVAL(cli->outbuf,smb_tid, cli->cnum);
331         cli_setup_packet(cli);
332         mid = cli->mid;
333
334         outparam = smb_buf(cli->outbuf)+3;
335         outdata = outparam+this_lparam;
336
337         /* primary request */
338         SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
339         SCVAL(cli->outbuf,smb_nt_Flags,flags);
340         SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
341         SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
342         SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
343         SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
344         SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
345         SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
346         SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
347         SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
348         SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
349         SIVAL(cli->outbuf,smb_nt_Function, function);
350         for (i=0;i<lsetup;i++)          /* setup[] */
351                 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
352         
353         if (this_lparam)                        /* param[] */
354                 memcpy(outparam,param,this_lparam);
355         if (this_ldata)                 /* data[] */
356                 memcpy(outdata,data,this_ldata);
357
358         cli_setup_bcc(cli, outdata+this_ldata);
359
360         show_msg(cli->outbuf);
361         cli_signing_trans_start(cli);
362         if (!cli_send_smb(cli))
363                 return False;
364
365         if (this_ldata < ldata || this_lparam < lparam) {
366                 /* receive interim response */
367                 if (!cli_receive_smb(cli) || cli_is_error(cli))
368                         return(False);
369
370                 tot_data = this_ldata;
371                 tot_param = this_lparam;
372                 
373                 while (tot_data < ldata || tot_param < lparam)  {
374                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
375                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
376
377                         set_message(cli->outbuf,18,0,True);
378                         SCVAL(cli->outbuf,smb_com,SMBnttranss);
379
380                         /* XXX - these should probably be aligned */
381                         outparam = smb_buf(cli->outbuf);
382                         outdata = outparam+this_lparam;
383                         
384                         /* secondary request */
385                         SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
386                         SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
387                         SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
388                         SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
389                         SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
390                         SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
391                         SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
392                         SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
393                         if (this_lparam)                        /* param[] */
394                                 memcpy(outparam,param+tot_param,this_lparam);
395                         if (this_ldata)                 /* data[] */
396                                 memcpy(outdata,data+tot_data,this_ldata);
397                         cli_setup_bcc(cli, outdata+this_ldata);
398                         
399                         /* Ensure this packet has the same MID as
400                          * the primary. Important in signing. JRA. */
401                         cli->mid = mid;
402
403                         show_msg(cli->outbuf);
404
405                         if (!cli_send_smb(cli))
406                                 return False;
407                         
408                         tot_data += this_ldata;
409                         tot_param += this_lparam;
410                 }
411         }
412
413         return(True);
414 }
415
416
417
418 /****************************************************************************
419   receive a SMB nttrans response allocating the necessary memory
420   ****************************************************************************/
421
422 BOOL cli_receive_nt_trans(struct cli_state *cli,
423                           char **param, unsigned int *param_len,
424                           char **data, unsigned int *data_len)
425 {
426         unsigned int total_data=0;
427         unsigned int total_param=0;
428         unsigned int this_data,this_param;
429         uint8 eclass;
430         uint32 ecode;
431         char *tdata;
432         char *tparam;
433
434         *data_len = *param_len = 0;
435
436         if (!cli_receive_smb(cli))
437                 return False;
438
439         show_msg(cli->inbuf);
440         
441         /* sanity check */
442         if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
443                 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
444                          CVAL(cli->inbuf,smb_com)));
445                 return(False);
446         }
447
448         /*
449          * An NT RPC pipe call can return ERRDOS, ERRmoredata
450          * to a trans call. This is not an error and should not
451          * be treated as such.
452          */
453         if (cli_is_dos_error(cli)) {
454                 cli_dos_error(cli, &eclass, &ecode);
455                 if (cli->nt_pipe_fnum == 0 || !(eclass == ERRDOS && ecode == ERRmoredata))
456                         return(False);
457         }
458
459         /* parse out the lengths */
460         total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
461         total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
462
463         /* allocate it */
464         if (total_data) {
465                 tdata = Realloc(*data,total_data);
466                 if (!tdata) {
467                         DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
468                         return False;
469                 } else {
470                         *data = tdata;
471                 }
472         }
473
474         if (total_param) {
475                 tparam = Realloc(*param,total_param);
476                 if (!tparam) {
477                         DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
478                         return False;
479                 } else {
480                         *param = tparam;
481                 }
482         }
483
484         while (1)  {
485                 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
486                 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
487
488                 if (this_data + *data_len > total_data ||
489                     this_param + *param_len > total_param) {
490                         DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
491                         return False;
492                 }
493
494                 if (this_data + *data_len < this_data ||
495                                 this_data + *data_len < *data_len ||
496                                 this_param + *param_len < this_param ||
497                                 this_param + *param_len < *param_len) {
498                         DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
499                         return False;
500                 }
501
502                 if (this_data) {
503                         unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
504                         unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
505
506                         if (data_offset_out > total_data ||
507                                         data_offset_out + this_data > total_data ||
508                                         data_offset_out + this_data < data_offset_out ||
509                                         data_offset_out + this_data < this_data) {
510                                 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
511                                 return False;
512                         }
513                         if (data_offset_in > cli->bufsize ||
514                                         data_offset_in + this_data >  cli->bufsize ||
515                                         data_offset_in + this_data < data_offset_in ||
516                                         data_offset_in + this_data < this_data) {
517                                 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
518                                 return False;
519                         }
520
521                         memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
522                 }
523
524                 if (this_param) {
525                         unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
526                         unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
527
528                         if (param_offset_out > total_param ||
529                                         param_offset_out + this_param > total_param ||
530                                         param_offset_out + this_param < param_offset_out ||
531                                         param_offset_out + this_param < this_param) {
532                                 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
533                                 return False;
534                         }
535                         if (param_offset_in > cli->bufsize ||
536                                         param_offset_in + this_param >  cli->bufsize ||
537                                         param_offset_in + this_param < param_offset_in ||
538                                         param_offset_in + this_param < this_param) {
539                                 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
540                                 return False;
541                         }
542
543                         memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
544                 }
545
546                 *data_len += this_data;
547                 *param_len += this_param;
548
549                 if (total_data <= *data_len && total_param <= *param_len)
550                         break;
551                 
552                 if (!cli_receive_smb(cli))
553                         return False;
554
555                 show_msg(cli->inbuf);
556                 
557                 /* sanity check */
558                 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
559                         DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
560                                  CVAL(cli->inbuf,smb_com)));
561                         return(False);
562                 }
563                 if (cli_is_dos_error(cli)) {
564                         cli_dos_error(cli, &eclass, &ecode);
565                         if(cli->nt_pipe_fnum == 0 || 
566                            !(eclass == ERRDOS && ecode == ERRmoredata))
567                                 return(False);
568                 }
569                 /* parse out the total lengths again - they can shrink! */
570                 if (SVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
571                         total_data = SVAL(cli->inbuf,smb_ntr_TotalDataCount);
572                 if (SVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
573                         total_param = SVAL(cli->inbuf,smb_ntr_TotalParameterCount);
574                 
575                 if (total_data <= *data_len && total_param <= *param_len)
576                         break;
577         }
578         
579         cli_signing_trans_stop(cli);
580         return(True);
581 }