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