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