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