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