smbXcli: add state->smb1.recv_{cmd,status,iov}
[kai/samba.git] / libcli / smb / smbXcli_base.c
1 /*
2    Unix SMB/CIFS implementation.
3    Infrastructure for async SMB client requests
4    Copyright (C) Volker Lendecke 2008
5    Copyright (C) Stefan Metzmacher 2011
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "system/network.h"
23 #include "../lib/async_req/async_sock.h"
24 #include "../lib/util/tevent_ntstatus.h"
25 #include "../lib/util/tevent_unix.h"
26 #include "lib/util/util_net.h"
27 #include "../libcli/smb/smb_common.h"
28 #include "../libcli/smb/smb_seal.h"
29 #include "../libcli/smb/smb_signing.h"
30 #include "../libcli/smb/read_smb.h"
31 #include "smbXcli_base.h"
32 #include "librpc/ndr/libndr.h"
33
34 struct smbXcli_conn {
35         int fd;
36         struct sockaddr_storage local_ss;
37         struct sockaddr_storage remote_ss;
38         const char *remote_name;
39
40         struct tevent_queue *outgoing;
41         struct tevent_req **pending;
42         struct tevent_req *read_smb_req;
43
44         enum protocol_types protocol;
45         bool allow_signing;
46         bool desire_signing;
47         bool mandatory_signing;
48
49         /*
50          * The incoming dispatch function should return:
51          * - NT_STATUS_RETRY, if more incoming PDUs are expected.
52          * - NT_STATUS_OK, if no more processing is desired, e.g.
53          *                 the dispatch function called
54          *                 tevent_req_done().
55          * - All other return values disconnect the connection.
56          */
57         NTSTATUS (*dispatch_incoming)(struct smbXcli_conn *conn,
58                                       TALLOC_CTX *tmp_mem,
59                                       uint8_t *inbuf);
60
61         struct {
62                 struct {
63                         uint32_t capabilities;
64                         uint32_t max_xmit;
65                 } client;
66
67                 struct {
68                         uint32_t capabilities;
69                         uint32_t max_xmit;
70                         uint16_t max_mux;
71                         uint16_t security_mode;
72                         bool readbraw;
73                         bool writebraw;
74                         bool lockread;
75                         bool writeunlock;
76                         uint32_t session_key;
77                         struct GUID guid;
78                         DATA_BLOB gss_blob;
79                         uint8_t challenge[8];
80                         const char *workgroup;
81                         int time_zone;
82                         NTTIME system_time;
83                 } server;
84
85                 uint32_t capabilities;
86                 uint32_t max_xmit;
87
88                 uint16_t mid;
89
90                 struct smb_signing_state *signing;
91                 struct smb_trans_enc_state *trans_enc;
92         } smb1;
93
94         struct {
95                 struct {
96                         uint16_t security_mode;
97                 } client;
98
99                 struct {
100                         uint32_t capabilities;
101                         uint16_t security_mode;
102                         struct GUID guid;
103                         uint32_t max_trans_size;
104                         uint32_t max_read_size;
105                         uint32_t max_write_size;
106                         NTTIME system_time;
107                         NTTIME start_time;
108                         DATA_BLOB gss_blob;
109                 } server;
110
111                 uint64_t mid;
112         } smb2;
113 };
114
115 struct smbXcli_req_state {
116         struct tevent_context *ev;
117         struct smbXcli_conn *conn;
118
119         uint8_t length_hdr[4];
120
121         bool one_way;
122
123         uint8_t *inbuf;
124
125         struct {
126                 /* Space for the header including the wct */
127                 uint8_t hdr[HDR_VWV];
128
129                 /*
130                  * For normal requests, smb1cli_req_send chooses a mid.
131                  * SecondaryV trans requests need to use the mid of the primary
132                  * request, so we need a place to store it.
133                  * Assume it is set if != 0.
134                  */
135                 uint16_t mid;
136
137                 uint16_t *vwv;
138                 uint8_t bytecount_buf[2];
139
140 #define MAX_SMB_IOV 5
141                 /* length_hdr, hdr, words, byte_count, buffers */
142                 struct iovec iov[1 + 3 + MAX_SMB_IOV];
143                 int iov_count;
144
145                 uint32_t seqnum;
146                 int chain_num;
147                 int chain_length;
148                 struct tevent_req **chained_requests;
149
150                 uint8_t recv_cmd;
151                 NTSTATUS recv_status;
152                 /* always an array of 3 talloc elements */
153                 struct iovec *recv_iov;
154         } smb1;
155
156         struct {
157                 const uint8_t *fixed;
158                 uint16_t fixed_len;
159                 const uint8_t *dyn;
160                 uint32_t dyn_len;
161
162                 uint8_t hdr[64];
163                 uint8_t pad[7]; /* padding space for compounding */
164
165                 /* always an array of 3 talloc elements */
166                 struct iovec *recv_iov;
167         } smb2;
168 };
169
170 static int smbXcli_conn_destructor(struct smbXcli_conn *conn)
171 {
172         /*
173          * NT_STATUS_OK, means we do not notify the callers
174          */
175         smbXcli_conn_disconnect(conn, NT_STATUS_OK);
176
177         if (conn->smb1.trans_enc) {
178                 common_free_encryption_state(&conn->smb1.trans_enc);
179         }
180
181         return 0;
182 }
183
184 struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx,
185                                          int fd,
186                                          const char *remote_name,
187                                          enum smb_signing_setting signing_state,
188                                          uint32_t smb1_capabilities)
189 {
190         struct smbXcli_conn *conn = NULL;
191         void *ss = NULL;
192         struct sockaddr *sa = NULL;
193         socklen_t sa_length;
194         int ret;
195
196         conn = talloc_zero(mem_ctx, struct smbXcli_conn);
197         if (!conn) {
198                 return NULL;
199         }
200
201         conn->remote_name = talloc_strdup(conn, remote_name);
202         if (conn->remote_name == NULL) {
203                 goto error;
204         }
205
206         conn->fd = fd;
207
208         ss = (void *)&conn->local_ss;
209         sa = (struct sockaddr *)ss;
210         sa_length = sizeof(conn->local_ss);
211         ret = getsockname(fd, sa, &sa_length);
212         if (ret == -1) {
213                 goto error;
214         }
215         ss = (void *)&conn->remote_ss;
216         sa = (struct sockaddr *)ss;
217         sa_length = sizeof(conn->remote_ss);
218         ret = getpeername(fd, sa, &sa_length);
219         if (ret == -1) {
220                 goto error;
221         }
222
223         conn->outgoing = tevent_queue_create(conn, "smbXcli_outgoing");
224         if (conn->outgoing == NULL) {
225                 goto error;
226         }
227         conn->pending = NULL;
228
229         conn->protocol = PROTOCOL_NONE;
230
231         switch (signing_state) {
232         case SMB_SIGNING_OFF:
233                 /* never */
234                 conn->allow_signing = false;
235                 conn->desire_signing = false;
236                 conn->mandatory_signing = false;
237                 break;
238         case SMB_SIGNING_DEFAULT:
239         case SMB_SIGNING_IF_REQUIRED:
240                 /* if the server requires it */
241                 conn->allow_signing = true;
242                 conn->desire_signing = false;
243                 conn->mandatory_signing = false;
244                 break;
245         case SMB_SIGNING_REQUIRED:
246                 /* always */
247                 conn->allow_signing = true;
248                 conn->desire_signing = true;
249                 conn->mandatory_signing = true;
250                 break;
251         }
252
253         conn->smb1.client.capabilities = smb1_capabilities;
254         conn->smb1.client.max_xmit = UINT16_MAX;
255
256         conn->smb1.capabilities = conn->smb1.client.capabilities;
257         conn->smb1.max_xmit = 1024;
258
259         conn->smb1.mid = 1;
260
261         /* initialise signing */
262         conn->smb1.signing = smb_signing_init(conn,
263                                               conn->allow_signing,
264                                               conn->desire_signing,
265                                               conn->mandatory_signing);
266         if (!conn->smb1.signing) {
267                 goto error;
268         }
269
270         conn->smb2.client.security_mode = SMB2_NEGOTIATE_SIGNING_ENABLED;
271         if (conn->mandatory_signing) {
272                 conn->smb2.client.security_mode |= SMB2_NEGOTIATE_SIGNING_REQUIRED;
273         }
274
275         talloc_set_destructor(conn, smbXcli_conn_destructor);
276         return conn;
277
278  error:
279         TALLOC_FREE(conn);
280         return NULL;
281 }
282
283 bool smbXcli_conn_is_connected(struct smbXcli_conn *conn)
284 {
285         if (conn == NULL) {
286                 return false;
287         }
288
289         if (conn->fd == -1) {
290                 return false;
291         }
292
293         return true;
294 }
295
296 enum protocol_types smbXcli_conn_protocol(struct smbXcli_conn *conn)
297 {
298         return conn->protocol;
299 }
300
301 bool smbXcli_conn_use_unicode(struct smbXcli_conn *conn)
302 {
303         if (conn->protocol >= PROTOCOL_SMB2_02) {
304                 return true;
305         }
306
307         if (conn->smb1.capabilities & CAP_UNICODE) {
308                 return true;
309         }
310
311         return false;
312 }
313
314 void smbXcli_conn_set_sockopt(struct smbXcli_conn *conn, const char *options)
315 {
316         set_socket_options(conn->fd, options);
317 }
318
319 const struct sockaddr_storage *smbXcli_conn_local_sockaddr(struct smbXcli_conn *conn)
320 {
321         return &conn->local_ss;
322 }
323
324 const struct sockaddr_storage *smbXcli_conn_remote_sockaddr(struct smbXcli_conn *conn)
325 {
326         return &conn->remote_ss;
327 }
328
329 const char *smbXcli_conn_remote_name(struct smbXcli_conn *conn)
330 {
331         return conn->remote_name;
332 }
333
334 bool smb1cli_conn_activate_signing(struct smbXcli_conn *conn,
335                                    const DATA_BLOB user_session_key,
336                                    const DATA_BLOB response)
337 {
338         return smb_signing_activate(conn->smb1.signing,
339                                     user_session_key,
340                                     response);
341 }
342
343 bool smb1cli_conn_check_signing(struct smbXcli_conn *conn,
344                                 const uint8_t *buf, uint32_t seqnum)
345 {
346         return smb_signing_check_pdu(conn->smb1.signing, buf, seqnum);
347 }
348
349 bool smb1cli_conn_signing_is_active(struct smbXcli_conn *conn)
350 {
351         return smb_signing_is_active(conn->smb1.signing);
352 }
353
354 void smb1cli_conn_set_encryption(struct smbXcli_conn *conn,
355                                  struct smb_trans_enc_state *es)
356 {
357         /* Replace the old state, if any. */
358         if (conn->smb1.trans_enc) {
359                 common_free_encryption_state(&conn->smb1.trans_enc);
360         }
361         conn->smb1.trans_enc = es;
362 }
363
364 bool smb1cli_conn_encryption_on(struct smbXcli_conn *conn)
365 {
366         return common_encryption_on(conn->smb1.trans_enc);
367 }
368
369
370 static NTSTATUS smb1cli_pull_raw_error(const uint8_t *buf)
371 {
372         const uint8_t *hdr = buf + NBT_HDR_SIZE;
373         uint32_t flags2 = SVAL(hdr, HDR_FLG2);
374         NTSTATUS status = NT_STATUS(IVAL(hdr, HDR_RCLS));
375
376         if (NT_STATUS_IS_OK(status)) {
377                 return NT_STATUS_OK;
378         }
379
380         if (flags2 & FLAGS2_32_BIT_ERROR_CODES) {
381                 return status;
382         }
383
384         return NT_STATUS_DOS(CVAL(hdr, HDR_RCLS), SVAL(hdr, HDR_ERR));
385 }
386
387 /**
388  * Figure out if there is an andx command behind the current one
389  * @param[in] buf       The smb buffer to look at
390  * @param[in] ofs       The offset to the wct field that is followed by the cmd
391  * @retval Is there a command following?
392  */
393
394 static bool smb1cli_have_andx_command(const uint8_t *buf,
395                                       uint16_t ofs,
396                                       uint8_t cmd)
397 {
398         uint8_t wct;
399         size_t buflen = talloc_get_size(buf);
400
401         if (!smb1cli_is_andx_req(cmd)) {
402                 return false;
403         }
404
405         if ((ofs == buflen-1) || (ofs == buflen)) {
406                 return false;
407         }
408
409         wct = CVAL(buf, ofs);
410         if (wct < 2) {
411                 /*
412                  * Not enough space for the command and a following pointer
413                  */
414                 return false;
415         }
416         return (CVAL(buf, ofs+1) != 0xff);
417 }
418
419 /**
420  * Is the SMB command able to hold an AND_X successor
421  * @param[in] cmd       The SMB command in question
422  * @retval Can we add a chained request after "cmd"?
423  */
424 bool smb1cli_is_andx_req(uint8_t cmd)
425 {
426         switch (cmd) {
427         case SMBtconX:
428         case SMBlockingX:
429         case SMBopenX:
430         case SMBreadX:
431         case SMBwriteX:
432         case SMBsesssetupX:
433         case SMBulogoffX:
434         case SMBntcreateX:
435                 return true;
436                 break;
437         default:
438                 break;
439         }
440
441         return false;
442 }
443
444 static uint16_t smb1cli_alloc_mid(struct smbXcli_conn *conn)
445 {
446         size_t num_pending = talloc_array_length(conn->pending);
447         uint16_t result;
448
449         while (true) {
450                 size_t i;
451
452                 result = conn->smb1.mid++;
453                 if ((result == 0) || (result == 0xffff)) {
454                         continue;
455                 }
456
457                 for (i=0; i<num_pending; i++) {
458                         if (result == smb1cli_req_mid(conn->pending[i])) {
459                                 break;
460                         }
461                 }
462
463                 if (i == num_pending) {
464                         return result;
465                 }
466         }
467 }
468
469 void smbXcli_req_unset_pending(struct tevent_req *req)
470 {
471         struct smbXcli_req_state *state =
472                 tevent_req_data(req,
473                 struct smbXcli_req_state);
474         struct smbXcli_conn *conn = state->conn;
475         size_t num_pending = talloc_array_length(conn->pending);
476         size_t i;
477
478         if (state->smb1.mid != 0) {
479                 /*
480                  * This is a [nt]trans[2] request which waits
481                  * for more than one reply.
482                  */
483                 return;
484         }
485
486         talloc_set_destructor(req, NULL);
487
488         if (num_pending == 1) {
489                 /*
490                  * The pending read_smb tevent_req is a child of
491                  * conn->pending. So if nothing is pending anymore, we need to
492                  * delete the socket read fde.
493                  */
494                 TALLOC_FREE(conn->pending);
495                 conn->read_smb_req = NULL;
496                 return;
497         }
498
499         for (i=0; i<num_pending; i++) {
500                 if (req == conn->pending[i]) {
501                         break;
502                 }
503         }
504         if (i == num_pending) {
505                 /*
506                  * Something's seriously broken. Just returning here is the
507                  * right thing nevertheless, the point of this routine is to
508                  * remove ourselves from conn->pending.
509                  */
510                 return;
511         }
512
513         /*
514          * Remove ourselves from the conn->pending array
515          */
516         for (; i < (num_pending - 1); i++) {
517                 conn->pending[i] = conn->pending[i+1];
518         }
519
520         /*
521          * No NULL check here, we're shrinking by sizeof(void *), and
522          * talloc_realloc just adjusts the size for this.
523          */
524         conn->pending = talloc_realloc(NULL, conn->pending, struct tevent_req *,
525                                        num_pending - 1);
526         return;
527 }
528
529 static int smbXcli_req_destructor(struct tevent_req *req)
530 {
531         struct smbXcli_req_state *state =
532                 tevent_req_data(req,
533                 struct smbXcli_req_state);
534
535         /*
536          * Make sure we really remove it from
537          * the pending array on destruction.
538          */
539         state->smb1.mid = 0;
540         smbXcli_req_unset_pending(req);
541         return 0;
542 }
543
544 static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn);
545
546 bool smbXcli_req_set_pending(struct tevent_req *req)
547 {
548         struct smbXcli_req_state *state =
549                 tevent_req_data(req,
550                 struct smbXcli_req_state);
551         struct smbXcli_conn *conn;
552         struct tevent_req **pending;
553         size_t num_pending;
554
555         conn = state->conn;
556
557         if (!smbXcli_conn_is_connected(conn)) {
558                 return false;
559         }
560
561         num_pending = talloc_array_length(conn->pending);
562
563         pending = talloc_realloc(conn, conn->pending, struct tevent_req *,
564                                  num_pending+1);
565         if (pending == NULL) {
566                 return false;
567         }
568         pending[num_pending] = req;
569         conn->pending = pending;
570         talloc_set_destructor(req, smbXcli_req_destructor);
571
572         if (!smbXcli_conn_receive_next(conn)) {
573                 /*
574                  * the caller should notify the current request
575                  *
576                  * And all other pending requests get notified
577                  * by smbXcli_conn_disconnect().
578                  */
579                 smbXcli_req_unset_pending(req);
580                 smbXcli_conn_disconnect(conn, NT_STATUS_NO_MEMORY);
581                 return false;
582         }
583
584         return true;
585 }
586
587 static void smbXcli_conn_received(struct tevent_req *subreq);
588
589 static bool smbXcli_conn_receive_next(struct smbXcli_conn *conn)
590 {
591         size_t num_pending = talloc_array_length(conn->pending);
592         struct tevent_req *req;
593         struct smbXcli_req_state *state;
594
595         if (conn->read_smb_req != NULL) {
596                 return true;
597         }
598
599         if (num_pending == 0) {
600                 if (conn->smb2.mid < UINT64_MAX) {
601                         /* no more pending requests, so we are done for now */
602                         return true;
603                 }
604
605                 /*
606                  * If there are no more SMB2 requests possible,
607                  * because we are out of message ids,
608                  * we need to disconnect.
609                  */
610                 smbXcli_conn_disconnect(conn, NT_STATUS_CONNECTION_ABORTED);
611                 return true;
612         }
613
614         req = conn->pending[0];
615         state = tevent_req_data(req, struct smbXcli_req_state);
616
617         /*
618          * We're the first ones, add the read_smb request that waits for the
619          * answer from the server
620          */
621         conn->read_smb_req = read_smb_send(conn->pending, state->ev, conn->fd);
622         if (conn->read_smb_req == NULL) {
623                 return false;
624         }
625         tevent_req_set_callback(conn->read_smb_req, smbXcli_conn_received, conn);
626         return true;
627 }
628
629 void smbXcli_conn_disconnect(struct smbXcli_conn *conn, NTSTATUS status)
630 {
631         if (conn->fd != -1) {
632                 close(conn->fd);
633         }
634         conn->fd = -1;
635
636         /*
637          * Cancel all pending requests. We do not do a for-loop walking
638          * conn->pending because that array changes in
639          * smbXcli_req_unset_pending.
640          */
641         while (talloc_array_length(conn->pending) > 0) {
642                 struct tevent_req *req;
643                 struct smbXcli_req_state *state;
644
645                 req = conn->pending[0];
646                 state = tevent_req_data(req, struct smbXcli_req_state);
647
648                 /*
649                  * We're dead. No point waiting for trans2
650                  * replies.
651                  */
652                 state->smb1.mid = 0;
653
654                 smbXcli_req_unset_pending(req);
655
656                 if (NT_STATUS_IS_OK(status)) {
657                         /* do not notify the callers */
658                         continue;
659                 }
660
661                 /*
662                  * we need to defer the callback, because we may notify more
663                  * then one caller.
664                  */
665                 tevent_req_defer_callback(req, state->ev);
666                 tevent_req_nterror(req, status);
667         }
668 }
669
670 /*
671  * Fetch a smb request's mid. Only valid after the request has been sent by
672  * smb1cli_req_send().
673  */
674 uint16_t smb1cli_req_mid(struct tevent_req *req)
675 {
676         struct smbXcli_req_state *state =
677                 tevent_req_data(req,
678                 struct smbXcli_req_state);
679
680         if (state->smb1.mid != 0) {
681                 return state->smb1.mid;
682         }
683
684         return SVAL(state->smb1.hdr, HDR_MID);
685 }
686
687 void smb1cli_req_set_mid(struct tevent_req *req, uint16_t mid)
688 {
689         struct smbXcli_req_state *state =
690                 tevent_req_data(req,
691                 struct smbXcli_req_state);
692
693         state->smb1.mid = mid;
694 }
695
696 uint32_t smb1cli_req_seqnum(struct tevent_req *req)
697 {
698         struct smbXcli_req_state *state =
699                 tevent_req_data(req,
700                 struct smbXcli_req_state);
701
702         return state->smb1.seqnum;
703 }
704
705 void smb1cli_req_set_seqnum(struct tevent_req *req, uint32_t seqnum)
706 {
707         struct smbXcli_req_state *state =
708                 tevent_req_data(req,
709                 struct smbXcli_req_state);
710
711         state->smb1.seqnum = seqnum;
712 }
713
714 static size_t smbXcli_iov_len(const struct iovec *iov, int count)
715 {
716         size_t result = 0;
717         int i;
718         for (i=0; i<count; i++) {
719                 result += iov[i].iov_len;
720         }
721         return result;
722 }
723
724 static uint8_t *smbXcli_iov_concat(TALLOC_CTX *mem_ctx,
725                                    const struct iovec *iov,
726                                    int count)
727 {
728         size_t len = smbXcli_iov_len(iov, count);
729         size_t copied;
730         uint8_t *buf;
731         int i;
732
733         buf = talloc_array(mem_ctx, uint8_t, len);
734         if (buf == NULL) {
735                 return NULL;
736         }
737         copied = 0;
738         for (i=0; i<count; i++) {
739                 memcpy(buf+copied, iov[i].iov_base, iov[i].iov_len);
740                 copied += iov[i].iov_len;
741         }
742         return buf;
743 }
744
745 static void smb1cli_req_flags(enum protocol_types protocol,
746                               uint32_t smb1_capabilities,
747                               uint8_t smb_command,
748                               uint8_t additional_flags,
749                               uint8_t clear_flags,
750                               uint8_t *_flags,
751                               uint16_t additional_flags2,
752                               uint16_t clear_flags2,
753                               uint16_t *_flags2)
754 {
755         uint8_t flags = 0;
756         uint16_t flags2 = 0;
757
758         if (protocol >= PROTOCOL_LANMAN1) {
759                 flags |= FLAG_CASELESS_PATHNAMES;
760                 flags |= FLAG_CANONICAL_PATHNAMES;
761         }
762
763         if (protocol >= PROTOCOL_LANMAN2) {
764                 flags2 |= FLAGS2_LONG_PATH_COMPONENTS;
765                 flags2 |= FLAGS2_EXTENDED_ATTRIBUTES;
766         }
767
768         if (protocol >= PROTOCOL_NT1) {
769                 flags2 |= FLAGS2_IS_LONG_NAME;
770
771                 if (smb1_capabilities & CAP_UNICODE) {
772                         flags2 |= FLAGS2_UNICODE_STRINGS;
773                 }
774                 if (smb1_capabilities & CAP_STATUS32) {
775                         flags2 |= FLAGS2_32_BIT_ERROR_CODES;
776                 }
777                 if (smb1_capabilities & CAP_EXTENDED_SECURITY) {
778                         flags2 |= FLAGS2_EXTENDED_SECURITY;
779                 }
780         }
781
782         flags |= additional_flags;
783         flags &= ~clear_flags;
784         flags2 |= additional_flags2;
785         flags2 &= ~clear_flags2;
786
787         *_flags = flags;
788         *_flags2 = flags2;
789 }
790
791 struct tevent_req *smb1cli_req_create(TALLOC_CTX *mem_ctx,
792                                       struct tevent_context *ev,
793                                       struct smbXcli_conn *conn,
794                                       uint8_t smb_command,
795                                       uint8_t additional_flags,
796                                       uint8_t clear_flags,
797                                       uint16_t additional_flags2,
798                                       uint16_t clear_flags2,
799                                       uint32_t timeout_msec,
800                                       uint32_t pid,
801                                       uint16_t tid,
802                                       uint16_t uid,
803                                       uint8_t wct, uint16_t *vwv,
804                                       int iov_count,
805                                       struct iovec *bytes_iov)
806 {
807         struct tevent_req *req;
808         struct smbXcli_req_state *state;
809         uint8_t flags = 0;
810         uint16_t flags2 = 0;
811
812         if (iov_count > MAX_SMB_IOV) {
813                 /*
814                  * Should not happen :-)
815                  */
816                 return NULL;
817         }
818
819         req = tevent_req_create(mem_ctx, &state,
820                                 struct smbXcli_req_state);
821         if (req == NULL) {
822                 return NULL;
823         }
824         state->ev = ev;
825         state->conn = conn;
826
827         state->smb1.recv_cmd = 0xFF;
828         state->smb1.recv_status = NT_STATUS_INTERNAL_ERROR;
829         state->smb1.recv_iov = talloc_zero_array(state, struct iovec, 3);
830         if (state->smb1.recv_iov == NULL) {
831                 TALLOC_FREE(req);
832                 return NULL;
833         }
834
835         smb1cli_req_flags(conn->protocol,
836                           conn->smb1.capabilities,
837                           smb_command,
838                           additional_flags,
839                           clear_flags,
840                           &flags,
841                           additional_flags2,
842                           clear_flags2,
843                           &flags2);
844
845         SIVAL(state->smb1.hdr, 0,           SMB_MAGIC);
846         SCVAL(state->smb1.hdr, HDR_COM,     smb_command);
847         SIVAL(state->smb1.hdr, HDR_RCLS,    NT_STATUS_V(NT_STATUS_OK));
848         SCVAL(state->smb1.hdr, HDR_FLG,     flags);
849         SSVAL(state->smb1.hdr, HDR_FLG2,    flags2);
850         SSVAL(state->smb1.hdr, HDR_PIDHIGH, pid >> 16);
851         SSVAL(state->smb1.hdr, HDR_TID,     tid);
852         SSVAL(state->smb1.hdr, HDR_PID,     pid);
853         SSVAL(state->smb1.hdr, HDR_UID,     uid);
854         SSVAL(state->smb1.hdr, HDR_MID,     0); /* this comes later */
855         SSVAL(state->smb1.hdr, HDR_WCT,     wct);
856
857         state->smb1.vwv = vwv;
858
859         SSVAL(state->smb1.bytecount_buf, 0, smbXcli_iov_len(bytes_iov, iov_count));
860
861         state->smb1.iov[0].iov_base = (void *)state->length_hdr;
862         state->smb1.iov[0].iov_len  = sizeof(state->length_hdr);
863         state->smb1.iov[1].iov_base = (void *)state->smb1.hdr;
864         state->smb1.iov[1].iov_len  = sizeof(state->smb1.hdr);
865         state->smb1.iov[2].iov_base = (void *)state->smb1.vwv;
866         state->smb1.iov[2].iov_len  = wct * sizeof(uint16_t);
867         state->smb1.iov[3].iov_base = (void *)state->smb1.bytecount_buf;
868         state->smb1.iov[3].iov_len  = sizeof(uint16_t);
869
870         if (iov_count != 0) {
871                 memcpy(&state->smb1.iov[4], bytes_iov,
872                        iov_count * sizeof(*bytes_iov));
873         }
874         state->smb1.iov_count = iov_count + 4;
875
876         if (timeout_msec > 0) {
877                 struct timeval endtime;
878
879                 endtime = timeval_current_ofs_msec(timeout_msec);
880                 if (!tevent_req_set_endtime(req, ev, endtime)) {
881                         return req;
882                 }
883         }
884
885         switch (smb_command) {
886         case SMBtranss:
887         case SMBtranss2:
888         case SMBnttranss:
889         case SMBntcancel:
890                 state->one_way = true;
891                 break;
892         case SMBlockingX:
893                 if ((wct == 8) &&
894                     (CVAL(vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) {
895                         state->one_way = true;
896                 }
897                 break;
898         }
899
900         return req;
901 }
902
903 static NTSTATUS smb1cli_conn_signv(struct smbXcli_conn *conn,
904                                    struct iovec *iov, int iov_count,
905                                    uint32_t *seqnum)
906 {
907         uint8_t *buf;
908
909         /*
910          * Obvious optimization: Make cli_calculate_sign_mac work with struct
911          * iovec directly. MD5Update would do that just fine.
912          */
913
914         if (iov_count < 4) {
915                 return NT_STATUS_INVALID_PARAMETER_MIX;
916         }
917         if (iov[0].iov_len != NBT_HDR_SIZE) {
918                 return NT_STATUS_INVALID_PARAMETER_MIX;
919         }
920         if (iov[1].iov_len != (MIN_SMB_SIZE-sizeof(uint16_t))) {
921                 return NT_STATUS_INVALID_PARAMETER_MIX;
922         }
923         if (iov[2].iov_len > (0xFF * sizeof(uint16_t))) {
924                 return NT_STATUS_INVALID_PARAMETER_MIX;
925         }
926         if (iov[3].iov_len != sizeof(uint16_t)) {
927                 return NT_STATUS_INVALID_PARAMETER_MIX;
928         }
929
930         buf = smbXcli_iov_concat(talloc_tos(), iov, iov_count);
931         if (buf == NULL) {
932                 return NT_STATUS_NO_MEMORY;
933         }
934
935         *seqnum = smb_signing_next_seqnum(conn->smb1.signing, false);
936         smb_signing_sign_pdu(conn->smb1.signing, buf, *seqnum);
937         memcpy(iov[1].iov_base, buf+4, iov[1].iov_len);
938
939         TALLOC_FREE(buf);
940         return NT_STATUS_OK;
941 }
942
943 static void smb1cli_req_writev_done(struct tevent_req *subreq);
944 static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
945                                                TALLOC_CTX *tmp_mem,
946                                                uint8_t *inbuf);
947
948 static NTSTATUS smb1cli_req_writev_submit(struct tevent_req *req,
949                                           struct smbXcli_req_state *state,
950                                           struct iovec *iov, int iov_count)
951 {
952         struct tevent_req *subreq;
953         NTSTATUS status;
954         uint16_t mid;
955
956         if (!smbXcli_conn_is_connected(state->conn)) {
957                 return NT_STATUS_CONNECTION_DISCONNECTED;
958         }
959
960         if (state->conn->protocol > PROTOCOL_NT1) {
961                 return NT_STATUS_REVISION_MISMATCH;
962         }
963
964         if (iov_count < 4) {
965                 return NT_STATUS_INVALID_PARAMETER_MIX;
966         }
967         if (iov[0].iov_len != NBT_HDR_SIZE) {
968                 return NT_STATUS_INVALID_PARAMETER_MIX;
969         }
970         if (iov[1].iov_len != (MIN_SMB_SIZE-sizeof(uint16_t))) {
971                 return NT_STATUS_INVALID_PARAMETER_MIX;
972         }
973         if (iov[2].iov_len > (0xFF * sizeof(uint16_t))) {
974                 return NT_STATUS_INVALID_PARAMETER_MIX;
975         }
976         if (iov[3].iov_len != sizeof(uint16_t)) {
977                 return NT_STATUS_INVALID_PARAMETER_MIX;
978         }
979
980         if (state->smb1.mid != 0) {
981                 mid = state->smb1.mid;
982         } else {
983                 mid = smb1cli_alloc_mid(state->conn);
984         }
985         SSVAL(iov[1].iov_base, HDR_MID, mid);
986
987         _smb_setlen_nbt(iov[0].iov_base, smbXcli_iov_len(&iov[1], iov_count-1));
988
989         status = smb1cli_conn_signv(state->conn, iov, iov_count,
990                                     &state->smb1.seqnum);
991
992         if (!NT_STATUS_IS_OK(status)) {
993                 return status;
994         }
995
996         /*
997          * If we supported multiple encrytion contexts
998          * here we'd look up based on tid.
999          */
1000         if (common_encryption_on(state->conn->smb1.trans_enc)) {
1001                 char *buf, *enc_buf;
1002
1003                 buf = (char *)smbXcli_iov_concat(talloc_tos(), iov, iov_count);
1004                 if (buf == NULL) {
1005                         return NT_STATUS_NO_MEMORY;
1006                 }
1007                 status = common_encrypt_buffer(state->conn->smb1.trans_enc,
1008                                                (char *)buf, &enc_buf);
1009                 TALLOC_FREE(buf);
1010                 if (!NT_STATUS_IS_OK(status)) {
1011                         DEBUG(0, ("Error in encrypting client message: %s\n",
1012                                   nt_errstr(status)));
1013                         return status;
1014                 }
1015                 buf = (char *)talloc_memdup(state, enc_buf,
1016                                             smb_len_nbt(enc_buf)+4);
1017                 SAFE_FREE(enc_buf);
1018                 if (buf == NULL) {
1019                         return NT_STATUS_NO_MEMORY;
1020                 }
1021                 iov[0].iov_base = (void *)buf;
1022                 iov[0].iov_len = talloc_get_size(buf);
1023                 iov_count = 1;
1024         }
1025
1026         if (state->conn->dispatch_incoming == NULL) {
1027                 state->conn->dispatch_incoming = smb1cli_conn_dispatch_incoming;
1028         }
1029
1030         subreq = writev_send(state, state->ev, state->conn->outgoing,
1031                              state->conn->fd, false, iov, iov_count);
1032         if (subreq == NULL) {
1033                 return NT_STATUS_NO_MEMORY;
1034         }
1035         tevent_req_set_callback(subreq, smb1cli_req_writev_done, req);
1036         return NT_STATUS_OK;
1037 }
1038
1039 struct tevent_req *smb1cli_req_send(TALLOC_CTX *mem_ctx,
1040                                     struct tevent_context *ev,
1041                                     struct smbXcli_conn *conn,
1042                                     uint8_t smb_command,
1043                                     uint8_t additional_flags,
1044                                     uint8_t clear_flags,
1045                                     uint16_t additional_flags2,
1046                                     uint16_t clear_flags2,
1047                                     uint32_t timeout_msec,
1048                                     uint32_t pid,
1049                                     uint16_t tid,
1050                                     uint16_t uid,
1051                                     uint8_t wct, uint16_t *vwv,
1052                                     uint32_t num_bytes,
1053                                     const uint8_t *bytes)
1054 {
1055         struct tevent_req *req;
1056         struct iovec iov;
1057         NTSTATUS status;
1058
1059         iov.iov_base = discard_const_p(void, bytes);
1060         iov.iov_len = num_bytes;
1061
1062         req = smb1cli_req_create(mem_ctx, ev, conn, smb_command,
1063                                  additional_flags, clear_flags,
1064                                  additional_flags2, clear_flags2,
1065                                  timeout_msec,
1066                                  pid, tid, uid,
1067                                  wct, vwv, 1, &iov);
1068         if (req == NULL) {
1069                 return NULL;
1070         }
1071         if (!tevent_req_is_in_progress(req)) {
1072                 return tevent_req_post(req, ev);
1073         }
1074         status = smb1cli_req_chain_submit(&req, 1);
1075         if (tevent_req_nterror(req, status)) {
1076                 return tevent_req_post(req, ev);
1077         }
1078         return req;
1079 }
1080
1081 static void smb1cli_req_writev_done(struct tevent_req *subreq)
1082 {
1083         struct tevent_req *req =
1084                 tevent_req_callback_data(subreq,
1085                 struct tevent_req);
1086         struct smbXcli_req_state *state =
1087                 tevent_req_data(req,
1088                 struct smbXcli_req_state);
1089         ssize_t nwritten;
1090         int err;
1091
1092         nwritten = writev_recv(subreq, &err);
1093         TALLOC_FREE(subreq);
1094         if (nwritten == -1) {
1095                 NTSTATUS status = map_nt_error_from_unix_common(err);
1096                 smbXcli_conn_disconnect(state->conn, status);
1097                 return;
1098         }
1099
1100         if (state->one_way) {
1101                 state->inbuf = NULL;
1102                 tevent_req_done(req);
1103                 return;
1104         }
1105
1106         if (!smbXcli_req_set_pending(req)) {
1107                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1108                 return;
1109         }
1110 }
1111
1112 static void smbXcli_conn_received(struct tevent_req *subreq)
1113 {
1114         struct smbXcli_conn *conn =
1115                 tevent_req_callback_data(subreq,
1116                 struct smbXcli_conn);
1117         TALLOC_CTX *frame = talloc_stackframe();
1118         NTSTATUS status;
1119         uint8_t *inbuf;
1120         ssize_t received;
1121         int err;
1122
1123         if (subreq != conn->read_smb_req) {
1124                 DEBUG(1, ("Internal error: cli_smb_received called with "
1125                           "unexpected subreq\n"));
1126                 status = NT_STATUS_INTERNAL_ERROR;
1127                 smbXcli_conn_disconnect(conn, status);
1128                 TALLOC_FREE(frame);
1129                 return;
1130         }
1131         conn->read_smb_req = NULL;
1132
1133         received = read_smb_recv(subreq, frame, &inbuf, &err);
1134         TALLOC_FREE(subreq);
1135         if (received == -1) {
1136                 status = map_nt_error_from_unix_common(err);
1137                 smbXcli_conn_disconnect(conn, status);
1138                 TALLOC_FREE(frame);
1139                 return;
1140         }
1141
1142         status = conn->dispatch_incoming(conn, frame, inbuf);
1143         TALLOC_FREE(frame);
1144         if (NT_STATUS_IS_OK(status)) {
1145                 /*
1146                  * We should not do any more processing
1147                  * as the dispatch function called
1148                  * tevent_req_done().
1149                  */
1150                 return;
1151         } else if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
1152                 /*
1153                  * We got an error, so notify all pending requests
1154                  */
1155                 smbXcli_conn_disconnect(conn, status);
1156                 return;
1157         }
1158
1159         /*
1160          * We got NT_STATUS_RETRY, so we may ask for a
1161          * next incoming pdu.
1162          */
1163         if (!smbXcli_conn_receive_next(conn)) {
1164                 smbXcli_conn_disconnect(conn, NT_STATUS_NO_MEMORY);
1165         }
1166 }
1167
1168 static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
1169                                                TALLOC_CTX *tmp_mem,
1170                                                uint8_t *inbuf)
1171 {
1172         struct tevent_req *req;
1173         struct smbXcli_req_state *state;
1174         NTSTATUS status;
1175         size_t num_pending;
1176         size_t i;
1177         uint16_t mid;
1178         bool oplock_break;
1179         const uint8_t *inhdr = inbuf + NBT_HDR_SIZE;
1180
1181         if ((IVAL(inhdr, 0) != SMB_MAGIC) /* 0xFF"SMB" */
1182             && (SVAL(inhdr, 0) != 0x45ff)) /* 0xFF"E" */ {
1183                 DEBUG(10, ("Got non-SMB PDU\n"));
1184                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1185         }
1186
1187         /*
1188          * If we supported multiple encrytion contexts
1189          * here we'd look up based on tid.
1190          */
1191         if (common_encryption_on(conn->smb1.trans_enc)
1192             && (CVAL(inbuf, 0) == 0)) {
1193                 uint16_t enc_ctx_num;
1194
1195                 status = get_enc_ctx_num(inbuf, &enc_ctx_num);
1196                 if (!NT_STATUS_IS_OK(status)) {
1197                         DEBUG(10, ("get_enc_ctx_num returned %s\n",
1198                                    nt_errstr(status)));
1199                         return status;
1200                 }
1201
1202                 if (enc_ctx_num != conn->smb1.trans_enc->enc_ctx_num) {
1203                         DEBUG(10, ("wrong enc_ctx %d, expected %d\n",
1204                                    enc_ctx_num,
1205                                    conn->smb1.trans_enc->enc_ctx_num));
1206                         return NT_STATUS_INVALID_HANDLE;
1207                 }
1208
1209                 status = common_decrypt_buffer(conn->smb1.trans_enc,
1210                                                (char *)inbuf);
1211                 if (!NT_STATUS_IS_OK(status)) {
1212                         DEBUG(10, ("common_decrypt_buffer returned %s\n",
1213                                    nt_errstr(status)));
1214                         return status;
1215                 }
1216         }
1217
1218         mid = SVAL(inhdr, HDR_MID);
1219         num_pending = talloc_array_length(conn->pending);
1220
1221         for (i=0; i<num_pending; i++) {
1222                 if (mid == smb1cli_req_mid(conn->pending[i])) {
1223                         break;
1224                 }
1225         }
1226         if (i == num_pending) {
1227                 /* Dump unexpected reply */
1228                 return NT_STATUS_RETRY;
1229         }
1230
1231         oplock_break = false;
1232
1233         if (mid == 0xffff) {
1234                 /*
1235                  * Paranoia checks that this is really an oplock break request.
1236                  */
1237                 oplock_break = (smb_len_nbt(inbuf) == 51); /* hdr + 8 words */
1238                 oplock_break &= ((CVAL(inhdr, HDR_FLG) & FLAG_REPLY) == 0);
1239                 oplock_break &= (CVAL(inhdr, HDR_COM) == SMBlockingX);
1240                 oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(6)) == 0);
1241                 oplock_break &= (SVAL(inhdr, HDR_VWV+VWV(7)) == 0);
1242
1243                 if (!oplock_break) {
1244                         /* Dump unexpected reply */
1245                         return NT_STATUS_RETRY;
1246                 }
1247         }
1248
1249         req = conn->pending[i];
1250         state = tevent_req_data(req, struct smbXcli_req_state);
1251
1252         if (!oplock_break /* oplock breaks are not signed */
1253             && !smb_signing_check_pdu(conn->smb1.signing,
1254                                       inbuf, state->smb1.seqnum+1)) {
1255                 DEBUG(10, ("cli_check_sign_mac failed\n"));
1256                 return NT_STATUS_ACCESS_DENIED;
1257         }
1258
1259         if (state->smb1.chained_requests != NULL) {
1260                 struct tevent_req **chain = talloc_move(tmp_mem,
1261                                             &state->smb1.chained_requests);
1262                 size_t num_chained = talloc_array_length(chain);
1263
1264                 /*
1265                  * We steal the inbuf to the chain,
1266                  * so that it will stay until all
1267                  * requests of the chain are finished.
1268                  *
1269                  * Each requests in the chain will
1270                  * hold a talloc reference to the chain.
1271                  * This way we do not expose the talloc_reference()
1272                  * behavior to the callers.
1273                  */
1274                 talloc_steal(chain, inbuf);
1275
1276                 for (i=0; i<num_chained; i++) {
1277                         struct tevent_req **ref;
1278
1279                         req = chain[i];
1280                         state = tevent_req_data(req, struct smbXcli_req_state);
1281
1282                         smbXcli_req_unset_pending(req);
1283
1284                         /*
1285                          * as we finish multiple requests here
1286                          * we need to defer the callbacks as
1287                          * they could destroy our current stack state.
1288                          */
1289                         tevent_req_defer_callback(req, state->ev);
1290
1291                         ref = talloc_reference(state, chain);
1292                         if (tevent_req_nomem(ref, req)) {
1293                                 continue;
1294                         }
1295
1296                         state->inbuf = inbuf;
1297                         state->smb1.chain_num = i;
1298                         state->smb1.chain_length = num_chained;
1299
1300                         tevent_req_done(req);
1301                 }
1302                 return NT_STATUS_RETRY;
1303         }
1304
1305         smbXcli_req_unset_pending(req);
1306
1307         state->inbuf = talloc_move(state, &inbuf);
1308         state->smb1.chain_num = 0;
1309         state->smb1.chain_length = 1;
1310
1311         if (talloc_array_length(conn->pending) == 0) {
1312                 tevent_req_done(req);
1313                 return NT_STATUS_OK;
1314         }
1315
1316         tevent_req_defer_callback(req, state->ev);
1317         tevent_req_done(req);
1318         return NT_STATUS_RETRY;
1319 }
1320
1321 NTSTATUS smb1cli_req_recv(struct tevent_req *req,
1322                           TALLOC_CTX *mem_ctx, uint8_t **pinbuf,
1323                           uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
1324                           uint32_t *pnum_bytes, uint8_t **pbytes)
1325 {
1326         struct smbXcli_req_state *state =
1327                 tevent_req_data(req,
1328                 struct smbXcli_req_state);
1329         NTSTATUS status = NT_STATUS_OK;
1330         uint8_t cmd, wct;
1331         uint16_t num_bytes;
1332         size_t wct_ofs, bytes_offset;
1333         int i;
1334
1335         if (tevent_req_is_nterror(req, &status)) {
1336                 return status;
1337         }
1338
1339         if (state->inbuf == NULL) {
1340                 if (min_wct != 0) {
1341                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
1342                 }
1343                 if (pinbuf) {
1344                         *pinbuf = NULL;
1345                 }
1346                 if (pwct) {
1347                         *pwct = 0;
1348                 }
1349                 if (pvwv) {
1350                         *pvwv = NULL;
1351                 }
1352                 if (pnum_bytes) {
1353                         *pnum_bytes = 0;
1354                 }
1355                 if (pbytes) {
1356                         *pbytes = NULL;
1357                 }
1358                 /* This was a request without a reply */
1359                 return NT_STATUS_OK;
1360         }
1361
1362         wct_ofs = NBT_HDR_SIZE + HDR_WCT;
1363         cmd = CVAL(state->inbuf, NBT_HDR_SIZE + HDR_COM);
1364
1365         for (i=0; i<state->smb1.chain_num; i++) {
1366                 if (i < state->smb1.chain_num-1) {
1367                         if (cmd == 0xff) {
1368                                 return NT_STATUS_REQUEST_ABORTED;
1369                         }
1370                         if (!smb1cli_is_andx_req(cmd)) {
1371                                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1372                         }
1373                 }
1374
1375                 if (!smb1cli_have_andx_command(state->inbuf, wct_ofs, cmd)) {
1376                         /*
1377                          * This request was not completed because a previous
1378                          * request in the chain had received an error.
1379                          */
1380                         return NT_STATUS_REQUEST_ABORTED;
1381                 }
1382
1383                 cmd = CVAL(state->inbuf, wct_ofs + 1);
1384                 wct_ofs = SVAL(state->inbuf, wct_ofs + 3);
1385
1386                 /*
1387                  * Skip the all-present length field. No overflow, we've just
1388                  * put a 16-bit value into a size_t.
1389                  */
1390                 wct_ofs += 4;
1391
1392                 if (wct_ofs+2 > talloc_get_size(state->inbuf)) {
1393                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
1394                 }
1395         }
1396
1397         status = smb1cli_pull_raw_error(state->inbuf);
1398
1399         if (!smb1cli_have_andx_command(state->inbuf, wct_ofs, cmd)) {
1400
1401                 if ((cmd == SMBsesssetupX)
1402                     && NT_STATUS_EQUAL(
1403                             status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
1404                         /*
1405                          * NT_STATUS_MORE_PROCESSING_REQUIRED is a
1406                          * valid return code for session setup
1407                          */
1408                         goto no_err;
1409                 }
1410
1411                 if (NT_STATUS_IS_ERR(status)) {
1412                         /*
1413                          * The last command takes the error code. All
1414                          * further commands down the requested chain
1415                          * will get a NT_STATUS_REQUEST_ABORTED.
1416                          */
1417                         return status;
1418                 }
1419         } else {
1420                 /*
1421                  * Only the last request in the chain get the returned
1422                  * status.
1423                  */
1424                 status = NT_STATUS_OK;
1425         }
1426
1427 no_err:
1428
1429         wct = CVAL(state->inbuf, wct_ofs);
1430         bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
1431         num_bytes = SVAL(state->inbuf, bytes_offset);
1432
1433         if (wct < min_wct) {
1434                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1435         }
1436
1437         /*
1438          * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes
1439          * is a 16-bit value. So bytes_offset being size_t should be far from
1440          * wrapping.
1441          */
1442         if ((bytes_offset + 2 > talloc_get_size(state->inbuf))
1443             || (bytes_offset > 0xffff)) {
1444                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
1445         }
1446
1447         if (pwct != NULL) {
1448                 *pwct = wct;
1449         }
1450         if (pvwv != NULL) {
1451                 *pvwv = (uint16_t *)(state->inbuf + wct_ofs + 1);
1452         }
1453         if (pnum_bytes != NULL) {
1454                 *pnum_bytes = num_bytes;
1455         }
1456         if (pbytes != NULL) {
1457                 *pbytes = (uint8_t *)state->inbuf + bytes_offset + 2;
1458         }
1459         if ((mem_ctx != NULL) && (pinbuf != NULL)) {
1460                 if (state->smb1.chain_num == state->smb1.chain_length-1) {
1461                         *pinbuf = talloc_move(mem_ctx, &state->inbuf);
1462                 } else {
1463                         *pinbuf = state->inbuf;
1464                 }
1465         }
1466
1467         return status;
1468 }
1469
1470 size_t smb1cli_req_wct_ofs(struct tevent_req **reqs, int num_reqs)
1471 {
1472         size_t wct_ofs;
1473         int i;
1474
1475         wct_ofs = HDR_WCT;
1476
1477         for (i=0; i<num_reqs; i++) {
1478                 struct smbXcli_req_state *state;
1479                 state = tevent_req_data(reqs[i], struct smbXcli_req_state);
1480                 wct_ofs += smbXcli_iov_len(state->smb1.iov+2,
1481                                            state->smb1.iov_count-2);
1482                 wct_ofs = (wct_ofs + 3) & ~3;
1483         }
1484         return wct_ofs;
1485 }
1486
1487 NTSTATUS smb1cli_req_chain_submit(struct tevent_req **reqs, int num_reqs)
1488 {
1489         struct smbXcli_req_state *first_state =
1490                 tevent_req_data(reqs[0],
1491                 struct smbXcli_req_state);
1492         struct smbXcli_req_state *last_state =
1493                 tevent_req_data(reqs[num_reqs-1],
1494                 struct smbXcli_req_state);
1495         struct smbXcli_req_state *state;
1496         size_t wct_offset;
1497         size_t chain_padding = 0;
1498         int i, iovlen;
1499         struct iovec *iov = NULL;
1500         struct iovec *this_iov;
1501         NTSTATUS status;
1502         size_t nbt_len;
1503
1504         if (num_reqs == 1) {
1505                 return smb1cli_req_writev_submit(reqs[0], first_state,
1506                                                  first_state->smb1.iov,
1507                                                  first_state->smb1.iov_count);
1508         }
1509
1510         iovlen = 0;
1511         for (i=0; i<num_reqs; i++) {
1512                 if (!tevent_req_is_in_progress(reqs[i])) {
1513                         return NT_STATUS_INTERNAL_ERROR;
1514                 }
1515
1516                 state = tevent_req_data(reqs[i], struct smbXcli_req_state);
1517
1518                 if (state->smb1.iov_count < 4) {
1519                         return NT_STATUS_INVALID_PARAMETER_MIX;
1520                 }
1521
1522                 if (i == 0) {
1523                         /*
1524                          * The NBT and SMB header
1525                          */
1526                         iovlen += 2;
1527                 } else {
1528                         /*
1529                          * Chain padding
1530                          */
1531                         iovlen += 1;
1532                 }
1533
1534                 /*
1535                  * words and bytes
1536                  */
1537                 iovlen += state->smb1.iov_count - 2;
1538         }
1539
1540         iov = talloc_zero_array(last_state, struct iovec, iovlen);
1541         if (iov == NULL) {
1542                 return NT_STATUS_NO_MEMORY;
1543         }
1544
1545         first_state->smb1.chained_requests = (struct tevent_req **)talloc_memdup(
1546                 last_state, reqs, sizeof(*reqs) * num_reqs);
1547         if (first_state->smb1.chained_requests == NULL) {
1548                 TALLOC_FREE(iov);
1549                 return NT_STATUS_NO_MEMORY;
1550         }
1551
1552         wct_offset = HDR_WCT;
1553         this_iov = iov;
1554
1555         for (i=0; i<num_reqs; i++) {
1556                 size_t next_padding = 0;
1557                 uint16_t *vwv;
1558
1559                 state = tevent_req_data(reqs[i], struct smbXcli_req_state);
1560
1561                 if (i < num_reqs-1) {
1562                         if (!smb1cli_is_andx_req(CVAL(state->smb1.hdr, HDR_COM))
1563                             || CVAL(state->smb1.hdr, HDR_WCT) < 2) {
1564                                 TALLOC_FREE(iov);
1565                                 TALLOC_FREE(first_state->smb1.chained_requests);
1566                                 return NT_STATUS_INVALID_PARAMETER_MIX;
1567                         }
1568                 }
1569
1570                 wct_offset += smbXcli_iov_len(state->smb1.iov+2,
1571                                               state->smb1.iov_count-2) + 1;
1572                 if ((wct_offset % 4) != 0) {
1573                         next_padding = 4 - (wct_offset % 4);
1574                 }
1575                 wct_offset += next_padding;
1576                 vwv = state->smb1.vwv;
1577
1578                 if (i < num_reqs-1) {
1579                         struct smbXcli_req_state *next_state =
1580                                 tevent_req_data(reqs[i+1],
1581                                 struct smbXcli_req_state);
1582                         SCVAL(vwv+0, 0, CVAL(next_state->smb1.hdr, HDR_COM));
1583                         SCVAL(vwv+0, 1, 0);
1584                         SSVAL(vwv+1, 0, wct_offset);
1585                 } else if (smb1cli_is_andx_req(CVAL(state->smb1.hdr, HDR_COM))) {
1586                         /* properly end the chain */
1587                         SCVAL(vwv+0, 0, 0xff);
1588                         SCVAL(vwv+0, 1, 0xff);
1589                         SSVAL(vwv+1, 0, 0);
1590                 }
1591
1592                 if (i == 0) {
1593                         /*
1594                          * The NBT and SMB header
1595                          */
1596                         this_iov[0] = state->smb1.iov[0];
1597                         this_iov[1] = state->smb1.iov[1];
1598                         this_iov += 2;
1599                 } else {
1600                         /*
1601                          * This one is a bit subtle. We have to add
1602                          * chain_padding bytes between the requests, and we
1603                          * have to also include the wct field of the
1604                          * subsequent requests. We use the subsequent header
1605                          * for the padding, it contains the wct field in its
1606                          * last byte.
1607                          */
1608                         this_iov[0].iov_len = chain_padding+1;
1609                         this_iov[0].iov_base = (void *)&state->smb1.hdr[
1610                                 sizeof(state->smb1.hdr) - this_iov[0].iov_len];
1611                         memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1);
1612                         this_iov += 1;
1613                 }
1614
1615                 /*
1616                  * copy the words and bytes
1617                  */
1618                 memcpy(this_iov, state->smb1.iov+2,
1619                        sizeof(struct iovec) * (state->smb1.iov_count-2));
1620                 this_iov += state->smb1.iov_count - 2;
1621                 chain_padding = next_padding;
1622         }
1623
1624         nbt_len = smbXcli_iov_len(&iov[1], iovlen-1);
1625         if (nbt_len > first_state->conn->smb1.max_xmit) {
1626                 TALLOC_FREE(iov);
1627                 TALLOC_FREE(first_state->smb1.chained_requests);
1628                 return NT_STATUS_INVALID_PARAMETER_MIX;
1629         }
1630
1631         status = smb1cli_req_writev_submit(reqs[0], last_state, iov, iovlen);
1632         if (!NT_STATUS_IS_OK(status)) {
1633                 TALLOC_FREE(iov);
1634                 TALLOC_FREE(first_state->smb1.chained_requests);
1635                 return status;
1636         }
1637
1638         for (i=0; i < (num_reqs - 1); i++) {
1639                 state = tevent_req_data(reqs[i], struct smbXcli_req_state);
1640
1641                 state->smb1.seqnum = last_state->smb1.seqnum;
1642         }
1643
1644         return NT_STATUS_OK;
1645 }
1646
1647 bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn)
1648 {
1649         return ((tevent_queue_length(conn->outgoing) != 0)
1650                 || (talloc_array_length(conn->pending) != 0));
1651 }
1652
1653 struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx,
1654                                       struct tevent_context *ev,
1655                                       struct smbXcli_conn *conn,
1656                                       uint16_t cmd,
1657                                       uint32_t additional_flags,
1658                                       uint32_t clear_flags,
1659                                       uint32_t timeout_msec,
1660                                       uint32_t pid,
1661                                       uint32_t tid,
1662                                       uint64_t uid,
1663                                       const uint8_t *fixed,
1664                                       uint16_t fixed_len,
1665                                       const uint8_t *dyn,
1666                                       uint32_t dyn_len)
1667 {
1668         struct tevent_req *req;
1669         struct smbXcli_req_state *state;
1670         uint32_t flags = 0;
1671
1672         req = tevent_req_create(mem_ctx, &state,
1673                                 struct smbXcli_req_state);
1674         if (req == NULL) {
1675                 return NULL;
1676         }
1677
1678         state->ev = ev;
1679         state->conn = conn;
1680
1681         state->smb2.recv_iov = talloc_zero_array(state, struct iovec, 3);
1682         if (state->smb2.recv_iov == NULL) {
1683                 TALLOC_FREE(req);
1684                 return NULL;
1685         }
1686
1687         flags |= additional_flags;
1688         flags &= ~clear_flags;
1689
1690         state->smb2.fixed = fixed;
1691         state->smb2.fixed_len = fixed_len;
1692         state->smb2.dyn = dyn;
1693         state->smb2.dyn_len = dyn_len;
1694
1695         SIVAL(state->smb2.hdr, SMB2_HDR_PROTOCOL_ID,    SMB2_MAGIC);
1696         SSVAL(state->smb2.hdr, SMB2_HDR_LENGTH,         SMB2_HDR_BODY);
1697         SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT_CHARGE,  1);
1698         SIVAL(state->smb2.hdr, SMB2_HDR_STATUS,         NT_STATUS_V(NT_STATUS_OK));
1699         SSVAL(state->smb2.hdr, SMB2_HDR_OPCODE,         cmd);
1700         SSVAL(state->smb2.hdr, SMB2_HDR_CREDIT,         31);
1701         SIVAL(state->smb2.hdr, SMB2_HDR_FLAGS,          flags);
1702         SIVAL(state->smb2.hdr, SMB2_HDR_PID,            pid);
1703         SIVAL(state->smb2.hdr, SMB2_HDR_TID,            tid);
1704         SBVAL(state->smb2.hdr, SMB2_HDR_SESSION_ID,     uid);
1705
1706         switch (cmd) {
1707         case SMB2_OP_CANCEL:
1708                 state->one_way = true;
1709                 break;
1710         case SMB2_OP_BREAK:
1711                 /*
1712                  * If this is a dummy request, it will have
1713                  * UINT64_MAX as message id.
1714                  * If we send on break acknowledgement,
1715                  * this gets overwritten later.
1716                  */
1717                 SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, UINT64_MAX);
1718                 break;
1719         }
1720
1721         if (timeout_msec > 0) {
1722                 struct timeval endtime;
1723
1724                 endtime = timeval_current_ofs_msec(timeout_msec);
1725                 if (!tevent_req_set_endtime(req, ev, endtime)) {
1726                         return req;
1727                 }
1728         }
1729
1730         return req;
1731 }
1732
1733 static void smb2cli_writev_done(struct tevent_req *subreq);
1734 static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
1735                                                TALLOC_CTX *tmp_mem,
1736                                                uint8_t *inbuf);
1737
1738 NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs,
1739                                      int num_reqs)
1740 {
1741         struct smbXcli_req_state *state;
1742         struct tevent_req *subreq;
1743         struct iovec *iov;
1744         int i, num_iov, nbt_len;
1745
1746         /*
1747          * 1 for the nbt length
1748          * per request: HDR, fixed, dyn, padding
1749          * -1 because the last one does not need padding
1750          */
1751
1752         iov = talloc_array(reqs[0], struct iovec, 1 + 4*num_reqs - 1);
1753         if (iov == NULL) {
1754                 return NT_STATUS_NO_MEMORY;
1755         }
1756
1757         num_iov = 1;
1758         nbt_len = 0;
1759
1760         for (i=0; i<num_reqs; i++) {
1761                 size_t reqlen;
1762                 bool ret;
1763                 uint64_t mid;
1764
1765                 if (!tevent_req_is_in_progress(reqs[i])) {
1766                         return NT_STATUS_INTERNAL_ERROR;
1767                 }
1768
1769                 state = tevent_req_data(reqs[i], struct smbXcli_req_state);
1770
1771                 if (!smbXcli_conn_is_connected(state->conn)) {
1772                         return NT_STATUS_CONNECTION_DISCONNECTED;
1773                 }
1774
1775                 if ((state->conn->protocol != PROTOCOL_NONE) &&
1776                     (state->conn->protocol < PROTOCOL_SMB2_02)) {
1777                         return NT_STATUS_REVISION_MISMATCH;
1778                 }
1779
1780                 if (state->conn->smb2.mid == UINT64_MAX) {
1781                         return NT_STATUS_CONNECTION_ABORTED;
1782                 }
1783
1784                 mid = state->conn->smb2.mid;
1785                 state->conn->smb2.mid += 1;
1786
1787                 SBVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID, mid);
1788
1789                 iov[num_iov].iov_base = state->smb2.hdr;
1790                 iov[num_iov].iov_len  = sizeof(state->smb2.hdr);
1791                 num_iov += 1;
1792
1793                 iov[num_iov].iov_base = discard_const(state->smb2.fixed);
1794                 iov[num_iov].iov_len  = state->smb2.fixed_len;
1795                 num_iov += 1;
1796
1797                 if (state->smb2.dyn != NULL) {
1798                         iov[num_iov].iov_base = discard_const(state->smb2.dyn);
1799                         iov[num_iov].iov_len  = state->smb2.dyn_len;
1800                         num_iov += 1;
1801                 }
1802
1803                 reqlen  = sizeof(state->smb2.hdr);
1804                 reqlen += state->smb2.fixed_len;
1805                 reqlen += state->smb2.dyn_len;
1806
1807                 if (i < num_reqs-1) {
1808                         if ((reqlen % 8) > 0) {
1809                                 uint8_t pad = 8 - (reqlen % 8);
1810                                 iov[num_iov].iov_base = state->smb2.pad;
1811                                 iov[num_iov].iov_len = pad;
1812                                 num_iov += 1;
1813                                 reqlen += pad;
1814                         }
1815                         SIVAL(state->smb2.hdr, SMB2_HDR_NEXT_COMMAND, reqlen);
1816                 }
1817                 nbt_len += reqlen;
1818
1819                 ret = smbXcli_req_set_pending(reqs[i]);
1820                 if (!ret) {
1821                         return NT_STATUS_NO_MEMORY;
1822                 }
1823         }
1824
1825         /*
1826          * TODO: Do signing here
1827          */
1828
1829         state = tevent_req_data(reqs[0], struct smbXcli_req_state);
1830         _smb_setlen_tcp(state->length_hdr, nbt_len);
1831         iov[0].iov_base = state->length_hdr;
1832         iov[0].iov_len  = sizeof(state->length_hdr);
1833
1834         if (state->conn->dispatch_incoming == NULL) {
1835                 state->conn->dispatch_incoming = smb2cli_conn_dispatch_incoming;
1836         }
1837
1838         subreq = writev_send(state, state->ev, state->conn->outgoing,
1839                              state->conn->fd, false, iov, num_iov);
1840         if (subreq == NULL) {
1841                 return NT_STATUS_NO_MEMORY;
1842         }
1843         tevent_req_set_callback(subreq, smb2cli_writev_done, reqs[0]);
1844         return NT_STATUS_OK;
1845 }
1846
1847 struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx,
1848                                     struct tevent_context *ev,
1849                                     struct smbXcli_conn *conn,
1850                                     uint16_t cmd,
1851                                     uint32_t additional_flags,
1852                                     uint32_t clear_flags,
1853                                     uint32_t timeout_msec,
1854                                     uint32_t pid,
1855                                     uint32_t tid,
1856                                     uint64_t uid,
1857                                     const uint8_t *fixed,
1858                                     uint16_t fixed_len,
1859                                     const uint8_t *dyn,
1860                                     uint32_t dyn_len)
1861 {
1862         struct tevent_req *req;
1863         NTSTATUS status;
1864
1865         req = smb2cli_req_create(mem_ctx, ev, conn, cmd,
1866                                  additional_flags, clear_flags,
1867                                  timeout_msec,
1868                                  pid, tid, uid,
1869                                  fixed, fixed_len, dyn, dyn_len);
1870         if (req == NULL) {
1871                 return NULL;
1872         }
1873         if (!tevent_req_is_in_progress(req)) {
1874                 return tevent_req_post(req, ev);
1875         }
1876         status = smb2cli_req_compound_submit(&req, 1);
1877         if (tevent_req_nterror(req, status)) {
1878                 return tevent_req_post(req, ev);
1879         }
1880         return req;
1881 }
1882
1883 static void smb2cli_writev_done(struct tevent_req *subreq)
1884 {
1885         struct tevent_req *req =
1886                 tevent_req_callback_data(subreq,
1887                 struct tevent_req);
1888         struct smbXcli_req_state *state =
1889                 tevent_req_data(req,
1890                 struct smbXcli_req_state);
1891         ssize_t nwritten;
1892         int err;
1893
1894         nwritten = writev_recv(subreq, &err);
1895         TALLOC_FREE(subreq);
1896         if (nwritten == -1) {
1897                 /* here, we need to notify all pending requests */
1898                 NTSTATUS status = map_nt_error_from_unix_common(err);
1899                 smbXcli_conn_disconnect(state->conn, status);
1900                 return;
1901         }
1902 }
1903
1904 static NTSTATUS smb2cli_inbuf_parse_compound(uint8_t *buf, TALLOC_CTX *mem_ctx,
1905                                              struct iovec **piov, int *pnum_iov)
1906 {
1907         struct iovec *iov;
1908         int num_iov;
1909         size_t buflen;
1910         size_t taken;
1911         uint8_t *first_hdr;
1912
1913         num_iov = 0;
1914
1915         iov = talloc_array(mem_ctx, struct iovec, num_iov);
1916         if (iov == NULL) {
1917                 return NT_STATUS_NO_MEMORY;
1918         }
1919
1920         buflen = smb_len_tcp(buf);
1921         taken = 0;
1922         first_hdr = buf + NBT_HDR_SIZE;
1923
1924         while (taken < buflen) {
1925                 size_t len = buflen - taken;
1926                 uint8_t *hdr = first_hdr + taken;
1927                 struct iovec *cur;
1928                 size_t full_size;
1929                 size_t next_command_ofs;
1930                 uint16_t body_size;
1931                 struct iovec *iov_tmp;
1932
1933                 /*
1934                  * We need the header plus the body length field
1935                  */
1936
1937                 if (len < SMB2_HDR_BODY + 2) {
1938                         DEBUG(10, ("%d bytes left, expected at least %d\n",
1939                                    (int)len, SMB2_HDR_BODY));
1940                         goto inval;
1941                 }
1942                 if (IVAL(hdr, 0) != SMB2_MAGIC) {
1943                         DEBUG(10, ("Got non-SMB2 PDU: %x\n",
1944                                    IVAL(hdr, 0)));
1945                         goto inval;
1946                 }
1947                 if (SVAL(hdr, 4) != SMB2_HDR_BODY) {
1948                         DEBUG(10, ("Got HDR len %d, expected %d\n",
1949                                    SVAL(hdr, 4), SMB2_HDR_BODY));
1950                         goto inval;
1951                 }
1952
1953                 full_size = len;
1954                 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
1955                 body_size = SVAL(hdr, SMB2_HDR_BODY);
1956
1957                 if (next_command_ofs != 0) {
1958                         if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
1959                                 goto inval;
1960                         }
1961                         if (next_command_ofs > full_size) {
1962                                 goto inval;
1963                         }
1964                         full_size = next_command_ofs;
1965                 }
1966                 if (body_size < 2) {
1967                         goto inval;
1968                 }
1969                 body_size &= 0xfffe;
1970
1971                 if (body_size > (full_size - SMB2_HDR_BODY)) {
1972                         goto inval;
1973                 }
1974
1975                 iov_tmp = talloc_realloc(mem_ctx, iov, struct iovec,
1976                                          num_iov + 3);
1977                 if (iov_tmp == NULL) {
1978                         TALLOC_FREE(iov);
1979                         return NT_STATUS_NO_MEMORY;
1980                 }
1981                 iov = iov_tmp;
1982                 cur = &iov[num_iov];
1983                 num_iov += 3;
1984
1985                 cur[0].iov_base = hdr;
1986                 cur[0].iov_len  = SMB2_HDR_BODY;
1987                 cur[1].iov_base = hdr + SMB2_HDR_BODY;
1988                 cur[1].iov_len  = body_size;
1989                 cur[2].iov_base = hdr + SMB2_HDR_BODY + body_size;
1990                 cur[2].iov_len  = full_size - (SMB2_HDR_BODY + body_size);
1991
1992                 taken += full_size;
1993         }
1994
1995         *piov = iov;
1996         *pnum_iov = num_iov;
1997         return NT_STATUS_OK;
1998
1999 inval:
2000         TALLOC_FREE(iov);
2001         return NT_STATUS_INVALID_NETWORK_RESPONSE;
2002 }
2003
2004 static struct tevent_req *smb2cli_conn_find_pending(struct smbXcli_conn *conn,
2005                                                     uint64_t mid)
2006 {
2007         size_t num_pending = talloc_array_length(conn->pending);
2008         size_t i;
2009
2010         for (i=0; i<num_pending; i++) {
2011                 struct tevent_req *req = conn->pending[i];
2012                 struct smbXcli_req_state *state =
2013                         tevent_req_data(req,
2014                         struct smbXcli_req_state);
2015
2016                 if (mid == BVAL(state->smb2.hdr, SMB2_HDR_MESSAGE_ID)) {
2017                         return req;
2018                 }
2019         }
2020         return NULL;
2021 }
2022
2023 static NTSTATUS smb2cli_conn_dispatch_incoming(struct smbXcli_conn *conn,
2024                                                TALLOC_CTX *tmp_mem,
2025                                                uint8_t *inbuf)
2026 {
2027         struct tevent_req *req;
2028         struct smbXcli_req_state *state = NULL;
2029         struct iovec *iov;
2030         int i, num_iov;
2031         NTSTATUS status;
2032         bool defer = true;
2033
2034         status = smb2cli_inbuf_parse_compound(inbuf, tmp_mem,
2035                                               &iov, &num_iov);
2036         if (!NT_STATUS_IS_OK(status)) {
2037                 return status;
2038         }
2039
2040         for (i=0; i<num_iov; i+=3) {
2041                 uint8_t *inbuf_ref = NULL;
2042                 struct iovec *cur = &iov[i];
2043                 uint8_t *inhdr = (uint8_t *)cur[0].iov_base;
2044                 uint16_t opcode = SVAL(inhdr, SMB2_HDR_OPCODE);
2045                 uint32_t flags = IVAL(inhdr, SMB2_HDR_FLAGS);
2046                 uint64_t mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
2047                 uint16_t req_opcode;
2048
2049                 req = smb2cli_conn_find_pending(conn, mid);
2050                 if (req == NULL) {
2051                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
2052                 }
2053                 state = tevent_req_data(req, struct smbXcli_req_state);
2054
2055                 req_opcode = SVAL(state->smb2.hdr, SMB2_HDR_OPCODE);
2056                 if (opcode != req_opcode) {
2057                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
2058                 }
2059
2060                 if (!(flags & SMB2_HDR_FLAG_REDIRECT)) {
2061                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
2062                 }
2063
2064                 status = NT_STATUS(IVAL(inhdr, SMB2_HDR_STATUS));
2065                 if ((flags & SMB2_HDR_FLAG_ASYNC) &&
2066                     NT_STATUS_EQUAL(status, STATUS_PENDING)) {
2067                         uint32_t req_flags = IVAL(state->smb2.hdr, SMB2_HDR_FLAGS);
2068                         uint64_t async_id = BVAL(inhdr, SMB2_HDR_ASYNC_ID);
2069
2070                         req_flags |= SMB2_HDR_FLAG_ASYNC;
2071                         SBVAL(state->smb2.hdr, SMB2_HDR_FLAGS, req_flags);
2072                         SBVAL(state->smb2.hdr, SMB2_HDR_ASYNC_ID, async_id);
2073                         continue;
2074                 }
2075
2076                 smbXcli_req_unset_pending(req);
2077
2078                 /*
2079                  * There might be more than one response
2080                  * we need to defer the notifications
2081                  */
2082                 if ((num_iov == 4) && (talloc_array_length(conn->pending) == 0)) {
2083                         defer = false;
2084                 }
2085
2086                 if (defer) {
2087                         tevent_req_defer_callback(req, state->ev);
2088                 }
2089
2090                 /*
2091                  * Note: here we use talloc_reference() in a way
2092                  *       that does not expose it to the caller.
2093                  */
2094                 inbuf_ref = talloc_reference(state->smb2.recv_iov, inbuf);
2095                 if (tevent_req_nomem(inbuf_ref, req)) {
2096                         continue;
2097                 }
2098
2099                 /* copy the related buffers */
2100                 state->smb2.recv_iov[0] = cur[0];
2101                 state->smb2.recv_iov[1] = cur[1];
2102                 state->smb2.recv_iov[2] = cur[2];
2103
2104                 tevent_req_done(req);
2105         }
2106
2107         if (defer) {
2108                 return NT_STATUS_RETRY;
2109         }
2110
2111         return NT_STATUS_OK;
2112 }
2113
2114 NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
2115                           struct iovec **piov,
2116                           const struct smb2cli_req_expected_response *expected,
2117                           size_t num_expected)
2118 {
2119         struct smbXcli_req_state *state =
2120                 tevent_req_data(req,
2121                 struct smbXcli_req_state);
2122         NTSTATUS status;
2123         size_t body_size;
2124         bool found_status = false;
2125         bool found_size = false;
2126         size_t i;
2127
2128         if (piov != NULL) {
2129                 *piov = NULL;
2130         }
2131
2132         if (tevent_req_is_nterror(req, &status)) {
2133                 for (i=0; i < num_expected; i++) {
2134                         if (NT_STATUS_EQUAL(status, expected[i].status)) {
2135                                 found_status = true;
2136                                 break;
2137                         }
2138                 }
2139
2140                 if (found_status) {
2141                         return NT_STATUS_UNEXPECTED_NETWORK_ERROR;
2142                 }
2143
2144                 return status;
2145         }
2146
2147         if (num_expected == 0) {
2148                 found_status = true;
2149                 found_size = true;
2150         }
2151
2152         status = NT_STATUS(IVAL(state->smb2.recv_iov[0].iov_base, SMB2_HDR_STATUS));
2153         body_size = SVAL(state->smb2.recv_iov[1].iov_base, 0);
2154
2155         for (i=0; i < num_expected; i++) {
2156                 if (!NT_STATUS_EQUAL(status, expected[i].status)) {
2157                         continue;
2158                 }
2159
2160                 found_status = true;
2161                 if (expected[i].body_size == 0) {
2162                         found_size = true;
2163                         break;
2164                 }
2165
2166                 if (expected[i].body_size == body_size) {
2167                         found_size = true;
2168                         break;
2169                 }
2170         }
2171
2172         if (!found_status) {
2173                 return status;
2174         }
2175
2176         if (!found_size) {
2177                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
2178         }
2179
2180         if (piov != NULL) {
2181                 *piov = talloc_move(mem_ctx, &state->smb2.recv_iov);
2182         }
2183
2184         return status;
2185 }