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