s3: Explicitly handle inbuf in cli_trans_done
[sfrench/samba-autobuild/.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         cli_state_seqnum_persistent(cli, mid);
98
99         if (this_ldata < ldata || this_lparam < lparam) {
100                 /* receive interim response */
101                 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
102                         cli_state_seqnum_remove(cli, mid);
103                         return(False);
104                 }
105
106                 tot_data = this_ldata;
107                 tot_param = this_lparam;
108
109                 while (tot_data < ldata || tot_param < lparam)  {
110                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
111                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
112
113                         cli_set_message(cli->outbuf,trans==SMBtrans?8:9,0,True);
114                         SCVAL(cli->outbuf,smb_com,(trans==SMBtrans ? SMBtranss : SMBtranss2));
115
116                         outparam = smb_buf(cli->outbuf);
117                         outdata = outparam+this_lparam;
118
119                         /* secondary request */
120                         SSVAL(cli->outbuf,smb_tpscnt,lparam);   /* tpscnt */
121                         SSVAL(cli->outbuf,smb_tdscnt,ldata);    /* tdscnt */
122                         SSVAL(cli->outbuf,smb_spscnt,this_lparam);      /* pscnt */
123                         SSVAL(cli->outbuf,smb_spsoff,smb_offset(outparam,cli->outbuf)); /* psoff */
124                         SSVAL(cli->outbuf,smb_spsdisp,tot_param);       /* psdisp */
125                         SSVAL(cli->outbuf,smb_sdscnt,this_ldata);       /* dscnt */
126                         SSVAL(cli->outbuf,smb_sdsoff,smb_offset(outdata,cli->outbuf)); /* dsoff */
127                         SSVAL(cli->outbuf,smb_sdsdisp,tot_data);        /* dsdisp */
128                         if (trans==SMBtrans2)
129                                 SSVALS(cli->outbuf,smb_sfid,fid);               /* fid */
130                         if (this_lparam)                        /* param[] */
131                                 memcpy(outparam,param+tot_param,this_lparam);
132                         if (this_ldata)                 /* data[] */
133                                 memcpy(outdata,data+tot_data,this_ldata);
134                         cli_setup_bcc(cli, outdata+this_ldata);
135
136                         show_msg(cli->outbuf);
137
138                         cli->mid = mid;
139                         if (!cli_send_smb(cli)) {
140                                 cli_state_seqnum_remove(cli, mid);
141                                 return False;
142                         }
143
144                         tot_data += this_ldata;
145                         tot_param += this_lparam;
146                 }
147         }
148
149         return(True);
150 }
151
152 /****************************************************************************
153  Receive a SMB trans or trans2 response allocating the necessary memory.
154 ****************************************************************************/
155
156 bool cli_receive_trans(struct cli_state *cli,int trans,
157                               char **param, unsigned int *param_len,
158                               char **data, unsigned int *data_len)
159 {
160         unsigned int total_data=0;
161         unsigned int total_param=0;
162         unsigned int this_data,this_param;
163         NTSTATUS status;
164         bool ret = False;
165         uint16_t mid;
166
167         *data_len = *param_len = 0;
168
169         mid = SVAL(cli->outbuf,smb_mid);
170
171         if (!cli_receive_smb(cli)) {
172                 cli_state_seqnum_remove(cli, mid);
173                 return False;
174         }
175
176         show_msg(cli->inbuf);
177
178         /* sanity check */
179         if (CVAL(cli->inbuf,smb_com) != trans) {
180                 DEBUG(0,("Expected %s response, got command 0x%02x\n",
181                          trans==SMBtrans?"SMBtrans":"SMBtrans2",
182                          CVAL(cli->inbuf,smb_com)));
183                 cli_state_seqnum_remove(cli, mid);
184                 return False;
185         }
186
187         /*
188          * An NT RPC pipe call can return ERRDOS, ERRmoredata
189          * to a trans call. This is not an error and should not
190          * be treated as such. Note that STATUS_NO_MORE_FILES is
191          * returned when a trans2 findfirst/next finishes.
192          * When setting up an encrypted transport we can also
193          * see NT_STATUS_MORE_PROCESSING_REQUIRED here.
194          *
195          * Vista returns NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT if the folder
196          * "<share>/Users/All Users" is enumerated.  This is a special pseudo
197          * folder, and the response does not have parameters (nor a parameter
198          * length).
199          */
200         status = cli_nt_error(cli);
201
202         if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
203                 if (NT_STATUS_IS_ERR(status) ||
204                     NT_STATUS_EQUAL(status,STATUS_NO_MORE_FILES) ||
205                     NT_STATUS_EQUAL(status,NT_STATUS_INACCESSIBLE_SYSTEM_SHORTCUT)) {
206                         goto out;
207                 }
208         }
209
210         /* parse out the lengths */
211         total_data = SVAL(cli->inbuf,smb_tdrcnt);
212         total_param = SVAL(cli->inbuf,smb_tprcnt);
213
214         /* allocate it */
215         if (total_data!=0) {
216                 /* We know adding 2 is safe as total_data is an
217                  * SVAL <= 0xFFFF. */
218                 *data = (char *)SMB_REALLOC(*data,total_data+2);
219                 if (!(*data)) {
220                         DEBUG(0,("cli_receive_trans: failed to enlarge data buffer\n"));
221                         goto out;
222                 }
223         }
224
225         if (total_param!=0) {
226                 /* We know adding 2 is safe as total_param is an
227                  * SVAL <= 0xFFFF. */
228                 *param = (char *)SMB_REALLOC(*param,total_param+2);
229                 if (!(*param)) {
230                         DEBUG(0,("cli_receive_trans: failed to enlarge param buffer\n"));
231                         goto out;
232                 }
233         }
234
235         for (;;)  {
236                 this_data = SVAL(cli->inbuf,smb_drcnt);
237                 this_param = SVAL(cli->inbuf,smb_prcnt);
238
239                 if (this_data + *data_len > total_data ||
240                     this_param + *param_len > total_param) {
241                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
242                         goto out;
243                 }
244
245                 if (this_data + *data_len < this_data ||
246                                 this_data + *data_len < *data_len ||
247                                 this_param + *param_len < this_param ||
248                                 this_param + *param_len < *param_len) {
249                         DEBUG(1,("Data overflow in cli_receive_trans\n"));
250                         goto out;
251                 }
252
253                 if (this_data) {
254                         unsigned int data_offset_out = SVAL(cli->inbuf,smb_drdisp);
255                         unsigned int data_offset_in = SVAL(cli->inbuf,smb_droff);
256
257                         if (data_offset_out > total_data ||
258                                         data_offset_out + this_data > total_data ||
259                                         data_offset_out + this_data < data_offset_out ||
260                                         data_offset_out + this_data < this_data) {
261                                 DEBUG(1,("Data overflow in cli_receive_trans\n"));
262                                 goto out;
263                         }
264                         if (data_offset_in > cli->bufsize ||
265                                         data_offset_in + this_data >  cli->bufsize ||
266                                         data_offset_in + this_data < data_offset_in ||
267                                         data_offset_in + this_data < this_data) {
268                                 DEBUG(1,("Data overflow in cli_receive_trans\n"));
269                                 goto out;
270                         }
271
272                         memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
273                 }
274                 if (this_param) {
275                         unsigned int param_offset_out = SVAL(cli->inbuf,smb_prdisp);
276                         unsigned int param_offset_in = SVAL(cli->inbuf,smb_proff);
277
278                         if (param_offset_out > total_param ||
279                                         param_offset_out + this_param > total_param ||
280                                         param_offset_out + this_param < param_offset_out ||
281                                         param_offset_out + this_param < this_param) {
282                                 DEBUG(1,("Param overflow in cli_receive_trans\n"));
283                                 goto out;
284                         }
285                         if (param_offset_in > cli->bufsize ||
286                                         param_offset_in + this_param >  cli->bufsize ||
287                                         param_offset_in + this_param < param_offset_in ||
288                                         param_offset_in + this_param < this_param) {
289                                 DEBUG(1,("Param overflow in cli_receive_trans\n"));
290                                 goto out;
291                         }
292
293                         memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
294                 }
295                 *data_len += this_data;
296                 *param_len += this_param;
297
298                 if (total_data <= *data_len && total_param <= *param_len) {
299                         ret = True;
300                         break;
301                 }
302
303                 if (!cli_receive_smb(cli)) {
304                         goto out;
305                 }
306
307                 show_msg(cli->inbuf);
308
309                 /* sanity check */
310                 if (CVAL(cli->inbuf,smb_com) != trans) {
311                         DEBUG(0,("Expected %s response, got command 0x%02x\n",
312                                  trans==SMBtrans?"SMBtrans":"SMBtrans2", 
313                                  CVAL(cli->inbuf,smb_com)));
314                         goto out;
315                 }
316                 if (!NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
317                         if (NT_STATUS_IS_ERR(cli_nt_error(cli))) {
318                                 goto out;
319                         }
320                 }
321
322                 /* parse out the total lengths again - they can shrink! */
323                 if (SVAL(cli->inbuf,smb_tdrcnt) < total_data)
324                         total_data = SVAL(cli->inbuf,smb_tdrcnt);
325                 if (SVAL(cli->inbuf,smb_tprcnt) < total_param)
326                         total_param = SVAL(cli->inbuf,smb_tprcnt);
327
328                 if (total_data <= *data_len && total_param <= *param_len) {
329                         ret = True;
330                         break;
331                 }
332         }
333
334   out:
335
336         cli_state_seqnum_remove(cli, mid);
337
338         if (ret) {
339                 /* Ensure the last 2 bytes of param and data are 2 null
340                  * bytes. These are malloc'ed, but not included in any
341                  * length counts. This allows cli_XX string reading functions
342                  * to safely null terminate. */
343                 if (total_data) {
344                         SSVAL(*data,total_data,0);
345                 }
346                 if (total_param) {
347                         SSVAL(*param,total_param,0);
348                 }
349         }
350
351         return ret;
352 }
353
354 /****************************************************************************
355  Send a SMB nttrans request.
356 ****************************************************************************/
357
358 bool cli_send_nt_trans(struct cli_state *cli,
359                        int function,
360                        int flags,
361                        uint16 *setup, unsigned int lsetup, unsigned int msetup,
362                        char *param, unsigned int lparam, unsigned int mparam,
363                        char *data, unsigned int ldata, unsigned int mdata)
364 {
365         unsigned int i;
366         unsigned int this_ldata,this_lparam;
367         unsigned int tot_data=0,tot_param=0;
368         uint16 mid;
369         char *outdata,*outparam;
370
371         this_lparam = MIN(lparam,cli->max_xmit - (500+lsetup*2)); /* hack */
372         this_ldata = MIN(ldata,cli->max_xmit - (500+lsetup*2+this_lparam));
373
374         memset(cli->outbuf,'\0',smb_size);
375         cli_set_message(cli->outbuf,19+lsetup,0,True);
376         SCVAL(cli->outbuf,smb_com,SMBnttrans);
377         SSVAL(cli->outbuf,smb_tid, cli->cnum);
378         cli_setup_packet(cli);
379
380         /*
381          * Save the mid we're using. We need this for finding
382          * signing replies.
383          */
384
385         mid = cli->mid;
386
387         outparam = smb_buf(cli->outbuf)+3;
388         outdata = outparam+this_lparam;
389
390         /* primary request */
391         SCVAL(cli->outbuf,smb_nt_MaxSetupCount,msetup);
392         SCVAL(cli->outbuf,smb_nt_Flags,flags);
393         SIVAL(cli->outbuf,smb_nt_TotalParameterCount, lparam);
394         SIVAL(cli->outbuf,smb_nt_TotalDataCount, ldata);
395         SIVAL(cli->outbuf,smb_nt_MaxParameterCount, mparam);
396         SIVAL(cli->outbuf,smb_nt_MaxDataCount, mdata);
397         SIVAL(cli->outbuf,smb_nt_ParameterCount, this_lparam);
398         SIVAL(cli->outbuf,smb_nt_ParameterOffset, smb_offset(outparam,cli->outbuf));
399         SIVAL(cli->outbuf,smb_nt_DataCount, this_ldata);
400         SIVAL(cli->outbuf,smb_nt_DataOffset, smb_offset(outdata,cli->outbuf));
401         SIVAL(cli->outbuf,smb_nt_SetupCount, lsetup);
402         SIVAL(cli->outbuf,smb_nt_Function, function);
403         for (i=0;i<lsetup;i++)          /* setup[] */
404                 SSVAL(cli->outbuf,smb_nt_SetupStart+i*2,setup[i]);
405
406         if (this_lparam)                        /* param[] */
407                 memcpy(outparam,param,this_lparam);
408         if (this_ldata)                 /* data[] */
409                 memcpy(outdata,data,this_ldata);
410
411         cli_setup_bcc(cli, outdata+this_ldata);
412
413         show_msg(cli->outbuf);
414         if (!cli_send_smb(cli)) {
415                 return False;
416         }
417
418         cli_state_seqnum_persistent(cli, mid);
419
420         if (this_ldata < ldata || this_lparam < lparam) {
421                 /* receive interim response */
422                 if (!cli_receive_smb(cli) || cli_is_error(cli)) {
423                         cli_state_seqnum_remove(cli, mid);
424                         return(False);
425                 }
426
427                 tot_data = this_ldata;
428                 tot_param = this_lparam;
429
430                 while (tot_data < ldata || tot_param < lparam)  {
431                         this_lparam = MIN(lparam-tot_param,cli->max_xmit - 500); /* hack */
432                         this_ldata = MIN(ldata-tot_data,cli->max_xmit - (500+this_lparam));
433
434                         cli_set_message(cli->outbuf,18,0,True);
435                         SCVAL(cli->outbuf,smb_com,SMBnttranss);
436
437                         /* XXX - these should probably be aligned */
438                         outparam = smb_buf(cli->outbuf);
439                         outdata = outparam+this_lparam;
440
441                         /* secondary request */
442                         SIVAL(cli->outbuf,smb_nts_TotalParameterCount,lparam);
443                         SIVAL(cli->outbuf,smb_nts_TotalDataCount,ldata);
444                         SIVAL(cli->outbuf,smb_nts_ParameterCount,this_lparam);
445                         SIVAL(cli->outbuf,smb_nts_ParameterOffset,smb_offset(outparam,cli->outbuf));
446                         SIVAL(cli->outbuf,smb_nts_ParameterDisplacement,tot_param);
447                         SIVAL(cli->outbuf,smb_nts_DataCount,this_ldata);
448                         SIVAL(cli->outbuf,smb_nts_DataOffset,smb_offset(outdata,cli->outbuf));
449                         SIVAL(cli->outbuf,smb_nts_DataDisplacement,tot_data);
450                         if (this_lparam)                        /* param[] */
451                                 memcpy(outparam,param+tot_param,this_lparam);
452                         if (this_ldata)                 /* data[] */
453                                 memcpy(outdata,data+tot_data,this_ldata);
454                         cli_setup_bcc(cli, outdata+this_ldata);
455
456                         show_msg(cli->outbuf);
457
458                         cli->mid = mid;
459                         if (!cli_send_smb(cli)) {
460                                 cli_state_seqnum_remove(cli, mid);
461                                 return False;
462                         }
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         uint16_t mid;
487
488         *data_len = *param_len = 0;
489
490         mid = SVAL(cli->outbuf,smb_mid);
491
492         if (!cli_receive_smb(cli)) {
493                 cli_state_seqnum_remove(cli, mid);
494                 return False;
495         }
496
497         show_msg(cli->inbuf);
498
499         /* sanity check */
500         if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
501                 DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
502                          CVAL(cli->inbuf,smb_com)));
503                 cli_state_seqnum_remove(cli, mid);
504                 return(False);
505         }
506
507         /*
508          * An NT RPC pipe call can return ERRDOS, ERRmoredata
509          * to a trans call. This is not an error and should not
510          * be treated as such.
511          */
512         if (cli_is_dos_error(cli)) {
513                 cli_dos_error(cli, &eclass, &ecode);
514                 if (!(eclass == ERRDOS && ecode == ERRmoredata)) {
515                         goto out;
516                 }
517         }
518
519         /*
520          * Likewise for NT_STATUS_BUFFER_TOO_SMALL
521          */
522         if (cli_is_nt_error(cli)) {
523                 if (!NT_STATUS_EQUAL(cli_nt_error(cli),
524                                      NT_STATUS_BUFFER_TOO_SMALL)) {
525                         goto out;
526                 }
527         }
528
529         /* parse out the lengths */
530         total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
531         total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
532         /* Only allow 16 megs. */
533         if (total_param > 16*1024*1024) {
534                 DEBUG(0,("cli_receive_nt_trans: param buffer too large %d\n",
535                                         total_param));
536                 goto out;
537         }
538         if (total_data > 16*1024*1024) {
539                 DEBUG(0,("cli_receive_nt_trans: data buffer too large %d\n",
540                                         total_data));
541                 goto out;
542         }
543
544         /* allocate it */
545         if (total_data) {
546                 /* We know adding 2 is safe as total_data is less
547                  * than 16mb (above). */
548                 *data = (char *)SMB_REALLOC(*data,total_data+2);
549                 if (!(*data)) {
550                         DEBUG(0,("cli_receive_nt_trans: failed to enlarge data buffer to %d\n",total_data));
551                         goto out;
552                 }
553         }
554
555         if (total_param) {
556                 /* We know adding 2 is safe as total_param is less
557                  * than 16mb (above). */
558                 *param = (char *)SMB_REALLOC(*param,total_param+2);
559                 if (!(*param)) {
560                         DEBUG(0,("cli_receive_nt_trans: failed to enlarge param buffer to %d\n", total_param));
561                         goto out;
562                 }
563         }
564
565         while (1)  {
566                 this_data = SVAL(cli->inbuf,smb_ntr_DataCount);
567                 this_param = SVAL(cli->inbuf,smb_ntr_ParameterCount);
568
569                 if (this_data + *data_len > total_data ||
570                     this_param + *param_len > total_param) {
571                         DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
572                         goto out;
573                 }
574
575                 if (this_data + *data_len < this_data ||
576                                 this_data + *data_len < *data_len ||
577                                 this_param + *param_len < this_param ||
578                                 this_param + *param_len < *param_len) {
579                         DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
580                         goto out;
581                 }
582
583                 if (this_data) {
584                         unsigned int data_offset_out = SVAL(cli->inbuf,smb_ntr_DataDisplacement);
585                         unsigned int data_offset_in = SVAL(cli->inbuf,smb_ntr_DataOffset);
586
587                         if (data_offset_out > total_data ||
588                                         data_offset_out + this_data > total_data ||
589                                         data_offset_out + this_data < data_offset_out ||
590                                         data_offset_out + this_data < this_data) {
591                                 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
592                                 goto out;
593                         }
594                         if (data_offset_in > cli->bufsize ||
595                                         data_offset_in + this_data >  cli->bufsize ||
596                                         data_offset_in + this_data < data_offset_in ||
597                                         data_offset_in + this_data < this_data) {
598                                 DEBUG(1,("Data overflow in cli_receive_nt_trans\n"));
599                                 goto out;
600                         }
601
602                         memcpy(*data + data_offset_out, smb_base(cli->inbuf) + data_offset_in, this_data);
603                 }
604
605                 if (this_param) {
606                         unsigned int param_offset_out = SVAL(cli->inbuf,smb_ntr_ParameterDisplacement);
607                         unsigned int param_offset_in = SVAL(cli->inbuf,smb_ntr_ParameterOffset);
608
609                         if (param_offset_out > total_param ||
610                                         param_offset_out + this_param > total_param ||
611                                         param_offset_out + this_param < param_offset_out ||
612                                         param_offset_out + this_param < this_param) {
613                                 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
614                                 goto out;
615                         }
616                         if (param_offset_in > cli->bufsize ||
617                                         param_offset_in + this_param >  cli->bufsize ||
618                                         param_offset_in + this_param < param_offset_in ||
619                                         param_offset_in + this_param < this_param) {
620                                 DEBUG(1,("Param overflow in cli_receive_nt_trans\n"));
621                                 goto out;
622                         }
623
624                         memcpy(*param + param_offset_out, smb_base(cli->inbuf) + param_offset_in, this_param);
625                 }
626
627                 *data_len += this_data;
628                 *param_len += this_param;
629
630                 if (total_data <= *data_len && total_param <= *param_len) {
631                         ret = True;
632                         break;
633                 }
634
635                 if (!cli_receive_smb(cli)) {
636                         goto out;
637                 }
638
639                 show_msg(cli->inbuf);
640
641                 /* sanity check */
642                 if (CVAL(cli->inbuf,smb_com) != SMBnttrans) {
643                         DEBUG(0,("Expected SMBnttrans response, got command 0x%02x\n",
644                                  CVAL(cli->inbuf,smb_com)));
645                         goto out;
646                 }
647                 if (cli_is_dos_error(cli)) {
648                         cli_dos_error(cli, &eclass, &ecode);
649                         if(!(eclass == ERRDOS && ecode == ERRmoredata)) {
650                                 goto out;
651                         }
652                 }
653                 /*
654                  * Likewise for NT_STATUS_BUFFER_TOO_SMALL
655                  */
656                 if (cli_is_nt_error(cli)) {
657                         if (!NT_STATUS_EQUAL(cli_nt_error(cli),
658                                              NT_STATUS_BUFFER_TOO_SMALL)) {
659                                 goto out;
660                         }
661                 }
662
663                 /* parse out the total lengths again - they can shrink! */
664                 if (IVAL(cli->inbuf,smb_ntr_TotalDataCount) < total_data)
665                         total_data = IVAL(cli->inbuf,smb_ntr_TotalDataCount);
666                 if (IVAL(cli->inbuf,smb_ntr_TotalParameterCount) < total_param)
667                         total_param = IVAL(cli->inbuf,smb_ntr_TotalParameterCount);
668
669                 if (total_data <= *data_len && total_param <= *param_len) {
670                         ret = True;
671                         break;
672                 }
673         }
674
675   out:
676
677         cli_state_seqnum_remove(cli, mid);
678
679         if (ret) {
680                 /* Ensure the last 2 bytes of param and data are 2 null
681                  * bytes. These are malloc'ed, but not included in any
682                  * length counts. This allows cli_XX string reading functions
683                  * to safely null terminate. */
684                 if (total_data) {
685                         SSVAL(*data,total_data,0);
686                 }
687                 if (total_param) {
688                         SSVAL(*param,total_param,0);
689                 }
690         }
691
692         return ret;
693 }
694
695 struct trans_recvblob {
696         uint8_t *data;
697         uint32_t max, total, received;
698 };
699
700 struct cli_trans_state {
701         struct cli_state *cli;
702         struct event_context *ev;
703         uint8_t cmd;
704         uint16_t mid;
705         uint32_t seqnum;
706         const char *pipe_name;
707         uint8_t *pipe_name_conv;
708         size_t pipe_name_conv_len;
709         uint16_t fid;
710         uint16_t function;
711         int flags;
712         uint16_t *setup;
713         uint8_t num_setup, max_setup;
714         uint8_t *param;
715         uint32_t num_param, param_sent;
716         uint8_t *data;
717         uint32_t num_data, data_sent;
718
719         uint8_t num_rsetup;
720         uint16_t *rsetup;
721         struct trans_recvblob rparam;
722         struct trans_recvblob rdata;
723
724         TALLOC_CTX *secondary_request_ctx;
725
726         struct iovec iov[4];
727         uint8_t pad[4];
728         uint16_t vwv[32];
729 };
730
731 static NTSTATUS cli_pull_trans(uint8_t *inbuf,
732                                uint8_t wct, uint16_t *vwv,
733                                uint16_t num_bytes, uint8_t *bytes,
734                                uint8_t smb_cmd, bool expect_first_reply,
735                                uint8_t *pnum_setup, uint16_t **psetup,
736                                uint32_t *ptotal_param, uint32_t *pnum_param,
737                                uint32_t *pparam_disp, uint8_t **pparam,
738                                uint32_t *ptotal_data, uint32_t *pnum_data,
739                                uint32_t *pdata_disp, uint8_t **pdata)
740 {
741         uint32_t param_ofs, data_ofs;
742
743         if (expect_first_reply) {
744                 if ((wct != 0) || (num_bytes != 0)) {
745                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
746                 }
747                 return NT_STATUS_OK;
748         }
749
750         switch (smb_cmd) {
751         case SMBtrans:
752         case SMBtrans2:
753                 if (wct < 10) {
754                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
755                 }
756                 *ptotal_param   = SVAL(vwv + 0, 0);
757                 *ptotal_data    = SVAL(vwv + 1, 0);
758                 *pnum_param     = SVAL(vwv + 3, 0);
759                 param_ofs       = SVAL(vwv + 4, 0);
760                 *pparam_disp    = SVAL(vwv + 5, 0);
761                 *pnum_data      = SVAL(vwv + 6, 0);
762                 data_ofs        = SVAL(vwv + 7, 0);
763                 *pdata_disp     = SVAL(vwv + 8, 0);
764                 *pnum_setup     = CVAL(vwv + 9, 0);
765                 if (wct < 10 + (*pnum_setup)) {
766                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
767                 }
768                 *psetup = vwv + 10;
769
770                 break;
771         case SMBnttrans:
772                 if (wct < 18) {
773                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
774                 }
775                 *ptotal_param   = IVAL(vwv, 3);
776                 *ptotal_data    = IVAL(vwv, 7);
777                 *pnum_param     = IVAL(vwv, 11);
778                 param_ofs       = IVAL(vwv, 15);
779                 *pparam_disp    = IVAL(vwv, 19);
780                 *pnum_data      = IVAL(vwv, 23);
781                 data_ofs        = IVAL(vwv, 27);
782                 *pdata_disp     = IVAL(vwv, 31);
783                 *pnum_setup     = CVAL(vwv, 35);
784                 *psetup         = vwv + 18;
785                 break;
786
787         default:
788                 return NT_STATUS_INTERNAL_ERROR;
789         }
790
791         /*
792          * Check for buffer overflows. data_ofs needs to be checked against
793          * the incoming buffer length, data_disp against the total
794          * length. Likewise for param_ofs/param_disp.
795          */
796
797         if (trans_oob(smb_len(inbuf), param_ofs, *pnum_param)
798             || trans_oob(*ptotal_param, *pparam_disp, *pnum_param)
799             || trans_oob(smb_len(inbuf), data_ofs, *pnum_data)
800             || trans_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
801                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
802         }
803
804         *pparam = (uint8_t *)inbuf + 4 + param_ofs;
805         *pdata = (uint8_t *)inbuf + 4 + data_ofs;
806
807         return NT_STATUS_OK;
808 }
809
810 static NTSTATUS cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
811                                     struct trans_recvblob *blob,
812                                     uint32_t total, uint32_t thistime,
813                                     uint8_t *buf, uint32_t displacement)
814 {
815         if (blob->data == NULL) {
816                 if (total > blob->max) {
817                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
818                 }
819                 blob->total = total;
820                 blob->data = TALLOC_ARRAY(mem_ctx, uint8_t, total);
821                 if (blob->data == NULL) {
822                         return NT_STATUS_NO_MEMORY;
823                 }
824         }
825
826         if (total > blob->total) {
827                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
828         }
829
830         if (thistime) {
831                 memcpy(blob->data + displacement, buf, thistime);
832                 blob->received += thistime;
833         }
834
835         return NT_STATUS_OK;
836 }
837
838 static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct,
839                              int *piov_count)
840 {
841         uint8_t wct = 0;
842         struct iovec *iov = state->iov;
843         uint8_t *pad = state->pad;
844         uint16_t *vwv = state->vwv;
845         uint16_t param_offset;
846         uint16_t this_param = 0;
847         uint16_t this_data = 0;
848         uint32_t useable_space;
849         uint8_t cmd;
850
851         cmd = state->cmd;
852
853         if ((state->param_sent != 0) || (state->data_sent != 0)) {
854                 /* The secondary commands are one after the primary ones */
855                 cmd += 1;
856         }
857
858         param_offset = smb_size - 4;
859
860         switch (cmd) {
861         case SMBtrans:
862                 pad[0] = 0;
863                 iov[0].iov_base = (void *)pad;
864                 iov[0].iov_len = 1;
865                 iov[1].iov_base = (void *)state->pipe_name_conv;
866                 iov[1].iov_len = state->pipe_name_conv_len;
867                 wct = 14 + state->num_setup;
868                 param_offset += iov[0].iov_len + iov[1].iov_len;
869                 iov += 2;
870                 break;
871         case SMBtrans2:
872                 pad[0] = 0;
873                 pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
874                 pad[2] = ' ';
875                 iov[0].iov_base = (void *)pad;
876                 iov[0].iov_len = 3;
877                 wct = 14 + state->num_setup;
878                 param_offset += 3;
879                 iov += 1;
880                 break;
881         case SMBtranss:
882                 wct = 8;
883                 break;
884         case SMBtranss2:
885                 wct = 9;
886                 break;
887         case SMBnttrans:
888                 wct = 19 + state->num_setup;
889                 break;
890         case SMBnttranss:
891                 wct = 18;
892                 break;
893         }
894
895         useable_space = state->cli->max_xmit - smb_size - sizeof(uint16_t)*wct;
896
897         if (state->param_sent < state->num_param) {
898                 this_param = MIN(state->num_param - state->param_sent,
899                                  useable_space);
900                 iov[0].iov_base = (void *)(state->param + state->param_sent);
901                 iov[0].iov_len = this_param;
902                 iov += 1;
903         }
904
905         if (state->data_sent < state->num_data) {
906                 this_data = MIN(state->num_data - state->data_sent,
907                                 useable_space - this_param);
908                 iov[0].iov_base = (void *)(state->data + state->data_sent);
909                 iov[0].iov_len = this_data;
910                 iov += 1;
911         }
912
913         param_offset += wct * sizeof(uint16_t);
914
915         DEBUG(10, ("num_setup=%u, max_setup=%u, "
916                    "param_total=%u, this_param=%u, max_param=%u, "
917                    "data_total=%u, this_data=%u, max_data=%u, "
918                    "param_offset=%u, param_disp=%u, data_disp=%u\n",
919                    (unsigned)state->num_setup, (unsigned)state->max_setup,
920                    (unsigned)state->num_param, (unsigned)this_param,
921                    (unsigned)state->rparam.max,
922                    (unsigned)state->num_data, (unsigned)this_data,
923                    (unsigned)state->rdata.max,
924                    (unsigned)param_offset,
925                    (unsigned)state->param_sent, (unsigned)state->data_sent));
926
927         switch (cmd) {
928         case SMBtrans:
929         case SMBtrans2:
930                 SSVAL(vwv + 0, 0, state->num_param);
931                 SSVAL(vwv + 1, 0, state->num_data);
932                 SSVAL(vwv + 2, 0, state->rparam.max);
933                 SSVAL(vwv + 3, 0, state->rdata.max);
934                 SCVAL(vwv + 4, 0, state->max_setup);
935                 SCVAL(vwv + 4, 1, 0);   /* reserved */
936                 SSVAL(vwv + 5, 0, state->flags);
937                 SIVAL(vwv + 6, 0, 0);   /* timeout */
938                 SSVAL(vwv + 8, 0, 0);   /* reserved */
939                 SSVAL(vwv + 9, 0, this_param);
940                 SSVAL(vwv +10, 0, param_offset);
941                 SSVAL(vwv +11, 0, this_data);
942                 SSVAL(vwv +12, 0, param_offset + this_param);
943                 SCVAL(vwv +13, 0, state->num_setup);
944                 SCVAL(vwv +13, 1, 0);   /* reserved */
945                 memcpy(vwv + 14, state->setup,
946                        sizeof(uint16_t) * state->num_setup);
947                 break;
948         case SMBtranss:
949         case SMBtranss2:
950                 SSVAL(vwv + 0, 0, state->num_param);
951                 SSVAL(vwv + 1, 0, state->num_data);
952                 SSVAL(vwv + 2, 0, this_param);
953                 SSVAL(vwv + 3, 0, param_offset);
954                 SSVAL(vwv + 4, 0, state->param_sent);
955                 SSVAL(vwv + 5, 0, this_data);
956                 SSVAL(vwv + 6, 0, param_offset + this_param);
957                 SSVAL(vwv + 7, 0, state->data_sent);
958                 if (cmd == SMBtranss2) {
959                         SSVAL(vwv + 8, 0, state->fid);
960                 }
961                 break;
962         case SMBnttrans:
963                 SCVAL(vwv,  0, state->max_setup);
964                 SSVAL(vwv,  1, 0); /* reserved */
965                 SIVAL(vwv,  3, state->num_param);
966                 SIVAL(vwv,  7, state->num_data);
967                 SIVAL(vwv, 11, state->rparam.max);
968                 SIVAL(vwv, 15, state->rdata.max);
969                 SIVAL(vwv, 19, this_param);
970                 SIVAL(vwv, 23, param_offset);
971                 SIVAL(vwv, 27, this_data);
972                 SIVAL(vwv, 31, param_offset + this_param);
973                 SCVAL(vwv, 35, state->num_setup);
974                 SSVAL(vwv, 36, state->function);
975                 memcpy(vwv + 19, state->setup,
976                        sizeof(uint16_t) * state->num_setup);
977                 break;
978         case SMBnttranss:
979                 SSVAL(vwv,  0, 0); /* reserved */
980                 SCVAL(vwv,  2, 0); /* reserved */
981                 SIVAL(vwv,  3, state->num_param);
982                 SIVAL(vwv,  7, state->num_data);
983                 SIVAL(vwv, 11, this_param);
984                 SIVAL(vwv, 15, param_offset);
985                 SIVAL(vwv, 19, state->param_sent);
986                 SIVAL(vwv, 23, this_data);
987                 SIVAL(vwv, 27, param_offset + this_param);
988                 SIVAL(vwv, 31, state->data_sent);
989                 SCVAL(vwv, 35, 0); /* reserved */
990                 break;
991         }
992
993         state->param_sent += this_param;
994         state->data_sent += this_data;
995
996         *pwct = wct;
997         *piov_count = iov - state->iov;
998 }
999
1000 static void cli_trans_done(struct tevent_req *subreq);
1001
1002 struct tevent_req *cli_trans_send(
1003         TALLOC_CTX *mem_ctx, struct event_context *ev,
1004         struct cli_state *cli, uint8_t cmd,
1005         const char *pipe_name, uint16_t fid, uint16_t function, int flags,
1006         uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
1007         uint8_t *param, uint32_t num_param, uint32_t max_param,
1008         uint8_t *data, uint32_t num_data, uint32_t max_data)
1009 {
1010         struct tevent_req *req, *subreq;
1011         struct cli_trans_state *state;
1012         int iov_count;
1013         uint8_t wct;
1014         NTSTATUS status;
1015
1016         req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
1017         if (req == NULL) {
1018                 return NULL;
1019         }
1020
1021         if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
1022                 if ((num_param > 0xffff) || (max_param > 0xffff)
1023                     || (num_data > 0xffff) || (max_data > 0xffff)) {
1024                         DEBUG(3, ("Attempt to send invalid trans2 request "
1025                                   "(setup %u, params %u/%u, data %u/%u)\n",
1026                                   (unsigned)num_setup,
1027                                   (unsigned)num_param, (unsigned)max_param,
1028                                   (unsigned)num_data, (unsigned)max_data));
1029                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1030                         return tevent_req_post(req, ev);
1031                 }
1032         }
1033
1034         /*
1035          * The largest wct will be for nttrans (19+num_setup). Make sure we
1036          * don't overflow state->vwv in cli_trans_format.
1037          */
1038
1039         if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
1040                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1041                 return tevent_req_post(req, ev);
1042         }
1043
1044         state->cli = cli;
1045         state->ev = ev;
1046         state->cmd = cmd;
1047         state->flags = flags;
1048         state->num_rsetup = 0;
1049         state->rsetup = NULL;
1050         ZERO_STRUCT(state->rparam);
1051         ZERO_STRUCT(state->rdata);
1052
1053         if ((pipe_name != NULL)
1054             && (!convert_string_talloc(state, CH_UNIX,
1055                                        cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
1056                                        pipe_name, strlen(pipe_name) + 1,
1057                                        &state->pipe_name_conv,
1058                                        &state->pipe_name_conv_len, true))) {
1059                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1060                 return tevent_req_post(req, ev);
1061         }
1062         state->fid = fid;       /* trans2 */
1063         state->function = function; /* nttrans */
1064
1065         state->setup = setup;
1066         state->num_setup = num_setup;
1067         state->max_setup = max_setup;
1068
1069         state->param = param;
1070         state->num_param = num_param;
1071         state->param_sent = 0;
1072         state->rparam.max = max_param;
1073
1074         state->data = data;
1075         state->num_data = num_data;
1076         state->data_sent = 0;
1077         state->rdata.max = max_data;
1078
1079         cli_trans_format(state, &wct, &iov_count);
1080
1081         subreq = cli_smb_req_create(state, ev, cli, cmd, 0, wct, state->vwv,
1082                                     iov_count, state->iov);
1083         if (tevent_req_nomem(subreq, req)) {
1084                 return tevent_req_post(req, ev);
1085         }
1086         state->mid = cli_smb_req_mid(subreq);
1087         status = cli_smb_req_send(subreq);
1088         if (!NT_STATUS_IS_OK(status)) {
1089                 tevent_req_nterror(req, status);
1090                 return tevent_req_post(req, state->ev);
1091         }
1092         cli_state_seqnum_persistent(cli, state->mid);
1093         tevent_req_set_callback(subreq, cli_trans_done, req);
1094         return req;
1095 }
1096
1097 static void cli_trans_done(struct tevent_req *subreq)
1098 {
1099         struct tevent_req *req = tevent_req_callback_data(
1100                 subreq, struct tevent_req);
1101         struct cli_trans_state *state = tevent_req_data(
1102                 req, struct cli_trans_state);
1103         NTSTATUS status;
1104         bool sent_all;
1105         uint8_t wct;
1106         uint16_t *vwv;
1107         uint32_t num_bytes;
1108         uint8_t *bytes;
1109         uint8_t *inbuf;
1110         uint8_t num_setup       = 0;
1111         uint16_t *setup         = NULL;
1112         uint32_t total_param    = 0;
1113         uint32_t num_param      = 0;
1114         uint32_t param_disp     = 0;
1115         uint32_t total_data     = 0;
1116         uint32_t num_data       = 0;
1117         uint32_t data_disp      = 0;
1118         uint8_t *param          = NULL;
1119         uint8_t *data           = NULL;
1120
1121         status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv,
1122                               &num_bytes, &bytes);
1123         /*
1124          * Do not TALLOC_FREE(subreq) here, we might receive more than
1125          * one response for the same mid.
1126          */
1127
1128         /*
1129          * We can receive something like STATUS_MORE_ENTRIES, so don't use
1130          * !NT_STATUS_IS_OK(status) here.
1131          */
1132
1133         if (NT_STATUS_IS_ERR(status)) {
1134                 goto fail;
1135         }
1136
1137         sent_all = ((state->param_sent == state->num_param)
1138                     && (state->data_sent == state->num_data));
1139
1140         status = cli_pull_trans(
1141                 inbuf, wct, vwv, num_bytes, bytes,
1142                 state->cmd, !sent_all, &num_setup, &setup,
1143                 &total_param, &num_param, &param_disp, &param,
1144                 &total_data, &num_data, &data_disp, &data);
1145
1146         if (!NT_STATUS_IS_OK(status)) {
1147                 goto fail;
1148         }
1149
1150         if (!sent_all) {
1151                 int iov_count;
1152
1153                 TALLOC_FREE(subreq);
1154
1155                 cli_trans_format(state, &wct, &iov_count);
1156
1157                 subreq = cli_smb_req_create(state, state->ev, state->cli,
1158                                             state->cmd + 1, 0, wct, state->vwv,
1159                                             iov_count, state->iov);
1160                 if (tevent_req_nomem(subreq, req)) {
1161                         return;
1162                 }
1163                 cli_smb_req_set_mid(subreq, state->mid);
1164
1165                 status = cli_smb_req_send(subreq);
1166
1167                 if (!NT_STATUS_IS_OK(status)) {
1168                         goto fail;
1169                 }
1170                 tevent_req_set_callback(subreq, cli_trans_done, req);
1171                 return;
1172         }
1173
1174         status = cli_trans_pull_blob(
1175                 state, &state->rparam, total_param, num_param, param,
1176                 param_disp);
1177
1178         if (!NT_STATUS_IS_OK(status)) {
1179                 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
1180                 goto fail;
1181         }
1182
1183         status = cli_trans_pull_blob(
1184                 state, &state->rdata, total_data, num_data, data,
1185                 data_disp);
1186
1187         if (!NT_STATUS_IS_OK(status)) {
1188                 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
1189                 goto fail;
1190         }
1191
1192         if ((state->rparam.total == state->rparam.received)
1193             && (state->rdata.total == state->rdata.received)) {
1194                 TALLOC_FREE(subreq);
1195                 cli_state_seqnum_remove(state->cli, state->mid);
1196                 tevent_req_done(req);
1197                 return;
1198         }
1199
1200         TALLOC_FREE(inbuf);
1201
1202         if (!cli_smb_req_set_pending(subreq)) {
1203                 status = NT_STATUS_NO_MEMORY;
1204                 goto fail;
1205         }
1206         return;
1207
1208  fail:
1209         cli_state_seqnum_remove(state->cli, state->mid);
1210         TALLOC_FREE(subreq);
1211         tevent_req_nterror(req, status);
1212 }
1213
1214 NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1215                         uint16_t **setup, uint8_t min_setup,
1216                         uint8_t *num_setup,
1217                         uint8_t **param, uint32_t min_param,
1218                         uint32_t *num_param,
1219                         uint8_t **data, uint32_t min_data,
1220                         uint32_t *num_data)
1221 {
1222         struct cli_trans_state *state = tevent_req_data(
1223                 req, struct cli_trans_state);
1224         NTSTATUS status;
1225
1226         if (tevent_req_is_nterror(req, &status)) {
1227                 return status;
1228         }
1229
1230         if ((state->num_rsetup < min_setup)
1231             || (state->rparam.total < min_param)
1232             || (state->rdata.total < min_data)) {
1233                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1234         }
1235
1236         if (setup != NULL) {
1237                 *setup = talloc_move(mem_ctx, &state->rsetup);
1238                 *num_setup = state->num_rsetup;
1239         } else {
1240                 TALLOC_FREE(state->rsetup);
1241         }
1242
1243         if (param != NULL) {
1244                 *param = talloc_move(mem_ctx, &state->rparam.data);
1245                 *num_param = state->rparam.total;
1246         } else {
1247                 TALLOC_FREE(state->rparam.data);
1248         }
1249
1250         if (data != NULL) {
1251                 *data = talloc_move(mem_ctx, &state->rdata.data);
1252                 *num_data = state->rdata.total;
1253         } else {
1254                 TALLOC_FREE(state->rdata.data);
1255         }
1256
1257         return NT_STATUS_OK;
1258 }
1259
1260 NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
1261                    uint8_t trans_cmd,
1262                    const char *pipe_name, uint16_t fid, uint16_t function,
1263                    int flags,
1264                    uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
1265                    uint8_t *param, uint32_t num_param, uint32_t max_param,
1266                    uint8_t *data, uint32_t num_data, uint32_t max_data,
1267                    uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
1268                    uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
1269                    uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
1270 {
1271         TALLOC_CTX *frame = talloc_stackframe();
1272         struct event_context *ev;
1273         struct tevent_req *req;
1274         NTSTATUS status = NT_STATUS_OK;
1275
1276         if (cli_has_async_calls(cli)) {
1277                 /*
1278                  * Can't use sync call while an async call is in flight
1279                  */
1280                 status = NT_STATUS_INVALID_PARAMETER;
1281                 goto fail;
1282         }
1283
1284         ev = event_context_init(frame);
1285         if (ev == NULL) {
1286                 status = NT_STATUS_NO_MEMORY;
1287                 goto fail;
1288         }
1289
1290         req = cli_trans_send(frame, ev, cli, trans_cmd,
1291                              pipe_name, fid, function, flags,
1292                              setup, num_setup, max_setup,
1293                              param, num_param, max_param,
1294                              data, num_data, max_data);
1295         if (req == NULL) {
1296                 status = NT_STATUS_NO_MEMORY;
1297                 goto fail;
1298         }
1299
1300         if (!tevent_req_poll(req, ev)) {
1301                 status = map_nt_error_from_unix(errno);
1302                 goto fail;
1303         }
1304
1305         status = cli_trans_recv(req, mem_ctx, rsetup, min_rsetup, num_rsetup,
1306                                 rparam, min_rparam, num_rparam,
1307                                 rdata, min_rdata, num_rdata);
1308  fail:
1309         TALLOC_FREE(frame);
1310         if (!NT_STATUS_IS_OK(status)) {
1311                 cli_set_error(cli, status);
1312         }
1313         return status;
1314 }