s3:libsmb: let cli_smb_req_mid() return the mid set by cli_smb_req_set_mid()
[metze/samba/wip.git] / source3 / libsmb / async_smb.c
1 /*
2    Unix SMB/CIFS implementation.
3    Infrastructure for async SMB client requests
4    Copyright (C) Volker Lendecke 2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "libsmb/libsmb.h"
22 #include "../lib/async_req/async_sock.h"
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "../lib/util/tevent_unix.h"
25 #include "async_smb.h"
26 #include "smb_crypt.h"
27 #include "libsmb/nmblib.h"
28 #include "read_smb.h"
29
30 static NTSTATUS cli_pull_raw_error(const uint8_t *buf)
31 {
32         uint32_t flags2 = SVAL(buf, smb_flg2);
33
34         if (flags2 & FLAGS2_32_BIT_ERROR_CODES) {
35                 return NT_STATUS(IVAL(buf, smb_rcls));
36         }
37
38         return NT_STATUS_DOS(CVAL(buf, smb_rcls), SVAL(buf,smb_err));
39 }
40
41 /**
42  * Figure out if there is an andx command behind the current one
43  * @param[in] buf       The smb buffer to look at
44  * @param[in] ofs       The offset to the wct field that is followed by the cmd
45  * @retval Is there a command following?
46  */
47
48 static bool have_andx_command(const char *buf, uint16_t ofs)
49 {
50         uint8_t wct;
51         size_t buflen = talloc_get_size(buf);
52
53         if ((ofs == buflen-1) || (ofs == buflen)) {
54                 return false;
55         }
56
57         wct = CVAL(buf, ofs);
58         if (wct < 2) {
59                 /*
60                  * Not enough space for the command and a following pointer
61                  */
62                 return false;
63         }
64         return (CVAL(buf, ofs+1) != 0xff);
65 }
66
67 #define MAX_SMB_IOV 5
68
69 struct cli_smb_state {
70         struct tevent_context *ev;
71         struct cli_state *cli;
72         uint8_t header[smb_wct+1]; /* Space for the header including the wct */
73
74         /*
75          * For normal requests, cli_smb_req_send chooses a mid. Secondary
76          * trans requests need to use the mid of the primary request, so we
77          * need a place to store it. Assume it's set if != 0.
78          */
79         uint16_t mid;
80
81         uint16_t *vwv;
82         uint8_t bytecount_buf[2];
83
84         struct iovec iov[MAX_SMB_IOV+3];
85         int iov_count;
86
87         uint8_t *inbuf;
88         uint32_t seqnum;
89         int chain_num;
90         int chain_length;
91         struct tevent_req **chained_requests;
92
93         bool one_way;
94 };
95
96 static uint16_t cli_alloc_mid(struct cli_state *cli)
97 {
98         int num_pending = talloc_array_length(cli->conn.pending);
99         uint16_t result;
100
101         while (true) {
102                 int i;
103
104                 result = cli->smb1.mid++;
105                 if ((result == 0) || (result == 0xffff)) {
106                         continue;
107                 }
108
109                 for (i=0; i<num_pending; i++) {
110                         if (result == cli_smb_req_mid(cli->conn.pending[i])) {
111                                 break;
112                         }
113                 }
114
115                 if (i == num_pending) {
116                         return result;
117                 }
118         }
119 }
120
121 void cli_smb_req_unset_pending(struct tevent_req *req)
122 {
123         struct cli_smb_state *state = tevent_req_data(
124                 req, struct cli_smb_state);
125         struct cli_state *cli = state->cli;
126         int num_pending = talloc_array_length(cli->conn.pending);
127         int i;
128
129         if (state->mid != 0) {
130                 /*
131                  * This is a [nt]trans[2] request which waits
132                  * for more than one reply.
133                  */
134                 return;
135         }
136
137         talloc_set_destructor(req, NULL);
138
139         if (num_pending == 1) {
140                 /*
141                  * The pending read_smb tevent_req is a child of
142                  * cli->pending. So if nothing is pending anymore, we need to
143                  * delete the socket read fde.
144                  */
145                 TALLOC_FREE(cli->conn.pending);
146                 cli->conn.read_smb_req = NULL;
147                 return;
148         }
149
150         for (i=0; i<num_pending; i++) {
151                 if (req == cli->conn.pending[i]) {
152                         break;
153                 }
154         }
155         if (i == num_pending) {
156                 /*
157                  * Something's seriously broken. Just returning here is the
158                  * right thing nevertheless, the point of this routine is to
159                  * remove ourselves from cli->conn.pending.
160                  */
161                 return;
162         }
163
164         /*
165          * Remove ourselves from the cli->conn.pending array
166          */
167         for (; i < (num_pending - 1); i++) {
168                 cli->conn.pending[i] = cli->conn.pending[i+1];
169         }
170
171         /*
172          * No NULL check here, we're shrinking by sizeof(void *), and
173          * talloc_realloc just adjusts the size for this.
174          */
175         cli->conn.pending = talloc_realloc(NULL, cli->conn.pending,
176                                            struct tevent_req *,
177                                            num_pending - 1);
178         return;
179 }
180
181 static int cli_smb_req_destructor(struct tevent_req *req)
182 {
183         struct cli_smb_state *state = tevent_req_data(
184                 req, struct cli_smb_state);
185         /*
186          * Make sure we really remove it from
187          * the pending array on destruction.
188          */
189         state->mid = 0;
190         cli_smb_req_unset_pending(req);
191         return 0;
192 }
193
194 static bool cli_state_receive_next(struct cli_state *cli);
195 static void cli_state_notify_pending(struct cli_state *cli, NTSTATUS status);
196
197 bool cli_smb_req_set_pending(struct tevent_req *req)
198 {
199         struct cli_smb_state *state = tevent_req_data(
200                 req, struct cli_smb_state);
201         struct cli_state *cli;
202         struct tevent_req **pending;
203         int num_pending;
204
205         cli = state->cli;
206         num_pending = talloc_array_length(cli->conn.pending);
207
208         pending = talloc_realloc(cli, cli->conn.pending, struct tevent_req *,
209                                  num_pending+1);
210         if (pending == NULL) {
211                 return false;
212         }
213         pending[num_pending] = req;
214         cli->conn.pending = pending;
215         talloc_set_destructor(req, cli_smb_req_destructor);
216
217         if (!cli_state_receive_next(cli)) {
218                 /*
219                  * the caller should notify the current request
220                  *
221                  * And all other pending requests get notified
222                  * by cli_state_notify_pending().
223                  */
224                 cli_smb_req_unset_pending(req);
225                 cli_state_notify_pending(cli, NT_STATUS_NO_MEMORY);
226                 return false;
227         }
228
229         return true;
230 }
231
232 static void cli_smb_received(struct tevent_req *subreq);
233 static NTSTATUS cli_state_dispatch_smb1(struct cli_state *cli,
234                                         TALLOC_CTX *frame,
235                                         uint8_t *inbuf);
236
237 static bool cli_state_receive_next(struct cli_state *cli)
238 {
239         size_t num_pending = talloc_array_length(cli->conn.pending);
240         struct tevent_req *req;
241         struct cli_smb_state *state;
242
243         if (cli->conn.read_smb_req != NULL) {
244                 return true;
245         }
246
247         if (num_pending == 0) {
248                 return true;
249         }
250
251         req = cli->conn.pending[0];
252         state = tevent_req_data(req, struct cli_smb_state);
253
254         cli->conn.dispatch_incoming = cli_state_dispatch_smb1;
255
256         /*
257          * We're the first ones, add the read_smb request that waits for the
258          * answer from the server
259          */
260         cli->conn.read_smb_req = read_smb_send(cli->conn.pending, state->ev,
261                                                cli->conn.fd);
262         if (cli->conn.read_smb_req == NULL) {
263                 return false;
264         }
265         tevent_req_set_callback(cli->conn.read_smb_req, cli_smb_received, cli);
266         return true;
267 }
268
269 static void cli_state_notify_pending(struct cli_state *cli, NTSTATUS status)
270 {
271         cli_state_disconnect(cli);
272
273         /*
274          * Cancel all pending requests. We do not do a for-loop walking
275          * cli->conn.pending because that array changes in
276          * cli_smb_req_destructor().
277          */
278         while (talloc_array_length(cli->conn.pending) > 0) {
279                 struct tevent_req *req;
280                 struct cli_smb_state *state;
281
282                 req = cli->conn.pending[0];
283                 state = tevent_req_data(req, struct cli_smb_state);
284
285                 cli_smb_req_unset_pending(req);
286
287                 /*
288                  * we need to defer the callback, because we may notify more
289                  * then one caller.
290                  */
291                 tevent_req_defer_callback(req, state->ev);
292                 tevent_req_nterror(req, status);
293         }
294 }
295
296 /*
297  * Fetch a smb request's mid. Only valid after the request has been sent by
298  * cli_smb_req_send().
299  */
300 uint16_t cli_smb_req_mid(struct tevent_req *req)
301 {
302         struct cli_smb_state *state = tevent_req_data(
303                 req, struct cli_smb_state);
304
305         if (state->mid != 0) {
306                 return state->mid;
307         }
308
309         return SVAL(state->header, smb_mid);
310 }
311
312 void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid)
313 {
314         struct cli_smb_state *state = tevent_req_data(
315                 req, struct cli_smb_state);
316         state->mid = mid;
317 }
318
319 uint32_t cli_smb_req_seqnum(struct tevent_req *req)
320 {
321         struct cli_smb_state *state = tevent_req_data(
322                 req, struct cli_smb_state);
323         return state->seqnum;
324 }
325
326 void cli_smb_req_set_seqnum(struct tevent_req *req, uint32_t seqnum)
327 {
328         struct cli_smb_state *state = tevent_req_data(
329                 req, struct cli_smb_state);
330         state->seqnum = seqnum;
331 }
332
333 static size_t iov_len(const struct iovec *iov, int count)
334 {
335         size_t result = 0;
336         int i;
337         for (i=0; i<count; i++) {
338                 result += iov[i].iov_len;
339         }
340         return result;
341 }
342
343 static uint8_t *iov_concat(TALLOC_CTX *mem_ctx, const struct iovec *iov,
344                            int count)
345 {
346         size_t len = iov_len(iov, count);
347         size_t copied;
348         uint8_t *buf;
349         int i;
350
351         buf = talloc_array(mem_ctx, uint8_t, len);
352         if (buf == NULL) {
353                 return NULL;
354         }
355         copied = 0;
356         for (i=0; i<count; i++) {
357                 memcpy(buf+copied, iov[i].iov_base, iov[i].iov_len);
358                 copied += iov[i].iov_len;
359         }
360         return buf;
361 }
362
363 struct tevent_req *cli_smb_req_create(TALLOC_CTX *mem_ctx,
364                                       struct event_context *ev,
365                                       struct cli_state *cli,
366                                       uint8_t smb_command,
367                                       uint8_t additional_flags,
368                                       uint8_t wct, uint16_t *vwv,
369                                       int iov_count,
370                                       struct iovec *bytes_iov)
371 {
372         struct tevent_req *result;
373         struct cli_smb_state *state;
374         struct timeval endtime;
375
376         if (iov_count > MAX_SMB_IOV) {
377                 /*
378                  * Should not happen :-)
379                  */
380                 return NULL;
381         }
382
383         result = tevent_req_create(mem_ctx, &state, struct cli_smb_state);
384         if (result == NULL) {
385                 return NULL;
386         }
387         state->ev = ev;
388         state->cli = cli;
389         state->mid = 0;         /* Set to auto-choose in cli_smb_req_send */
390         state->chain_num = 0;
391         state->chained_requests = NULL;
392
393         cli_setup_packet_buf(cli, (char *)state->header);
394         SCVAL(state->header, smb_com, smb_command);
395         SSVAL(state->header, smb_tid, cli->smb1.tid);
396         SCVAL(state->header, smb_wct, wct);
397
398         state->vwv = vwv;
399
400         SSVAL(state->bytecount_buf, 0, iov_len(bytes_iov, iov_count));
401
402         state->iov[0].iov_base = (void *)state->header;
403         state->iov[0].iov_len  = sizeof(state->header);
404         state->iov[1].iov_base = (void *)state->vwv;
405         state->iov[1].iov_len  = wct * sizeof(uint16_t);
406         state->iov[2].iov_base = (void *)state->bytecount_buf;
407         state->iov[2].iov_len  = sizeof(uint16_t);
408
409         if (iov_count != 0) {
410                 memcpy(&state->iov[3], bytes_iov,
411                        iov_count * sizeof(*bytes_iov));
412         }
413         state->iov_count = iov_count + 3;
414
415         if (cli->timeout) {
416                 endtime = timeval_current_ofs_msec(cli->timeout);
417                 if (!tevent_req_set_endtime(result, ev, endtime)) {
418                         tevent_req_oom(result);
419                 }
420         }
421
422         switch (smb_command) {
423         case SMBtranss:
424         case SMBtranss2:
425         case SMBnttranss:
426         case SMBntcancel:
427                 state->one_way = true;
428                 break;
429         case SMBlockingX:
430                 if ((wct == 8) &&
431                     (CVAL(vwv+3, 0) == LOCKING_ANDX_OPLOCK_RELEASE)) {
432                         state->one_way = true;
433                 }
434                 break;
435         }
436
437         return result;
438 }
439
440 static NTSTATUS cli_signv(struct cli_state *cli, struct iovec *iov, int count,
441                           uint32_t *seqnum)
442 {
443         uint8_t *buf;
444
445         /*
446          * Obvious optimization: Make cli_calculate_sign_mac work with struct
447          * iovec directly. MD5Update would do that just fine.
448          */
449
450         if ((count <= 0) || (iov[0].iov_len < smb_wct)) {
451                 return NT_STATUS_INVALID_PARAMETER;
452         }
453
454         buf = iov_concat(talloc_tos(), iov, count);
455         if (buf == NULL) {
456                 return NT_STATUS_NO_MEMORY;
457         }
458
459         cli_calculate_sign_mac(cli, (char *)buf, seqnum);
460         memcpy(iov[0].iov_base, buf, iov[0].iov_len);
461
462         TALLOC_FREE(buf);
463         return NT_STATUS_OK;
464 }
465
466 static void cli_smb_sent(struct tevent_req *subreq);
467
468 static NTSTATUS cli_smb_req_iov_send(struct tevent_req *req,
469                                      struct cli_smb_state *state,
470                                      struct iovec *iov, int iov_count)
471 {
472         struct tevent_req *subreq;
473         NTSTATUS status;
474
475         if (!cli_state_is_connected(state->cli)) {
476                 return NT_STATUS_CONNECTION_INVALID;
477         }
478
479         if (iov[0].iov_len < smb_wct) {
480                 return NT_STATUS_INVALID_PARAMETER;
481         }
482
483         if (state->mid != 0) {
484                 SSVAL(iov[0].iov_base, smb_mid, state->mid);
485         } else {
486                 uint16_t mid = cli_alloc_mid(state->cli);
487                 SSVAL(iov[0].iov_base, smb_mid, mid);
488         }
489
490         smb_setlen((char *)iov[0].iov_base, iov_len(iov, iov_count) - 4);
491
492         status = cli_signv(state->cli, iov, iov_count, &state->seqnum);
493
494         if (!NT_STATUS_IS_OK(status)) {
495                 return status;
496         }
497
498         if (cli_encryption_on(state->cli)) {
499                 char *buf, *enc_buf;
500
501                 buf = (char *)iov_concat(talloc_tos(), iov, iov_count);
502                 if (buf == NULL) {
503                         return NT_STATUS_NO_MEMORY;
504                 }
505                 status = common_encrypt_buffer(state->cli->trans_enc_state,
506                                                (char *)buf, &enc_buf);
507                 TALLOC_FREE(buf);
508                 if (!NT_STATUS_IS_OK(status)) {
509                         DEBUG(0, ("Error in encrypting client message: %s\n",
510                                   nt_errstr(status)));
511                         return status;
512                 }
513                 buf = (char *)talloc_memdup(state, enc_buf,
514                                             smb_len(enc_buf)+4);
515                 SAFE_FREE(enc_buf);
516                 if (buf == NULL) {
517                         return NT_STATUS_NO_MEMORY;
518                 }
519                 iov[0].iov_base = (void *)buf;
520                 iov[0].iov_len = talloc_get_size(buf);
521                 iov_count = 1;
522         }
523         subreq = writev_send(state, state->ev, state->cli->conn.outgoing,
524                              state->cli->conn.fd, false, iov, iov_count);
525         if (subreq == NULL) {
526                 return NT_STATUS_NO_MEMORY;
527         }
528         tevent_req_set_callback(subreq, cli_smb_sent, req);
529         return NT_STATUS_OK;
530 }
531
532 NTSTATUS cli_smb_req_send(struct tevent_req *req)
533 {
534         struct cli_smb_state *state = tevent_req_data(
535                 req, struct cli_smb_state);
536
537         return cli_smb_req_iov_send(req, state, state->iov, state->iov_count);
538 }
539
540 struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx,
541                                 struct event_context *ev,
542                                 struct cli_state *cli,
543                                 uint8_t smb_command,
544                                 uint8_t additional_flags,
545                                 uint8_t wct, uint16_t *vwv,
546                                 uint32_t num_bytes,
547                                 const uint8_t *bytes)
548 {
549         struct tevent_req *req;
550         struct iovec iov;
551         NTSTATUS status;
552
553         iov.iov_base = discard_const_p(void, bytes);
554         iov.iov_len = num_bytes;
555
556         req = cli_smb_req_create(mem_ctx, ev, cli, smb_command,
557                                  additional_flags, wct, vwv, 1, &iov);
558         if (req == NULL) {
559                 return NULL;
560         }
561
562         status = cli_smb_req_send(req);
563         if (!NT_STATUS_IS_OK(status)) {
564                 tevent_req_nterror(req, status);
565                 return tevent_req_post(req, ev);
566         }
567         return req;
568 }
569
570 static void cli_smb_sent(struct tevent_req *subreq)
571 {
572         struct tevent_req *req = tevent_req_callback_data(
573                 subreq, struct tevent_req);
574         struct cli_smb_state *state = tevent_req_data(
575                 req, struct cli_smb_state);
576         ssize_t nwritten;
577         int err;
578
579         nwritten = writev_recv(subreq, &err);
580         TALLOC_FREE(subreq);
581         if (nwritten == -1) {
582                 NTSTATUS status = map_nt_error_from_unix(err);
583                 cli_state_notify_pending(state->cli, status);
584                 return;
585         }
586
587         if (state->one_way) {
588                 state->inbuf = NULL;
589                 tevent_req_done(req);
590                 return;
591         }
592
593         if (!cli_smb_req_set_pending(req)) {
594                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
595                 return;
596         }
597 }
598
599 static void cli_smb_received(struct tevent_req *subreq)
600 {
601         struct cli_state *cli = tevent_req_callback_data(
602                 subreq, struct cli_state);
603         TALLOC_CTX *frame = talloc_stackframe();
604         NTSTATUS status;
605         uint8_t *inbuf;
606         ssize_t received;
607         int err;
608
609         if (subreq != cli->conn.read_smb_req) {
610                 DEBUG(1, ("Internal error: cli_smb_received called with "
611                           "unexpected subreq\n"));
612                 status = NT_STATUS_INTERNAL_ERROR;
613                 cli_state_notify_pending(cli, status);
614                 TALLOC_FREE(frame);
615                 return;
616         }
617
618         received = read_smb_recv(subreq, frame, &inbuf, &err);
619         TALLOC_FREE(subreq);
620         cli->conn.read_smb_req = NULL;
621         if (received == -1) {
622                 status = map_nt_error_from_unix(err);
623                 cli_state_notify_pending(cli, status);
624                 TALLOC_FREE(frame);
625                 return;
626         }
627
628         status = cli->conn.dispatch_incoming(cli, frame, inbuf);
629         TALLOC_FREE(frame);
630         if (NT_STATUS_IS_OK(status)) {
631                 /*
632                  * We should not do any more processing
633                  * as the dispatch function called
634                  * tevent_req_done().
635                  */
636                 return;
637         } else if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
638                 /*
639                  * We got an error, so notify all pending requests
640                  */
641                 cli_state_notify_pending(cli, status);
642                 return;
643         }
644
645         /*
646          * We got NT_STATUS_RETRY, so we may ask for a
647          * next incoming pdu.
648          */
649         if (!cli_state_receive_next(cli)) {
650                 cli_state_notify_pending(cli, NT_STATUS_NO_MEMORY);
651         }
652 }
653
654 static NTSTATUS cli_state_dispatch_smb1(struct cli_state *cli,
655                                         TALLOC_CTX *frame,
656                                         uint8_t *inbuf)
657 {
658         struct tevent_req *req;
659         struct cli_smb_state *state;
660         NTSTATUS status;
661         int num_pending;
662         int i;
663         uint16_t mid;
664         bool oplock_break;
665
666         if ((IVAL(inbuf, 4) != 0x424d53ff) /* 0xFF"SMB" */
667             && (SVAL(inbuf, 4) != 0x45ff)) /* 0xFF"E" */ {
668                 DEBUG(10, ("Got non-SMB PDU\n"));
669                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
670         }
671
672         if (cli_encryption_on(cli) && (CVAL(inbuf, 0) == 0)) {
673                 uint16_t enc_ctx_num;
674
675                 status = get_enc_ctx_num(inbuf, &enc_ctx_num);
676                 if (!NT_STATUS_IS_OK(status)) {
677                         DEBUG(10, ("get_enc_ctx_num returned %s\n",
678                                    nt_errstr(status)));
679                         return status;
680                 }
681
682                 if (enc_ctx_num != cli->trans_enc_state->enc_ctx_num) {
683                         DEBUG(10, ("wrong enc_ctx %d, expected %d\n",
684                                    enc_ctx_num,
685                                    cli->trans_enc_state->enc_ctx_num));
686                         return NT_STATUS_INVALID_HANDLE;
687                 }
688
689                 status = common_decrypt_buffer(cli->trans_enc_state,
690                                                (char *)inbuf);
691                 if (!NT_STATUS_IS_OK(status)) {
692                         DEBUG(10, ("common_decrypt_buffer returned %s\n",
693                                    nt_errstr(status)));
694                         return status;
695                 }
696         }
697
698         mid = SVAL(inbuf, smb_mid);
699         num_pending = talloc_array_length(cli->conn.pending);
700
701         for (i=0; i<num_pending; i++) {
702                 if (mid == cli_smb_req_mid(cli->conn.pending[i])) {
703                         break;
704                 }
705         }
706         if (i == num_pending) {
707                 /* Dump unexpected reply */
708                 return NT_STATUS_RETRY;
709         }
710
711         oplock_break = false;
712
713         if (mid == 0xffff) {
714                 /*
715                  * Paranoia checks that this is really an oplock break request.
716                  */
717                 oplock_break = (smb_len(inbuf) == 51); /* hdr + 8 words */
718                 oplock_break &= ((CVAL(inbuf, smb_flg) & FLAG_REPLY) == 0);
719                 oplock_break &= (CVAL(inbuf, smb_com) == SMBlockingX);
720                 oplock_break &= (SVAL(inbuf, smb_vwv6) == 0);
721                 oplock_break &= (SVAL(inbuf, smb_vwv7) == 0);
722
723                 if (!oplock_break) {
724                         /* Dump unexpected reply */
725                         return NT_STATUS_RETRY;
726                 }
727         }
728
729         req = cli->conn.pending[i];
730         state = tevent_req_data(req, struct cli_smb_state);
731
732         if (!oplock_break /* oplock breaks are not signed */
733             && !cli_check_sign_mac(cli, (char *)inbuf, state->seqnum+1)) {
734                 DEBUG(10, ("cli_check_sign_mac failed\n"));
735                 return NT_STATUS_ACCESS_DENIED;
736         }
737
738         if (state->chained_requests != NULL) {
739                 struct tevent_req **chain = talloc_move(frame,
740                                             &state->chained_requests);
741                 int num_chained = talloc_array_length(chain);
742
743                 /*
744                  * We steal the inbuf to the chain,
745                  * so that it will stay until all
746                  * requests of the chain are finished.
747                  *
748                  * Each requests in the chain will
749                  * hold a talloc reference to the chain.
750                  * This way we do not expose the talloc_reference()
751                  * behavior to the callers.
752                  */
753                 talloc_steal(chain, inbuf);
754
755                 for (i=0; i<num_chained; i++) {
756                         struct tevent_req **ref;
757
758                         req = chain[i];
759                         state = tevent_req_data(req, struct cli_smb_state);
760
761                         cli_smb_req_unset_pending(req);
762
763                         /*
764                          * as we finish multiple requests here
765                          * we need to defer the callbacks as
766                          * they could destroy our current stack state.
767                          */
768                         tevent_req_defer_callback(req, state->ev);
769
770                         ref = talloc_reference(state, chain);
771                         if (tevent_req_nomem(ref, req)) {
772                                 continue;
773                         }
774
775                         state->inbuf = inbuf;
776                         state->chain_num = i;
777                         state->chain_length = num_chained;
778
779                         tevent_req_done(req);
780                 }
781
782                 return NT_STATUS_RETRY;
783         }
784
785         cli_smb_req_unset_pending(req);
786
787         state->inbuf = talloc_move(state, &inbuf);
788         state->chain_num = 0;
789         state->chain_length = 1;
790
791         if (talloc_array_length(cli->conn.pending) == 0) {
792                 tevent_req_done(req);
793                 return NT_STATUS_OK;
794         }
795
796         tevent_req_defer_callback(req, state->ev);
797         tevent_req_done(req);
798         return NT_STATUS_RETRY;
799 }
800
801 NTSTATUS cli_smb_recv(struct tevent_req *req,
802                       TALLOC_CTX *mem_ctx, uint8_t **pinbuf,
803                       uint8_t min_wct, uint8_t *pwct, uint16_t **pvwv,
804                       uint32_t *pnum_bytes, uint8_t **pbytes)
805 {
806         struct cli_smb_state *state = tevent_req_data(
807                 req, struct cli_smb_state);
808         NTSTATUS status = NT_STATUS_OK;
809         uint8_t cmd, wct;
810         uint16_t num_bytes;
811         size_t wct_ofs, bytes_offset;
812         int i;
813
814         if (tevent_req_is_nterror(req, &status)) {
815                 return status;
816         }
817
818         if (state->inbuf == NULL) {
819                 if (min_wct != 0) {
820                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
821                 }
822                 if (pinbuf) {
823                         *pinbuf = NULL;
824                 }
825                 if (pwct) {
826                         *pwct = 0;
827                 }
828                 if (pvwv) {
829                         *pvwv = NULL;
830                 }
831                 if (pnum_bytes) {
832                         *pnum_bytes = 0;
833                 }
834                 if (pbytes) {
835                         *pbytes = NULL;
836                 }
837                 /* This was a request without a reply */
838                 return NT_STATUS_OK;
839         }
840
841         wct_ofs = smb_wct;
842         cmd = CVAL(state->inbuf, smb_com);
843
844         for (i=0; i<state->chain_num; i++) {
845                 if (i < state->chain_num-1) {
846                         if (cmd == 0xff) {
847                                 return NT_STATUS_REQUEST_ABORTED;
848                         }
849                         if (!is_andx_req(cmd)) {
850                                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
851                         }
852                 }
853
854                 if (!have_andx_command((char *)state->inbuf, wct_ofs)) {
855                         /*
856                          * This request was not completed because a previous
857                          * request in the chain had received an error.
858                          */
859                         return NT_STATUS_REQUEST_ABORTED;
860                 }
861
862                 wct_ofs = SVAL(state->inbuf, wct_ofs + 3);
863
864                 /*
865                  * Skip the all-present length field. No overflow, we've just
866                  * put a 16-bit value into a size_t.
867                  */
868                 wct_ofs += 4;
869
870                 if (wct_ofs+2 > talloc_get_size(state->inbuf)) {
871                         return NT_STATUS_INVALID_NETWORK_RESPONSE;
872                 }
873
874                 cmd = CVAL(state->inbuf, wct_ofs + 1);
875         }
876
877         state->cli->raw_status = cli_pull_raw_error(state->inbuf);
878         if (NT_STATUS_IS_DOS(state->cli->raw_status)) {
879                 uint8_t eclass = NT_STATUS_DOS_CLASS(state->cli->raw_status);
880                 uint16_t ecode = NT_STATUS_DOS_CODE(state->cli->raw_status);
881                 /*
882                  * TODO: is it really a good idea to do a mapping here?
883                  *
884                  * The old cli_pull_error() also does it, so I do not change
885                  * the behavior yet.
886                  */
887                 status = dos_to_ntstatus(eclass, ecode);
888         } else {
889                 status = state->cli->raw_status;
890         }
891
892         if (!have_andx_command((char *)state->inbuf, wct_ofs)) {
893
894                 if ((cmd == SMBsesssetupX)
895                     && NT_STATUS_EQUAL(
896                             status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
897                         /*
898                          * NT_STATUS_MORE_PROCESSING_REQUIRED is a
899                          * valid return code for session setup
900                          */
901                         goto no_err;
902                 }
903
904                 if (NT_STATUS_IS_ERR(status)) {
905                         /*
906                          * The last command takes the error code. All
907                          * further commands down the requested chain
908                          * will get a NT_STATUS_REQUEST_ABORTED.
909                          */
910                         return status;
911                 }
912         }
913
914 no_err:
915
916         wct = CVAL(state->inbuf, wct_ofs);
917         bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
918         num_bytes = SVAL(state->inbuf, bytes_offset);
919
920         if (wct < min_wct) {
921                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
922         }
923
924         /*
925          * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes
926          * is a 16-bit value. So bytes_offset being size_t should be far from
927          * wrapping.
928          */
929         if ((bytes_offset + 2 > talloc_get_size(state->inbuf))
930             || (bytes_offset > 0xffff)) {
931                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
932         }
933
934         if (pwct != NULL) {
935                 *pwct = wct;
936         }
937         if (pvwv != NULL) {
938                 *pvwv = (uint16_t *)(state->inbuf + wct_ofs + 1);
939         }
940         if (pnum_bytes != NULL) {
941                 *pnum_bytes = num_bytes;
942         }
943         if (pbytes != NULL) {
944                 *pbytes = (uint8_t *)state->inbuf + bytes_offset + 2;
945         }
946         if ((mem_ctx != NULL) && (pinbuf != NULL)) {
947                 if (state->chain_num == state->chain_length-1) {
948                         *pinbuf = talloc_move(mem_ctx, &state->inbuf);
949                 } else {
950                         *pinbuf = state->inbuf;
951                 }
952         }
953
954         return status;
955 }
956
957 size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs)
958 {
959         size_t wct_ofs;
960         int i;
961
962         wct_ofs = smb_wct - 4;
963
964         for (i=0; i<num_reqs; i++) {
965                 struct cli_smb_state *state;
966                 state = tevent_req_data(reqs[i], struct cli_smb_state);
967                 wct_ofs += iov_len(state->iov+1, state->iov_count-1);
968                 wct_ofs = (wct_ofs + 3) & ~3;
969         }
970         return wct_ofs;
971 }
972
973 NTSTATUS cli_smb_chain_send(struct tevent_req **reqs, int num_reqs)
974 {
975         struct cli_smb_state *first_state = tevent_req_data(
976                 reqs[0], struct cli_smb_state);
977         struct cli_smb_state *last_state = tevent_req_data(
978                 reqs[num_reqs-1], struct cli_smb_state);
979         struct cli_smb_state *state;
980         size_t wct_offset;
981         size_t chain_padding = 0;
982         int i, iovlen;
983         struct iovec *iov = NULL;
984         struct iovec *this_iov;
985         NTSTATUS status;
986
987         iovlen = 0;
988         for (i=0; i<num_reqs; i++) {
989                 state = tevent_req_data(reqs[i], struct cli_smb_state);
990                 iovlen += state->iov_count;
991         }
992
993         iov = talloc_array(last_state, struct iovec, iovlen);
994         if (iov == NULL) {
995                 return NT_STATUS_NO_MEMORY;
996         }
997
998         first_state->chained_requests = (struct tevent_req **)talloc_memdup(
999                 last_state, reqs, sizeof(*reqs) * num_reqs);
1000         if (first_state->chained_requests == NULL) {
1001                 TALLOC_FREE(iov);
1002                 return NT_STATUS_NO_MEMORY;
1003         }
1004
1005         wct_offset = smb_wct - 4;
1006         this_iov = iov;
1007
1008         for (i=0; i<num_reqs; i++) {
1009                 size_t next_padding = 0;
1010                 uint16_t *vwv;
1011
1012                 state = tevent_req_data(reqs[i], struct cli_smb_state);
1013
1014                 if (i < num_reqs-1) {
1015                         if (!is_andx_req(CVAL(state->header, smb_com))
1016                             || CVAL(state->header, smb_wct) < 2) {
1017                                 TALLOC_FREE(iov);
1018                                 TALLOC_FREE(first_state->chained_requests);
1019                                 return NT_STATUS_INVALID_PARAMETER;
1020                         }
1021                 }
1022
1023                 wct_offset += iov_len(state->iov+1, state->iov_count-1) + 1;
1024                 if ((wct_offset % 4) != 0) {
1025                         next_padding = 4 - (wct_offset % 4);
1026                 }
1027                 wct_offset += next_padding;
1028                 vwv = state->vwv;
1029
1030                 if (i < num_reqs-1) {
1031                         struct cli_smb_state *next_state = tevent_req_data(
1032                                 reqs[i+1], struct cli_smb_state);
1033                         SCVAL(vwv+0, 0, CVAL(next_state->header, smb_com));
1034                         SCVAL(vwv+0, 1, 0);
1035                         SSVAL(vwv+1, 0, wct_offset);
1036                 } else if (is_andx_req(CVAL(state->header, smb_com))) {
1037                         /* properly end the chain */
1038                         SCVAL(vwv+0, 0, 0xff);
1039                         SCVAL(vwv+0, 1, 0xff);
1040                         SSVAL(vwv+1, 0, 0);
1041                 }
1042
1043                 if (i == 0) {
1044                         this_iov[0] = state->iov[0];
1045                 } else {
1046                         /*
1047                          * This one is a bit subtle. We have to add
1048                          * chain_padding bytes between the requests, and we
1049                          * have to also include the wct field of the
1050                          * subsequent requests. We use the subsequent header
1051                          * for the padding, it contains the wct field in its
1052                          * last byte.
1053                          */
1054                         this_iov[0].iov_len = chain_padding+1;
1055                         this_iov[0].iov_base = (void *)&state->header[
1056                                 sizeof(state->header) - this_iov[0].iov_len];
1057                         memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1);
1058                 }
1059                 memcpy(this_iov+1, state->iov+1,
1060                        sizeof(struct iovec) * (state->iov_count-1));
1061                 this_iov += state->iov_count;
1062                 chain_padding = next_padding;
1063         }
1064
1065         status = cli_smb_req_iov_send(reqs[0], last_state, iov, iovlen);
1066         if (!NT_STATUS_IS_OK(status)) {
1067                 TALLOC_FREE(iov);
1068                 TALLOC_FREE(first_state->chained_requests);
1069                 return status;
1070         }
1071
1072         return NT_STATUS_OK;
1073 }
1074
1075 bool cli_has_async_calls(struct cli_state *cli)
1076 {
1077         return ((tevent_queue_length(cli->conn.outgoing) != 0)
1078                 || (talloc_array_length(cli->conn.pending) != 0));
1079 }
1080
1081 struct cli_smb_oplock_break_waiter_state {
1082         uint16_t fnum;
1083         uint8_t level;
1084 };
1085
1086 static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq);
1087
1088 struct tevent_req *cli_smb_oplock_break_waiter_send(TALLOC_CTX *mem_ctx,
1089                                                     struct event_context *ev,
1090                                                     struct cli_state *cli)
1091 {
1092         struct tevent_req *req, *subreq;
1093         struct cli_smb_oplock_break_waiter_state *state;
1094         struct cli_smb_state *smb_state;
1095
1096         req = tevent_req_create(mem_ctx, &state,
1097                                 struct cli_smb_oplock_break_waiter_state);
1098         if (req == NULL) {
1099                 return NULL;
1100         }
1101
1102         /*
1103          * Create a fake SMB request that we will never send out. This is only
1104          * used to be set into the pending queue with the right mid.
1105          */
1106         subreq = cli_smb_req_create(mem_ctx, ev, cli, 0, 0, 0, NULL, 0, NULL);
1107         if (tevent_req_nomem(subreq, req)) {
1108                 return tevent_req_post(req, ev);
1109         }
1110         smb_state = tevent_req_data(subreq, struct cli_smb_state);
1111         SSVAL(smb_state->header, smb_mid, 0xffff);
1112
1113         if (!cli_smb_req_set_pending(subreq)) {
1114                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1115                 return tevent_req_post(req, ev);
1116         }
1117         tevent_req_set_callback(subreq, cli_smb_oplock_break_waiter_done, req);
1118         return req;
1119 }
1120
1121 static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq)
1122 {
1123         struct tevent_req *req = tevent_req_callback_data(
1124                 subreq, struct tevent_req);
1125         struct cli_smb_oplock_break_waiter_state *state = tevent_req_data(
1126                 req, struct cli_smb_oplock_break_waiter_state);
1127         uint8_t wct;
1128         uint16_t *vwv;
1129         uint32_t num_bytes;
1130         uint8_t *bytes;
1131         uint8_t *inbuf;
1132         NTSTATUS status;
1133
1134         status = cli_smb_recv(subreq, state, &inbuf, 8, &wct, &vwv,
1135                               &num_bytes, &bytes);
1136         TALLOC_FREE(subreq);
1137         if (!NT_STATUS_IS_OK(status)) {
1138                 tevent_req_nterror(req, status);
1139                 return;
1140         }
1141         state->fnum = SVAL(vwv+2, 0);
1142         state->level = CVAL(vwv+3, 1);
1143         tevent_req_done(req);
1144 }
1145
1146 NTSTATUS cli_smb_oplock_break_waiter_recv(struct tevent_req *req,
1147                                           uint16_t *pfnum,
1148                                           uint8_t *plevel)
1149 {
1150         struct cli_smb_oplock_break_waiter_state *state = tevent_req_data(
1151                 req, struct cli_smb_oplock_break_waiter_state);
1152         NTSTATUS status;
1153
1154         if (tevent_req_is_nterror(req, &status)) {
1155                 return status;
1156         }
1157         *pfnum = state->fnum;
1158         *plevel = state->level;
1159         return NT_STATUS_OK;
1160 }
1161
1162
1163 struct cli_session_request_state {
1164         struct tevent_context *ev;
1165         int sock;
1166         uint32 len_hdr;
1167         struct iovec iov[3];
1168         uint8_t nb_session_response;
1169 };
1170
1171 static void cli_session_request_sent(struct tevent_req *subreq);
1172 static void cli_session_request_recvd(struct tevent_req *subreq);
1173
1174 struct tevent_req *cli_session_request_send(TALLOC_CTX *mem_ctx,
1175                                             struct tevent_context *ev,
1176                                             int sock,
1177                                             const struct nmb_name *called,
1178                                             const struct nmb_name *calling)
1179 {
1180         struct tevent_req *req, *subreq;
1181         struct cli_session_request_state *state;
1182
1183         req = tevent_req_create(mem_ctx, &state,
1184                                 struct cli_session_request_state);
1185         if (req == NULL) {
1186                 return NULL;
1187         }
1188         state->ev = ev;
1189         state->sock = sock;
1190
1191         state->iov[1].iov_base = name_mangle(
1192                 state, called->name, called->name_type);
1193         if (tevent_req_nomem(state->iov[1].iov_base, req)) {
1194                 return tevent_req_post(req, ev);
1195         }
1196         state->iov[1].iov_len = name_len(
1197                 (unsigned char *)state->iov[1].iov_base,
1198                 talloc_get_size(state->iov[1].iov_base));
1199
1200         state->iov[2].iov_base = name_mangle(
1201                 state, calling->name, calling->name_type);
1202         if (tevent_req_nomem(state->iov[2].iov_base, req)) {
1203                 return tevent_req_post(req, ev);
1204         }
1205         state->iov[2].iov_len = name_len(
1206                 (unsigned char *)state->iov[2].iov_base,
1207                 talloc_get_size(state->iov[2].iov_base));
1208
1209         _smb_setlen(((char *)&state->len_hdr),
1210                     state->iov[1].iov_len + state->iov[2].iov_len);
1211         SCVAL((char *)&state->len_hdr, 0, 0x81);
1212
1213         state->iov[0].iov_base = &state->len_hdr;
1214         state->iov[0].iov_len = sizeof(state->len_hdr);
1215
1216         subreq = writev_send(state, ev, NULL, sock, true, state->iov, 3);
1217         if (tevent_req_nomem(subreq, req)) {
1218                 return tevent_req_post(req, ev);
1219         }
1220         tevent_req_set_callback(subreq, cli_session_request_sent, req);
1221         return req;
1222 }
1223
1224 static void cli_session_request_sent(struct tevent_req *subreq)
1225 {
1226         struct tevent_req *req = tevent_req_callback_data(
1227                 subreq, struct tevent_req);
1228         struct cli_session_request_state *state = tevent_req_data(
1229                 req, struct cli_session_request_state);
1230         ssize_t ret;
1231         int err;
1232
1233         ret = writev_recv(subreq, &err);
1234         TALLOC_FREE(subreq);
1235         if (ret == -1) {
1236                 tevent_req_error(req, err);
1237                 return;
1238         }
1239         subreq = read_smb_send(state, state->ev, state->sock);
1240         if (tevent_req_nomem(subreq, req)) {
1241                 return;
1242         }
1243         tevent_req_set_callback(subreq, cli_session_request_recvd, req);
1244 }
1245
1246 static void cli_session_request_recvd(struct tevent_req *subreq)
1247 {
1248         struct tevent_req *req = tevent_req_callback_data(
1249                 subreq, struct tevent_req);
1250         struct cli_session_request_state *state = tevent_req_data(
1251                 req, struct cli_session_request_state);
1252         uint8_t *buf;
1253         ssize_t ret;
1254         int err;
1255
1256         ret = read_smb_recv(subreq, talloc_tos(), &buf, &err);
1257         TALLOC_FREE(subreq);
1258
1259         if (ret < 4) {
1260                 ret = -1;
1261                 err = EIO;
1262         }
1263         if (ret == -1) {
1264                 tevent_req_error(req, err);
1265                 return;
1266         }
1267         /*
1268          * In case of an error there is more information in the data
1269          * portion according to RFC1002. We're not subtle enough to
1270          * respond to the different error conditions, so drop the
1271          * error info here.
1272          */
1273         state->nb_session_response = CVAL(buf, 0);
1274         tevent_req_done(req);
1275 }
1276
1277 bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp)
1278 {
1279         struct cli_session_request_state *state = tevent_req_data(
1280                 req, struct cli_session_request_state);
1281
1282         if (tevent_req_is_unix_error(req, err)) {
1283                 return false;
1284         }
1285         *resp = state->nb_session_response;
1286         return true;
1287 }