s3:libsmb: only align unicode pipe_name (bug #8586)
[samba.git] / source3 / libsmb / clitrans.c
1 /*
2    Unix SMB/CIFS implementation.
3    client transaction calls
4    Copyright (C) Andrew Tridgell 1994-1998
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "libsmb/libsmb.h"
22 #include "../lib/util/tevent_ntstatus.h"
23 #include "async_smb.h"
24
25 struct trans_recvblob {
26         uint8_t *data;
27         uint32_t max, total, received;
28 };
29
30 struct cli_trans_state {
31         struct cli_state *cli;
32         struct tevent_context *ev;
33         uint8_t cmd;
34         uint16_t mid;
35         const char *pipe_name;
36         uint8_t *pipe_name_conv;
37         size_t pipe_name_conv_len;
38         uint16_t fid;
39         uint16_t function;
40         int flags;
41         uint16_t *setup;
42         uint8_t num_setup, max_setup;
43         uint8_t *param;
44         uint32_t num_param, param_sent;
45         uint8_t *data;
46         uint32_t num_data, data_sent;
47
48         uint8_t num_rsetup;
49         uint16_t *rsetup;
50         struct trans_recvblob rparam;
51         struct trans_recvblob rdata;
52         uint16_t recv_flags2;
53
54         struct iovec iov[6];
55         uint8_t pad[4];
56         uint8_t zero_pad[4];
57         uint16_t vwv[32];
58
59         struct tevent_req *primary_subreq;
60 };
61
62 static void cli_trans_cleanup_primary(struct cli_trans_state *state)
63 {
64         if (state->primary_subreq) {
65                 cli_smb_req_set_mid(state->primary_subreq, 0);
66                 cli_smb_req_unset_pending(state->primary_subreq);
67                 TALLOC_FREE(state->primary_subreq);
68         }
69 }
70
71 static int cli_trans_state_destructor(struct cli_trans_state *state)
72 {
73         cli_trans_cleanup_primary(state);
74         return 0;
75 }
76
77 static NTSTATUS cli_pull_trans(uint8_t *inbuf,
78                                uint8_t wct, uint16_t *vwv,
79                                uint16_t num_bytes, uint8_t *bytes,
80                                uint8_t smb_cmd, bool expect_first_reply,
81                                uint8_t *pnum_setup, uint16_t **psetup,
82                                uint32_t *ptotal_param, uint32_t *pnum_param,
83                                uint32_t *pparam_disp, uint8_t **pparam,
84                                uint32_t *ptotal_data, uint32_t *pnum_data,
85                                uint32_t *pdata_disp, uint8_t **pdata)
86 {
87         uint32_t param_ofs, data_ofs;
88
89         if (expect_first_reply) {
90                 if ((wct != 0) || (num_bytes != 0)) {
91                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
92                 }
93                 return NT_STATUS_OK;
94         }
95
96         switch (smb_cmd) {
97         case SMBtrans:
98         case SMBtrans2:
99                 if (wct < 10) {
100                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
101                 }
102                 *ptotal_param   = SVAL(vwv + 0, 0);
103                 *ptotal_data    = SVAL(vwv + 1, 0);
104                 *pnum_param     = SVAL(vwv + 3, 0);
105                 param_ofs       = SVAL(vwv + 4, 0);
106                 *pparam_disp    = SVAL(vwv + 5, 0);
107                 *pnum_data      = SVAL(vwv + 6, 0);
108                 data_ofs        = SVAL(vwv + 7, 0);
109                 *pdata_disp     = SVAL(vwv + 8, 0);
110                 *pnum_setup     = CVAL(vwv + 9, 0);
111                 if (wct < 10 + (*pnum_setup)) {
112                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
113                 }
114                 *psetup = vwv + 10;
115
116                 break;
117         case SMBnttrans:
118                 if (wct < 18) {
119                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
120                 }
121                 *ptotal_param   = IVAL(vwv, 3);
122                 *ptotal_data    = IVAL(vwv, 7);
123                 *pnum_param     = IVAL(vwv, 11);
124                 param_ofs       = IVAL(vwv, 15);
125                 *pparam_disp    = IVAL(vwv, 19);
126                 *pnum_data      = IVAL(vwv, 23);
127                 data_ofs        = IVAL(vwv, 27);
128                 *pdata_disp     = IVAL(vwv, 31);
129                 *pnum_setup     = CVAL(vwv, 35);
130                 *psetup         = vwv + 18;
131                 break;
132
133         default:
134                 return NT_STATUS_INTERNAL_ERROR;
135         }
136
137         /*
138          * Check for buffer overflows. data_ofs needs to be checked against
139          * the incoming buffer length, data_disp against the total
140          * length. Likewise for param_ofs/param_disp.
141          */
142
143         if (smb_buffer_oob(smb_len_nbt(inbuf), param_ofs, *pnum_param)
144             || smb_buffer_oob(*ptotal_param, *pparam_disp, *pnum_param)
145             || smb_buffer_oob(smb_len_nbt(inbuf), data_ofs, *pnum_data)
146             || smb_buffer_oob(*ptotal_data, *pdata_disp, *pnum_data)) {
147                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
148         }
149
150         *pparam = (uint8_t *)inbuf + 4 + param_ofs;
151         *pdata = (uint8_t *)inbuf + 4 + data_ofs;
152
153         return NT_STATUS_OK;
154 }
155
156 static NTSTATUS cli_trans_pull_blob(TALLOC_CTX *mem_ctx,
157                                     struct trans_recvblob *blob,
158                                     uint32_t total, uint32_t thistime,
159                                     uint8_t *buf, uint32_t displacement)
160 {
161         if (blob->data == NULL) {
162                 if (total > blob->max) {
163                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
164                 }
165                 blob->total = total;
166                 blob->data = talloc_array(mem_ctx, uint8_t, total);
167                 if (blob->data == NULL) {
168                         return NT_STATUS_NO_MEMORY;
169                 }
170         }
171
172         if (total > blob->total) {
173                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
174         }
175
176         if (thistime) {
177                 memcpy(blob->data + displacement, buf, thistime);
178                 blob->received += thistime;
179         }
180
181         return NT_STATUS_OK;
182 }
183
184 static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct,
185                              int *piov_count)
186 {
187         struct cli_state *cli = state->cli;
188         uint8_t wct = 0;
189         struct iovec *iov = state->iov;
190         uint8_t *pad = state->pad;
191         uint16_t *vwv = state->vwv;
192         uint32_t param_offset;
193         uint32_t this_param = 0;
194         uint32_t param_pad;
195         uint32_t data_offset;
196         uint32_t this_data = 0;
197         uint32_t data_pad;
198         uint32_t useable_space;
199         uint8_t cmd;
200
201         cmd = state->cmd;
202
203         if ((state->param_sent != 0) || (state->data_sent != 0)) {
204                 /* The secondary commands are one after the primary ones */
205                 cmd += 1;
206         }
207
208         param_offset = MIN_SMB_SIZE;
209
210         switch (cmd) {
211         case SMBtrans:
212                 if (cli_ucs2(state->cli)) {
213                         pad[0] = 0;
214                         iov[0].iov_base = (void *)pad;
215                         iov[0].iov_len = 1;
216                         param_offset += 1;
217                         iov += 1;
218                 }
219                 iov[0].iov_base = (void *)state->pipe_name_conv;
220                 iov[0].iov_len = state->pipe_name_conv_len;
221                 wct = 14 + state->num_setup;
222                 param_offset += iov[0].iov_len;
223                 iov += 1;
224                 break;
225         case SMBtrans2:
226                 pad[0] = 0;
227                 pad[1] = 'D'; /* Copy this from "old" 3.0 behaviour */
228                 pad[2] = ' ';
229                 iov[0].iov_base = (void *)pad;
230                 iov[0].iov_len = 3;
231                 wct = 14 + state->num_setup;
232                 param_offset += 3;
233                 iov += 1;
234                 break;
235         case SMBtranss:
236                 wct = 8;
237                 break;
238         case SMBtranss2:
239                 wct = 9;
240                 break;
241         case SMBnttrans:
242                 wct = 19 + state->num_setup;
243                 break;
244         case SMBnttranss:
245                 wct = 18;
246                 break;
247         }
248
249         param_offset += wct * sizeof(uint16_t);
250         useable_space = cli_state_available_size(cli, param_offset);
251
252         param_pad = param_offset % 4;
253         if (param_pad > 0) {
254                 param_pad = MIN(param_pad, useable_space);
255                 iov[0].iov_base = (void *)state->zero_pad;
256                 iov[0].iov_len = param_pad;
257                 iov += 1;
258                 param_offset += param_pad;
259         }
260         useable_space = cli_state_available_size(cli, param_offset);
261
262         if (state->param_sent < state->num_param) {
263                 this_param = MIN(state->num_param - state->param_sent,
264                                  useable_space);
265                 iov[0].iov_base = (void *)(state->param + state->param_sent);
266                 iov[0].iov_len = this_param;
267                 iov += 1;
268         }
269
270         data_offset = param_offset + this_param;
271         useable_space = cli_state_available_size(cli, data_offset);
272
273         data_pad = data_offset % 4;
274         if (data_pad > 0) {
275                 data_pad = MIN(data_pad, useable_space);
276                 iov[0].iov_base = (void *)state->zero_pad;
277                 iov[0].iov_len = data_pad;
278                 iov += 1;
279                 data_offset += data_pad;
280         }
281         useable_space = cli_state_available_size(cli, data_offset);
282
283         if (state->data_sent < state->num_data) {
284                 this_data = MIN(state->num_data - state->data_sent,
285                                 useable_space);
286                 iov[0].iov_base = (void *)(state->data + state->data_sent);
287                 iov[0].iov_len = this_data;
288                 iov += 1;
289         }
290
291         DEBUG(10, ("num_setup=%u, max_setup=%u, "
292                    "param_total=%u, this_param=%u, max_param=%u, "
293                    "data_total=%u, this_data=%u, max_data=%u, "
294                    "param_offset=%u, param_pad=%u, param_disp=%u, "
295                    "data_offset=%u, data_pad=%u, data_disp=%u\n",
296                    (unsigned)state->num_setup, (unsigned)state->max_setup,
297                    (unsigned)state->num_param, (unsigned)this_param,
298                    (unsigned)state->rparam.max,
299                    (unsigned)state->num_data, (unsigned)this_data,
300                    (unsigned)state->rdata.max,
301                    (unsigned)param_offset, (unsigned)param_pad,
302                    (unsigned)state->param_sent,
303                    (unsigned)data_offset, (unsigned)data_pad,
304                    (unsigned)state->data_sent));
305
306         switch (cmd) {
307         case SMBtrans:
308         case SMBtrans2:
309                 SSVAL(vwv + 0, 0, state->num_param);
310                 SSVAL(vwv + 1, 0, state->num_data);
311                 SSVAL(vwv + 2, 0, state->rparam.max);
312                 SSVAL(vwv + 3, 0, state->rdata.max);
313                 SCVAL(vwv + 4, 0, state->max_setup);
314                 SCVAL(vwv + 4, 1, 0);   /* reserved */
315                 SSVAL(vwv + 5, 0, state->flags);
316                 SIVAL(vwv + 6, 0, 0);   /* timeout */
317                 SSVAL(vwv + 8, 0, 0);   /* reserved */
318                 SSVAL(vwv + 9, 0, this_param);
319                 SSVAL(vwv +10, 0, param_offset);
320                 SSVAL(vwv +11, 0, this_data);
321                 SSVAL(vwv +12, 0, data_offset);
322                 SCVAL(vwv +13, 0, state->num_setup);
323                 SCVAL(vwv +13, 1, 0);   /* reserved */
324                 memcpy(vwv + 14, state->setup,
325                        sizeof(uint16_t) * state->num_setup);
326                 break;
327         case SMBtranss:
328         case SMBtranss2:
329                 SSVAL(vwv + 0, 0, state->num_param);
330                 SSVAL(vwv + 1, 0, state->num_data);
331                 SSVAL(vwv + 2, 0, this_param);
332                 SSVAL(vwv + 3, 0, param_offset);
333                 SSVAL(vwv + 4, 0, state->param_sent);
334                 SSVAL(vwv + 5, 0, this_data);
335                 SSVAL(vwv + 6, 0, data_offset);
336                 SSVAL(vwv + 7, 0, state->data_sent);
337                 if (cmd == SMBtranss2) {
338                         SSVAL(vwv + 8, 0, state->fid);
339                 }
340                 break;
341         case SMBnttrans:
342                 SCVAL(vwv + 0, 0, state->max_setup);
343                 SSVAL(vwv + 0, 1, 0); /* reserved */
344                 SIVAL(vwv + 1, 1, state->num_param);
345                 SIVAL(vwv + 3, 1, state->num_data);
346                 SIVAL(vwv + 5, 1, state->rparam.max);
347                 SIVAL(vwv + 7, 1, state->rdata.max);
348                 SIVAL(vwv + 9, 1, this_param);
349                 SIVAL(vwv +11, 1, param_offset);
350                 SIVAL(vwv +13, 1, this_data);
351                 SIVAL(vwv +15, 1, data_offset);
352                 SCVAL(vwv +17, 1, state->num_setup);
353                 SSVAL(vwv +18, 0, state->function);
354                 memcpy(vwv + 19, state->setup,
355                        sizeof(uint16_t) * state->num_setup);
356                 break;
357         case SMBnttranss:
358                 SSVAL(vwv + 0, 0, 0); /* reserved */
359                 SCVAL(vwv + 1, 0, 0); /* reserved */
360                 SIVAL(vwv + 1, 1, state->num_param);
361                 SIVAL(vwv + 3, 1, state->num_data);
362                 SIVAL(vwv + 5, 1, this_param);
363                 SIVAL(vwv + 7, 1, param_offset);
364                 SIVAL(vwv + 9, 1, state->param_sent);
365                 SIVAL(vwv +11, 1, this_data);
366                 SIVAL(vwv +13, 1, data_offset);
367                 SIVAL(vwv +15, 1, state->data_sent);
368                 SCVAL(vwv +17, 1, 0); /* reserved */
369                 break;
370         }
371
372         state->param_sent += this_param;
373         state->data_sent += this_data;
374
375         *pwct = wct;
376         *piov_count = iov - state->iov;
377 }
378
379 static void cli_trans_done(struct tevent_req *subreq);
380
381 struct tevent_req *cli_trans_send(
382         TALLOC_CTX *mem_ctx, struct tevent_context *ev,
383         struct cli_state *cli, uint8_t cmd,
384         const char *pipe_name, uint16_t fid, uint16_t function, int flags,
385         uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
386         uint8_t *param, uint32_t num_param, uint32_t max_param,
387         uint8_t *data, uint32_t num_data, uint32_t max_data)
388 {
389         struct tevent_req *req, *subreq;
390         struct cli_trans_state *state;
391         int iov_count;
392         uint8_t wct;
393         NTSTATUS status;
394
395         req = tevent_req_create(mem_ctx, &state, struct cli_trans_state);
396         if (req == NULL) {
397                 return NULL;
398         }
399
400         if ((cmd == SMBtrans) || (cmd == SMBtrans2)) {
401                 if ((num_param > 0xffff) || (max_param > 0xffff)
402                     || (num_data > 0xffff) || (max_data > 0xffff)) {
403                         DEBUG(3, ("Attempt to send invalid trans2 request "
404                                   "(setup %u, params %u/%u, data %u/%u)\n",
405                                   (unsigned)num_setup,
406                                   (unsigned)num_param, (unsigned)max_param,
407                                   (unsigned)num_data, (unsigned)max_data));
408                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
409                         return tevent_req_post(req, ev);
410                 }
411         }
412
413         /*
414          * The largest wct will be for nttrans (19+num_setup). Make sure we
415          * don't overflow state->vwv in cli_trans_format.
416          */
417
418         if ((num_setup + 19) > ARRAY_SIZE(state->vwv)) {
419                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
420                 return tevent_req_post(req, ev);
421         }
422
423         state->cli = cli;
424         state->ev = ev;
425         state->cmd = cmd;
426         state->flags = flags;
427         state->num_rsetup = 0;
428         state->rsetup = NULL;
429         ZERO_STRUCT(state->rparam);
430         ZERO_STRUCT(state->rdata);
431
432         if ((pipe_name != NULL)
433             && (!convert_string_talloc(state, CH_UNIX,
434                                        cli_ucs2(cli) ? CH_UTF16LE : CH_DOS,
435                                        pipe_name, strlen(pipe_name) + 1,
436                                        &state->pipe_name_conv,
437                                        &state->pipe_name_conv_len))) {
438                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
439                 return tevent_req_post(req, ev);
440         }
441         state->fid = fid;       /* trans2 */
442         state->function = function; /* nttrans */
443
444         state->setup = setup;
445         state->num_setup = num_setup;
446         state->max_setup = max_setup;
447
448         state->param = param;
449         state->num_param = num_param;
450         state->param_sent = 0;
451         state->rparam.max = max_param;
452
453         state->data = data;
454         state->num_data = num_data;
455         state->data_sent = 0;
456         state->rdata.max = max_data;
457
458         cli_trans_format(state, &wct, &iov_count);
459
460         subreq = cli_smb_req_create(state, ev, cli, cmd, 0, wct, state->vwv,
461                                     iov_count, state->iov);
462         if (tevent_req_nomem(subreq, req)) {
463                 return tevent_req_post(req, ev);
464         }
465         status = cli_smb_req_send(subreq);
466         if (!NT_STATUS_IS_OK(status)) {
467                 tevent_req_nterror(req, status);
468                 return tevent_req_post(req, state->ev);
469         }
470         tevent_req_set_callback(subreq, cli_trans_done, req);
471
472         /*
473          * Now get the MID of the primary request
474          * and mark it as persistent. This means
475          * we will able to send and receive multiple
476          * SMB pdus using this MID in both directions
477          * (including correct SMB signing).
478          */
479         state->mid = cli_smb_req_mid(subreq);
480         cli_smb_req_set_mid(subreq, state->mid);
481         state->primary_subreq = subreq;
482         talloc_set_destructor(state, cli_trans_state_destructor);
483
484         return req;
485 }
486
487 static void cli_trans_done2(struct tevent_req *subreq);
488
489 static void cli_trans_done(struct tevent_req *subreq)
490 {
491         struct tevent_req *req = tevent_req_callback_data(
492                 subreq, struct tevent_req);
493         struct cli_trans_state *state = tevent_req_data(
494                 req, struct cli_trans_state);
495         NTSTATUS status;
496         bool sent_all;
497         const uint8_t *inhdr;
498         uint8_t wct;
499         uint16_t *vwv;
500         uint32_t num_bytes;
501         uint8_t *bytes;
502         uint8_t *inbuf;
503         uint8_t num_setup       = 0;
504         uint16_t *setup         = NULL;
505         uint32_t total_param    = 0;
506         uint32_t num_param      = 0;
507         uint32_t param_disp     = 0;
508         uint32_t total_data     = 0;
509         uint32_t num_data       = 0;
510         uint32_t data_disp      = 0;
511         uint8_t *param          = NULL;
512         uint8_t *data           = NULL;
513
514         status = cli_smb_recv(subreq, state, &inbuf, 0, &wct, &vwv,
515                               &num_bytes, &bytes);
516         /*
517          * Do not TALLOC_FREE(subreq) here, we might receive more than
518          * one response for the same mid.
519          */
520
521         /*
522          * We can receive something like STATUS_MORE_ENTRIES, so don't use
523          * !NT_STATUS_IS_OK(status) here.
524          */
525
526         if (NT_STATUS_IS_ERR(status)) {
527                 goto fail;
528         }
529         inhdr = inbuf + NBT_HDR_SIZE;
530
531         sent_all = ((state->param_sent == state->num_param)
532                     && (state->data_sent == state->num_data));
533
534         status = cli_pull_trans(
535                 inbuf, wct, vwv, num_bytes, bytes,
536                 state->cmd, !sent_all, &num_setup, &setup,
537                 &total_param, &num_param, &param_disp, &param,
538                 &total_data, &num_data, &data_disp, &data);
539
540         if (!NT_STATUS_IS_OK(status)) {
541                 goto fail;
542         }
543
544         if (!sent_all) {
545                 int iov_count;
546                 struct tevent_req *subreq2;
547
548                 cli_trans_format(state, &wct, &iov_count);
549
550                 subreq2 = cli_smb_req_create(state, state->ev, state->cli,
551                                              state->cmd + 1, 0, wct, state->vwv,
552                                              iov_count, state->iov);
553                 if (tevent_req_nomem(subreq2, req)) {
554                         return;
555                 }
556                 cli_smb_req_set_mid(subreq2, state->mid);
557
558                 status = cli_smb_req_send(subreq2);
559
560                 if (!NT_STATUS_IS_OK(status)) {
561                         goto fail;
562                 }
563                 tevent_req_set_callback(subreq2, cli_trans_done2, req);
564
565                 return;
566         }
567
568         status = cli_trans_pull_blob(
569                 state, &state->rparam, total_param, num_param, param,
570                 param_disp);
571
572         if (!NT_STATUS_IS_OK(status)) {
573                 DEBUG(10, ("Pulling params failed: %s\n", nt_errstr(status)));
574                 goto fail;
575         }
576
577         status = cli_trans_pull_blob(
578                 state, &state->rdata, total_data, num_data, data,
579                 data_disp);
580
581         if (!NT_STATUS_IS_OK(status)) {
582                 DEBUG(10, ("Pulling data failed: %s\n", nt_errstr(status)));
583                 goto fail;
584         }
585
586         if ((state->rparam.total == state->rparam.received)
587             && (state->rdata.total == state->rdata.received)) {
588                 state->recv_flags2 = SVAL(inhdr, HDR_FLG2);
589                 cli_trans_cleanup_primary(state);
590                 tevent_req_done(req);
591                 return;
592         }
593
594         TALLOC_FREE(inbuf);
595
596         return;
597
598  fail:
599         cli_trans_cleanup_primary(state);
600         tevent_req_nterror(req, status);
601 }
602
603 static void cli_trans_done2(struct tevent_req *subreq2)
604 {
605         struct tevent_req *req = tevent_req_callback_data(
606                 subreq2, struct tevent_req);
607         struct cli_trans_state *state = tevent_req_data(
608                 req, struct cli_trans_state);
609         NTSTATUS status;
610         bool sent_all;
611         uint8_t wct;
612         uint32_t seqnum;
613
614         /*
615          * First backup the seqnum of the secondary request
616          * and attach it to the primary request.
617          */
618         seqnum = cli_smb_req_seqnum(subreq2);
619         cli_smb_req_set_seqnum(state->primary_subreq, seqnum);
620
621         status = cli_smb_recv(subreq2, state, NULL, 0, &wct, NULL,
622                               NULL, NULL);
623         TALLOC_FREE(subreq2);
624
625         if (!NT_STATUS_IS_OK(status)) {
626                 goto fail;
627         }
628
629         if (wct != 0) {
630                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
631                 goto fail;
632         }
633
634         sent_all = ((state->param_sent == state->num_param)
635                     && (state->data_sent == state->num_data));
636
637         if (!sent_all) {
638                 int iov_count;
639
640                 cli_trans_format(state, &wct, &iov_count);
641
642                 subreq2 = cli_smb_req_create(state, state->ev, state->cli,
643                                              state->cmd + 1, 0, wct, state->vwv,
644                                              iov_count, state->iov);
645                 if (tevent_req_nomem(subreq2, req)) {
646                         return;
647                 }
648                 cli_smb_req_set_mid(subreq2, state->mid);
649
650                 status = cli_smb_req_send(subreq2);
651
652                 if (!NT_STATUS_IS_OK(status)) {
653                         goto fail;
654                 }
655                 tevent_req_set_callback(subreq2, cli_trans_done2, req);
656                 return;
657         }
658
659         return;
660
661  fail:
662         cli_trans_cleanup_primary(state);
663         tevent_req_nterror(req, status);
664 }
665
666 NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
667                         uint16_t *recv_flags2,
668                         uint16_t **setup, uint8_t min_setup,
669                         uint8_t *num_setup,
670                         uint8_t **param, uint32_t min_param,
671                         uint32_t *num_param,
672                         uint8_t **data, uint32_t min_data,
673                         uint32_t *num_data)
674 {
675         struct cli_trans_state *state = tevent_req_data(
676                 req, struct cli_trans_state);
677         NTSTATUS status;
678
679         cli_trans_cleanup_primary(state);
680
681         if (tevent_req_is_nterror(req, &status)) {
682                 return status;
683         }
684
685         if ((state->num_rsetup < min_setup)
686             || (state->rparam.total < min_param)
687             || (state->rdata.total < min_data)) {
688                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
689         }
690
691         if (recv_flags2 != NULL) {
692                 *recv_flags2 = state->recv_flags2;
693         }
694
695         if (setup != NULL) {
696                 *setup = talloc_move(mem_ctx, &state->rsetup);
697                 *num_setup = state->num_rsetup;
698         } else {
699                 TALLOC_FREE(state->rsetup);
700         }
701
702         if (param != NULL) {
703                 *param = talloc_move(mem_ctx, &state->rparam.data);
704                 *num_param = state->rparam.total;
705         } else {
706                 TALLOC_FREE(state->rparam.data);
707         }
708
709         if (data != NULL) {
710                 *data = talloc_move(mem_ctx, &state->rdata.data);
711                 *num_data = state->rdata.total;
712         } else {
713                 TALLOC_FREE(state->rdata.data);
714         }
715
716         return NT_STATUS_OK;
717 }
718
719 NTSTATUS cli_trans(TALLOC_CTX *mem_ctx, struct cli_state *cli,
720                    uint8_t trans_cmd,
721                    const char *pipe_name, uint16_t fid, uint16_t function,
722                    int flags,
723                    uint16_t *setup, uint8_t num_setup, uint8_t max_setup,
724                    uint8_t *param, uint32_t num_param, uint32_t max_param,
725                    uint8_t *data, uint32_t num_data, uint32_t max_data,
726                    uint16_t *recv_flags2,
727                    uint16_t **rsetup, uint8_t min_rsetup, uint8_t *num_rsetup,
728                    uint8_t **rparam, uint32_t min_rparam, uint32_t *num_rparam,
729                    uint8_t **rdata, uint32_t min_rdata, uint32_t *num_rdata)
730 {
731         TALLOC_CTX *frame = talloc_stackframe();
732         struct tevent_context *ev;
733         struct tevent_req *req;
734         NTSTATUS status = NT_STATUS_OK;
735
736         if (cli_has_async_calls(cli)) {
737                 /*
738                  * Can't use sync call while an async call is in flight
739                  */
740                 status = NT_STATUS_INVALID_PARAMETER;
741                 goto fail;
742         }
743
744         ev = tevent_context_init(frame);
745         if (ev == NULL) {
746                 status = NT_STATUS_NO_MEMORY;
747                 goto fail;
748         }
749
750         req = cli_trans_send(frame, ev, cli, trans_cmd,
751                              pipe_name, fid, function, flags,
752                              setup, num_setup, max_setup,
753                              param, num_param, max_param,
754                              data, num_data, max_data);
755         if (req == NULL) {
756                 status = NT_STATUS_NO_MEMORY;
757                 goto fail;
758         }
759
760         if (!tevent_req_poll(req, ev)) {
761                 status = map_nt_error_from_unix_common(errno);
762                 goto fail;
763         }
764
765         status = cli_trans_recv(req, mem_ctx, recv_flags2,
766                                 rsetup, min_rsetup, num_rsetup,
767                                 rparam, min_rparam, num_rparam,
768                                 rdata, min_rdata, num_rdata);
769  fail:
770         TALLOC_FREE(frame);
771         return status;
772 }