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