Clean up assignments to iov_base, ensure it's always cast to void *. This should...
[samba.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
1015         req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
1016         if (req == NULL) {
1017                 return NULL;
1018         }
1019
1020         if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
1021                 if ((num_param > 0xffff) || (max_param > 0xffff)
1022                     || (num_data > 0xffff) || (max_data > 0xffff)) {
1023                         DEBUG(3, ("Attempt to send invalid trans2 request "
1024                                   "(setup %u, params %u/%u, data %u/%u)\n",
1025                                   (unsigned)num_setup,
1026                                   (unsigned)num_param, (unsigned)max_param,
1027                                   (unsigned)num_data, (unsigned)max_data));
1028                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1029                         return tevent_req_post(req, ev);
1030                 }
1031         }
1032
1033         /*
1034          * The largest wct will be for nttrans (19+num_setup). Make sure we
1035          * don't overflow state->vwv in cli_trans_format.
1036          */
1037
1038         if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
1039                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
1040                 return tevent_req_post(req, ev);
1041         }
1042
1043         state->cli = cli;
1044         state->ev = ev;
1045         state->cmd = cmd;
1046         state->flags = flags;
1047         state->num_rsetup = 0;
1048         state->rsetup = NULL;
1049         ZERO_STRUCT(state->rparam);
1050         ZERO_STRUCT(state->rdata);
1051
1052         if ((pipe_name != NULL)
1053             && (!convert_string_talloc(state, CH_UNIX,
1054                                        cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
1055                                        pipe_name, strlen(pipe_name) + 1,
1056                                        &state->pipe_name_conv,
1057                                        &state->pipe_name_conv_len, true))) {
1058                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1059                 return tevent_req_post(req, ev);
1060         }
1061         state->fid = fid;       /* trans2 */
1062         state->function = function; /* nttrans */
1063
1064         state->setup = setup;
1065         state->num_setup = num_setup;
1066         state->max_setup = max_setup;
1067
1068         state->param = param;
1069         state->num_param = num_param;
1070         state->param_sent = 0;
1071         state->rparam.max = max_param;
1072
1073         state->data = data;
1074         state->num_data = num_data;
1075         state->data_sent = 0;
1076         state->rdata.max = max_data;
1077
1078         cli_trans_format(state, &wct, &iov_count);
1079
1080         subreq = cli_smb_req_create(state, ev, cli, cmd, 0, wct, state->vwv,
1081                                     iov_count, state->iov);
1082         if (tevent_req_nomem(subreq, req)) {
1083                 return tevent_req_post(req, ev);
1084         }
1085         state->mid = cli_smb_req_mid(subreq);
1086         if (!cli_smb_req_send(subreq)) {
1087                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1088                 return tevent_req_post(req, state->ev);
1089         }
1090         cli_state_seqnum_persistent(cli, state->mid);
1091         tevent_req_set_callback(subreq, cli_trans_done, req);
1092         return req;
1093 }
1094
1095 static void cli_trans_done(struct tevent_req *subreq)
1096 {
1097         struct tevent_req *req = tevent_req_callback_data(
1098                 subreq, struct tevent_req);
1099         struct cli_trans_state *state = tevent_req_data(
1100                 req, struct cli_trans_state);
1101         NTSTATUS status;
1102         bool sent_all;
1103         uint8_t wct;
1104         uint16_t *vwv;
1105         uint32_t num_bytes;
1106         uint8_t *bytes;
1107         uint8_t num_setup       = 0;
1108         uint16_t *setup         = NULL;
1109         uint32_t total_param    = 0;
1110         uint32_t num_param      = 0;
1111         uint32_t param_disp     = 0;
1112         uint32_t total_data     = 0;
1113         uint32_t num_data       = 0;
1114         uint32_t data_disp      = 0;
1115         uint8_t *param          = NULL;
1116         uint8_t *data           = NULL;
1117
1118         status = cli_smb_recv(subreq, 0, &wct, &vwv, &num_bytes, &bytes);
1119
1120         /*
1121          * We can receive something like STATUS_MORE_ENTRIES, so don't use
1122          * !NT_STATUS_IS_OK(status) here.
1123          */
1124
1125         if (NT_STATUS_IS_ERR(status)) {
1126                 goto fail;
1127         }
1128
1129         sent_all = ((state->param_sent == state->num_param)
1130                     && (state->data_sent == state->num_data));
1131
1132         status = cli_pull_trans(
1133                 cli_smb_inbuf(subreq), wct, vwv, num_bytes, bytes,
1134                 state->cmd, !sent_all, &num_setup, &setup,
1135                 &total_param, &num_param, &param_disp, &param,
1136                 &total_data, &num_data, &data_disp, &data);
1137
1138         if (!NT_STATUS_IS_OK(status)) {
1139                 goto fail;
1140         }
1141
1142         if (!sent_all) {
1143                 int iov_count;
1144
1145                 TALLOC_FREE(subreq);
1146
1147                 cli_trans_format(state, &wct, &iov_count);
1148
1149                 subreq = cli_smb_req_create(state, state->ev, state->cli,
1150                                             state->cmd + 1, 0, wct, state->vwv,
1151                                             iov_count, state->iov);
1152                 if (tevent_req_nomem(subreq, req)) {
1153                         return;
1154                 }
1155                 cli_smb_req_set_mid(subreq, state->mid);
1156
1157                 if (!cli_smb_req_send(subreq)) {
1158                         status = NT_STATUS_NO_MEMORY;
1159                         goto fail;
1160                 }
1161                 tevent_req_set_callback(subreq, cli_trans_done, req);
1162                 return;
1163         }
1164
1165         status = cli_trans_pull_blob(
1166                 state, &state->rparam, total_param, num_param, param,
1167                 param_disp);
1168
1169         if (!NT_STATUS_IS_OK(status)) {
1170                 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
1171                 goto fail;
1172         }
1173
1174         status = cli_trans_pull_blob(
1175                 state, &state->rdata, total_data, num_data, data,
1176                 data_disp);
1177
1178         if (!NT_STATUS_IS_OK(status)) {
1179                 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
1180                 goto fail;
1181         }
1182
1183         if ((state->rparam.total == state->rparam.received)
1184             && (state->rdata.total == state->rdata.received)) {
1185                 TALLOC_FREE(subreq);
1186                 cli_state_seqnum_remove(state->cli, state->mid);
1187                 tevent_req_done(req);
1188                 return;
1189         }
1190
1191         if (!cli_smb_req_set_pending(subreq)) {
1192                 status = NT_STATUS_NO_MEMORY;
1193                 goto fail;
1194         }
1195         return;
1196
1197  fail:
1198         cli_state_seqnum_remove(state->cli, state->mid);
1199         TALLOC_FREE(subreq);
1200         tevent_req_nterror(req, status);
1201 }
1202
1203 NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
1204                         uint16_t **setup, uint8_t *num_setup,
1205                         uint8_t **param, uint32_t *num_param,
1206                         uint8_t **data, uint32_t *num_data)
1207 {
1208         struct cli_trans_state *state = tevent_req_data(
1209                 req, struct cli_trans_state);
1210         NTSTATUS status;
1211
1212         if (tevent_req_is_nterror(req, &status)) {
1213                 return status;
1214         }
1215
1216         if (setup != NULL) {
1217                 *setup = talloc_move(mem_ctx, &state->rsetup);
1218                 *num_setup = state->num_rsetup;
1219         } else {
1220                 TALLOC_FREE(state->rsetup);
1221         }
1222
1223         if (param != NULL) {
1224                 *param = talloc_move(mem_ctx, &state->rparam.data);
1225                 *num_param = state->rparam.total;
1226         } else {
1227                 TALLOC_FREE(state->rparam.data);
1228         }
1229
1230         if (data != NULL) {
1231                 *data = talloc_move(mem_ctx, &state->rdata.data);
1232                 *num_data = state->rdata.total;
1233         } else {
1234                 TALLOC_FREE(state->rdata.data);
1235         }
1236
1237         return NT_STATUS_OK;
1238 }
1239
1240 NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
1241                    uint8_t trans_cmd,
1242                    const char *pipe_name, uint16_t fid, uint16_t function,
1243                    int flags,
1244                    uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
1245                    uint8_t *param, uint32_t num_param, uint32_t max_param,
1246                    uint8_t *data, uint32_t num_data, uint32_t max_data,
1247                    uint16_t **rsetup, uint8_t *num_rsetup,
1248                    uint8_t **rparam, uint32_t *num_rparam,
1249                    uint8_t **rdata, uint32_t *num_rdata)
1250 {
1251         TALLOC_CTX *frame = talloc_stackframe();
1252         struct event_context *ev;
1253         struct tevent_req *req;
1254         NTSTATUS status = NT_STATUS_OK;
1255
1256         if (cli_has_async_calls(cli)) {
1257                 /*
1258                  * Can't use sync call while an async call is in flight
1259                  */
1260                 status = NT_STATUS_INVALID_PARAMETER;
1261                 goto fail;
1262         }
1263
1264         ev = event_context_init(frame);
1265         if (ev == NULL) {
1266                 status = NT_STATUS_NO_MEMORY;
1267                 goto fail;
1268         }
1269
1270         req = cli_trans_send(frame, ev, cli, trans_cmd,
1271                              pipe_name, fid, function, flags,
1272                              setup, num_setup, max_setup,
1273                              param, num_param, max_param,
1274                              data, num_data, max_data);
1275         if (req == NULL) {
1276                 status = NT_STATUS_NO_MEMORY;
1277                 goto fail;
1278         }
1279
1280         if (!tevent_req_poll(req, ev)) {
1281                 status = map_nt_error_from_unix(errno);
1282                 goto fail;
1283         }
1284
1285         status = cli_trans_recv(req, mem_ctx, rsetup, num_rsetup,
1286                                 rparam, num_rparam, rdata, num_rdata);
1287  fail:
1288         TALLOC_FREE(frame);
1289         if (!NT_STATUS_IS_OK(status)) {
1290                 cli_set_error(cli, status);
1291         }
1292         return status;
1293 }