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