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