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