Merge branch 'v3-2-test' of ssh://git.samba.org/data/git/samba into v3-2-test
[ira/wip.git] / source3 / 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 3 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, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21
22
23 /****************************************************************************
24  Send a SMB trans or trans2 request.
25 ****************************************************************************/
26
27 bool cli_send_trans(struct cli_state *cli, int trans,
28                     const char *pipe_name,
29                     int fid, int flags,
30                     uint16 *setup, unsigned int lsetup, unsigned int msetup,
31                     const char *param, unsigned int lparam, unsigned int mparam,
32                     const char *data, unsigned int ldata, unsigned int mdata)
33 {
34         unsigned int i;
35         unsigned int this_ldata,this_lparam;
36         unsigned int tot_data=0,tot_param=0;
37         char *outdata,*outparam;
38         char *p;
39         int pipe_name_len=0;
40         uint16 mid;
41
42         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
43         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
44
45         memset(cli->outbuf,'\0',smb_size);
46         cli_set_message(cli->outbuf,14+lsetup,0,True);
47         SCVAL(cli->outbuf,smb_com,trans);
48         SSVAL(cli->outbuf,smb_tid, cli->cnum);
49         cli_setup_packet(cli);
50
51         /*
52          * Save the mid we're using. We need this for finding
53          * signing replies.
54          */
55
56         mid = cli->mid;
57
58         if (pipe_name) {
59                 pipe_name_len = clistr_push(cli, smb_buf(cli->outbuf), pipe_name, -1, STR_TERMINATE);
60         }
61
62         outparam = smb_buf(cli->outbuf)+(trans==SMBtrans ? pipe_name_len : 3);
63         outdata = outparam+this_lparam;
64
65         /* primary request */
66         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
67         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
68         SSVAL(cli->outbuf,smb_mprcnt,mparam);   /* mprcnt */
69         SSVAL(cli->outbuf,smb_mdrcnt,mdata);    /* mdrcnt */
70         SCVAL(cli->outbuf,smb_msrcnt,msetup);   /* msrcnt */
71         SSVAL(cli->outbuf,smb_flags,flags);     /* flags */
72         SIVAL(cli->outbuf,smb_timeout,0);               /* timeout */
73         SSVAL(cli->outbuf,smb_pscnt,this_lparam);       /* pscnt */
74         SSVAL(cli->outbuf,smb_psoff,smb_offset(outparam,cli->outbuf)); /* psoff */
75         SSVAL(cli->outbuf,smb_dscnt,this_ldata);        /* dscnt */
76         SSVAL(cli->outbuf,smb_dsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
77         SCVAL(cli->outbuf,smb_suwcnt,lsetup);   /* suwcnt */
78         for (i=0;i<lsetup;i++)          /* setup[] */
79                 SSVAL(cli->outbuf,smb_setup+i*2,setup[i]);
80         p = smb_buf(cli->outbuf);
81         if (trans != SMBtrans) {
82                 *p++ = 0;  /* put in a null smb_name */
83                 *p++ = 'D'; *p++ = ' '; /* observed in OS/2 */
84         }
85         if (this_lparam)                        /* param[] */
86                 memcpy(outparam,param,this_lparam);
87         if (this_ldata)                 /* data[] */
88                 memcpy(outdata,data,this_ldata);
89         cli_setup_bcc(cli, outdata+this_ldata);
90
91         show_msg(cli->outbuf);
92
93         if (!cli_send_smb(cli)) {
94                 return False;
95         }
96
97         if (this_ldata < ldata || this_lparam < lparam) {
98                 /* receive interim response */
99                 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
100                         return(False);
101                 }
102
103                 tot_data = this_ldata;
104                 tot_param = this_lparam;
105
106                 while (tot_data < ldata || tot_param < lparam)  {
107                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
108                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
109
110                         cli_set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
111                         SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
112
113                         outparam = smb_buf(cli->outbuf);
114                         outdata = outparam+this_lparam;
115
116                         /* secondary request */
117                         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
118                         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
119                         SSVAL(cli->outbuf,smb_spscnt,this_lparam);      /* pscnt */
120                         SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
121                         SSVAL(cli->outbuf,smb_spsdisp,tot_param);       /* psdisp */
122                         SSVAL(cli->outbuf,smb_sdscnt,this_ldata);       /* dscnt */
123                         SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
124                         SSVAL(cli->outbuf,smb_sdsdisp,tot_data);        /* dsdisp */
125                         if (trans==SMBtrans2)
126                                 SSVALS(cli->outbuf,smb_sfid,fid);               /* fid */
127                         if (this_lparam)                        /* param[] */
128                                 memcpy(outparam,param+tot_param,this_lparam);
129                         if (this_ldata)                 /* data[] */
130                                 memcpy(outdata,data+tot_data,this_ldata);
131                         cli_setup_bcc(cli, outdata+this_ldata);
132
133                         /*
134                          * Save the mid we're using. We need this for finding
135                          * signing replies.
136                          */
137                         mid = cli->mid;
138
139                         show_msg(cli->outbuf);
140                         if (!cli_send_smb(cli)) {
141                                 return False;
142                         }
143
144                         /* Ensure we use the same mid for the secondaries. */
145                         cli->mid = mid;
146
147                         tot_data += this_ldata;
148                         tot_param += this_lparam;
149                 }
150         }
151
152         return(True);
153 }
154
155 /****************************************************************************
156  Receive a SMB trans or trans2 response allocating the necessary memory.
157 ****************************************************************************/
158
159 bool cli_receive_trans(struct cli_state *cli,int trans,
160                               char **param, unsigned int *param_len,
161                               char **data, unsigned int *data_len)
162 {
163         unsigned int total_data=0;
164         unsigned int total_param=0;
165         unsigned int this_data,this_param;
166         NTSTATUS status;
167         bool ret = False;
168
169         *data_len = *param_len = 0;
170
171         if (!cli_receive_smb(cli)) {
172                 return False;
173         }
174
175         show_msg(cli->inbuf);
176
177         /* sanity check */
178         if (CVAL(cli->inbuf,smb_com) != trans) {
179                 DEBUG(0,("Expected %s response, got command 0x%02x\n",
180                          trans==SMBtrans?"SMBtrans":"SMBtrans2",
181                          CVAL(cli->inbuf,smb_com)));
182                 return False;
183         }
184
185         /*
186          * An NT RPC pipe call can return ERRDOS, ERRmoredata
187          * to a trans call. This is not an error and should not
188          * be treated as such. Note that STATUS_NO_MORE_FILES is
189          * returned when a trans2 findfirst/next finishes.
190          * When setting up an encrypted transport we can also
191          * see NT_STATUS_MORE_PROCESSING_REQUIRED here.
192          *
193          * Vista returns NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT if the folder
194          * "<share>/Users/All Users" is enumerated.  This is a special pseudo
195          * folder, and the response does not have parameters (nor a parameter
196          * length).
197          */
198         status = cli_nt_error(cli);
199
200         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
201                 if (NT_STATUS_IS_ERR(status) ||
202                     NT_STATUS_EQUAL(status,STATUS_NO_MORE_FILES) ||
203                     NT_STATUS_EQUAL(status,NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
204                         goto out;
205                 }
206         }
207
208         /* parse out the lengths */
209         total_data = SVAL(cli->inbuf,smb_tdrcnt);
210         total_param = SVAL(cli->inbuf,smb_tprcnt);
211
212         /* allocate it */
213         if (total_data!=0) {
214                 /* We know adding 2 is safe as total_data is an
215                  * SVAL <= 0xFFFF. */
216                 *data = (char *)SMB_REALLOC(*data,total_data+2);
217                 if (!(*data)) {
218                         DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
219                         goto out;
220                 }
221         }
222
223         if (total_param!=0) {
224                 /* We know adding 2 is safe as total_param is an
225                  * SVAL <= 0xFFFF. */
226                 *param = (char *)SMB_REALLOC(*param,total_param+2);
227                 if (!(*param)) {
228                         DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
229                         goto out;
230                 }
231         }
232
233         for (;;)  {
234                 this_data = SVAL(cli->inbuf,smb_drcnt);
235                 this_param = SVAL(cli->inbuf,smb_prcnt);
236
237                 if (this_data + *data_len > total_data ||
238                     this_param + *param_len > total_param) {
239                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
240                         goto out;
241                 }
242
243                 if (this_data + *data_len < this_data ||
244                                 this_data + *data_len < *data_len ||
245                                 this_param + *param_len < this_param ||
246                                 this_param + *param_len < *param_len) {
247                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
248                         goto out;
249                 }
250
251                 if (this_data) {
252                         unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
253                         unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
254
255                         if (data_offset_out > total_data ||
256                                         data_offset_out + this_data > total_data ||
257                                         data_offset_out + this_data < data_offset_out ||
258                                         data_offset_out + this_data < this_data) {
259                                 DEBUG(1,("Data overflow in cli_receive_trans\n"));
260                                 goto out;
261                         }
262                         if (data_offset_in > cli->bufsize ||
263                                         data_offset_in + this_data >  cli->bufsize ||
264                                         data_offset_in + this_data < data_offset_in ||
265                                         data_offset_in + this_data < this_data) {
266                                 DEBUG(1,("Data overflow in cli_receive_trans\n"));
267                                 goto out;
268                         }
269
270                         memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
271                 }
272                 if (this_param) {
273                         unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
274                         unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
275
276                         if (param_offset_out > total_param ||
277                                         param_offset_out + this_param > total_param ||
278                                         param_offset_out + this_param < param_offset_out ||
279                                         param_offset_out + this_param < this_param) {
280                                 DEBUG(1,("Param overflow in cli_receive_trans\n"));
281                                 goto out;
282                         }
283                         if (param_offset_in > cli->bufsize ||
284                                         param_offset_in + this_param >  cli->bufsize ||
285                                         param_offset_in + this_param < param_offset_in ||
286                                         param_offset_in + this_param < this_param) {
287                                 DEBUG(1,("Param overflow in cli_receive_trans\n"));
288                                 goto out;
289                         }
290
291                         memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
292                 }
293                 *data_len += this_data;
294                 *param_len += this_param;
295
296                 if (total_data <= *data_len && total_param <= *param_len) {
297                         ret = True;
298                         break;
299                 }
300
301                 if (!cli_receive_smb(cli)) {
302                         goto out;
303                 }
304
305                 show_msg(cli->inbuf);
306
307                 /* sanity check */
308                 if (CVAL(cli->inbuf,smb_com) != trans) {
309                         DEBUG(0,("Expected %s response, got command 0x%02x\n",
310                                  trans==SMBtrans?"SMBtrans":"SMBtrans2", 
311                                  CVAL(cli->inbuf,smb_com)));
312                         goto out;
313                 }
314                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
315                         if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
316                                 goto out;
317                         }
318                 }
319
320                 /* parse out the total lengths again - they can shrink! */
321                 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
322                         total_data = SVAL(cli->inbuf,smb_tdrcnt);
323                 if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
324                         total_param = SVAL(cli->inbuf,smb_tprcnt);
325
326                 if (total_data <= *data_len && total_param <= *param_len) {
327                         ret = True;
328                         break;
329                 }
330         }
331
332   out:
333
334         if (ret) {
335                 /* Ensure the last 2 bytes of param and data are 2 null
336                  * bytes. These are malloc'ed, but not included in any
337                  * length counts. This allows cli_XX string reading functions
338                  * to safely null terminate. */
339                 if (total_data) {
340                         SSVAL(*data,total_data,0);
341                 }
342                 if (total_param) {
343                         SSVAL(*param,total_param,0);
344                 }
345         }
346
347         return ret;
348 }
349
350 /****************************************************************************
351  Send a SMB nttrans request.
352 ****************************************************************************/
353
354 bool cli_send_nt_trans(struct cli_state *cli,
355                        int function,
356                        int flags,
357                        uint16 *setup, unsigned int lsetup, unsigned int msetup,
358                        char *param, unsigned int lparam, unsigned int mparam,
359                        char *data, unsigned int ldata, unsigned int mdata)
360 {
361         unsigned int i;
362         unsigned int this_ldata,this_lparam;
363         unsigned int tot_data=0,tot_param=0;
364         uint16 mid;
365         char *outdata,*outparam;
366
367         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
368         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
369
370         memset(cli->outbuf,'\0',smb_size);
371         cli_set_message(cli->outbuf,19+lsetup,0,True);
372         SCVAL(cli->outbuf,smb_com,SMBnttrans);
373         SSVAL(cli->outbuf,smb_tid, cli->cnum);
374         cli_setup_packet(cli);
375
376         /*
377          * Save the mid we're using. We need this for finding
378          * signing replies.
379          */
380
381         mid = cli->mid;
382
383         outparam = smb_buf(cli->outbuf)+3;
384         outdata = outparam+this_lparam;
385
386         /* primary request */
387         SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
388         SCVAL(cli->outbuf,smb_nt_Flags,flags);
389         SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
390         SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
391         SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
392         SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
393         SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
394         SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
395         SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
396         SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
397         SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
398         SIVAL(cli->outbuf,smb_nt_Function, function);
399         for (i=0;i<lsetup;i++)          /* setup[] */
400                 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
401
402         if (this_lparam)                        /* param[] */
403                 memcpy(outparam,param,this_lparam);
404         if (this_ldata)                 /* data[] */
405                 memcpy(outdata,data,this_ldata);
406
407         cli_setup_bcc(cli, outdata+this_ldata);
408
409         show_msg(cli->outbuf);
410         if (!cli_send_smb(cli)) {
411                 return False;
412         }
413
414         if (this_ldata < ldata || this_lparam < lparam) {
415                 /* receive interim response */
416                 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
417                         return(False);
418                 }
419
420                 tot_data = this_ldata;
421                 tot_param = this_lparam;
422
423                 while (tot_data < ldata || tot_param < lparam)  {
424                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
425                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
426
427                         cli_set_message(cli->outbuf,18,0,True);
428                         SCVAL(cli->outbuf,smb_com,SMBnttranss);
429
430                         /* XXX - these should probably be aligned */
431                         outparam = smb_buf(cli->outbuf);
432                         outdata = outparam+this_lparam;
433
434                         /* secondary request */
435                         SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
436                         SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
437                         SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
438                         SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
439                         SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
440                         SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
441                         SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
442                         SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
443                         if (this_lparam)                        /* param[] */
444                                 memcpy(outparam,param+tot_param,this_lparam);
445                         if (this_ldata)                 /* data[] */
446                                 memcpy(outdata,data+tot_data,this_ldata);
447                         cli_setup_bcc(cli, outdata+this_ldata);
448
449                         /*
450                          * Save the mid we're using. We need this for finding
451                          * signing replies.
452                          */
453                         mid = cli->mid;
454
455                         show_msg(cli->outbuf);
456
457                         if (!cli_send_smb(cli)) {
458                                 return False;
459                         }
460
461                         /* Ensure we use the same mid for the secondaries. */
462                         cli->mid = mid;
463
464                         tot_data += this_ldata;
465                         tot_param += this_lparam;
466                 }
467         }
468
469         return(True);
470 }
471
472 /****************************************************************************
473  Receive a SMB nttrans response allocating the necessary memory.
474 ****************************************************************************/
475
476 bool cli_receive_nt_trans(struct cli_state *cli,
477                           char **param, unsigned int *param_len,
478                           char **data, unsigned int *data_len)
479 {
480         unsigned int total_data=0;
481         unsigned int total_param=0;
482         unsigned int this_data,this_param;
483         uint8 eclass;
484         uint32 ecode;
485         bool ret = False;
486
487         *data_len = *param_len = 0;
488
489         if (!cli_receive_smb(cli)) {
490                 return False;
491         }
492
493         show_msg(cli->inbuf);
494
495         /* sanity check */
496         if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
497                 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
498                          CVAL(cli->inbuf,smb_com)));
499                 return(False);
500         }
501
502         /*
503          * An NT RPC pipe call can return ERRDOS, ERRmoredata
504          * to a trans call. This is not an error and should not
505          * be treated as such.
506          */
507         if (cli_is_dos_error(cli)) {
508                 cli_dos_error(cli, &eclass, &ecode);
509                 if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
510                         goto out;
511                 }
512         }
513
514         /*
515          * Likewise for NT_STATUS_BUFFER_TOO_SMALL
516          */
517         if (cli_is_nt_error(cli)) {
518                 if (!NT_STATUS_EQUAL(cli_nt_error(cli),
519                                      NT_STATUS_BUFFER_TOO_SMALL)) {
520                         goto out;
521                 }
522         }
523
524         /* parse out the lengths */
525         total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
526         total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
527         /* Only allow 16 megs. */
528         if (total_param > 16*1024*1024) {
529                 DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n",
530                                         total_param));
531                 goto out;
532         }
533         if (total_data > 16*1024*1024) {
534                 DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n",
535                                         total_data));
536                 goto out;
537         }
538
539         /* allocate it */
540         if (total_data) {
541                 /* We know adding 2 is safe as total_data is less
542                  * than 16mb (above). */
543                 *data = (char *)SMB_REALLOC(*data,total_data+2);
544                 if (!(*data)) {
545                         DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
546                         goto out;
547                 }
548         }
549
550         if (total_param) {
551                 /* We know adding 2 is safe as total_param is less
552                  * than 16mb (above). */
553                 *param = (char *)SMB_REALLOC(*param,total_param+2);
554                 if (!(*param)) {
555                         DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
556                         goto out;
557                 }
558         }
559
560         while (1)  {
561                 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
562                 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
563
564                 if (this_data + *data_len > total_data ||
565                     this_param + *param_len > total_param) {
566                         DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
567                         goto out;
568                 }
569
570                 if (this_data + *data_len < this_data ||
571                                 this_data + *data_len < *data_len ||
572                                 this_param + *param_len < this_param ||
573                                 this_param + *param_len < *param_len) {
574                         DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
575                         goto out;
576                 }
577
578                 if (this_data) {
579                         unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
580                         unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
581
582                         if (data_offset_out > total_data ||
583                                         data_offset_out + this_data > total_data ||
584                                         data_offset_out + this_data < data_offset_out ||
585                                         data_offset_out + this_data < this_data) {
586                                 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
587                                 goto out;
588                         }
589                         if (data_offset_in > cli->bufsize ||
590                                         data_offset_in + this_data >  cli->bufsize ||
591                                         data_offset_in + this_data < data_offset_in ||
592                                         data_offset_in + this_data < this_data) {
593                                 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
594                                 goto out;
595                         }
596
597                         memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
598                 }
599
600                 if (this_param) {
601                         unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
602                         unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
603
604                         if (param_offset_out > total_param ||
605                                         param_offset_out + this_param > total_param ||
606                                         param_offset_out + this_param < param_offset_out ||
607                                         param_offset_out + this_param < this_param) {
608                                 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
609                                 goto out;
610                         }
611                         if (param_offset_in > cli->bufsize ||
612                                         param_offset_in + this_param >  cli->bufsize ||
613                                         param_offset_in + this_param < param_offset_in ||
614                                         param_offset_in + this_param < this_param) {
615                                 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
616                                 goto out;
617                         }
618
619                         memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
620                 }
621
622                 *data_len += this_data;
623                 *param_len += this_param;
624
625                 if (total_data <= *data_len && total_param <= *param_len) {
626                         ret = True;
627                         break;
628                 }
629
630                 if (!cli_receive_smb(cli)) {
631                         goto out;
632                 }
633
634                 show_msg(cli->inbuf);
635
636                 /* sanity check */
637                 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
638                         DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
639                                  CVAL(cli->inbuf,smb_com)));
640                         goto out;
641                 }
642                 if (cli_is_dos_error(cli)) {
643                         cli_dos_error(cli, &eclass, &ecode);
644                         if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
645                                 goto out;
646                         }
647                 }
648                 /*
649                  * Likewise for NT_STATUS_BUFFER_TOO_SMALL
650                  */
651                 if (cli_is_nt_error(cli)) {
652                         if (!NT_STATUS_EQUAL(cli_nt_error(cli),
653                                              NT_STATUS_BUFFER_TOO_SMALL)) {
654                                 goto out;
655                         }
656                 }
657
658                 /* parse out the total lengths again - they can shrink! */
659                 if (IVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
660                         total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
661                 if (IVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
662                         total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
663
664                 if (total_data <= *data_len && total_param <= *param_len) {
665                         ret = True;
666                         break;
667                 }
668         }
669
670   out:
671
672         if (ret) {
673                 /* Ensure the last 2 bytes of param and data are 2 null
674                  * bytes. These are malloc'ed, but not included in any
675                  * length counts. This allows cli_XX string reading functions
676                  * to safely null terminate. */
677                 if (total_data) {
678                         SSVAL(*data,total_data,0);
679                 }
680                 if (total_param) {
681                         SSVAL(*param,total_param,0);
682                 }
683         }
684
685         return ret;
686 }