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