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