s3:libsmb: don't use the cli->inbuf to store the last error
[metze/samba/wip.git] / source3 / libsmb / async_smb.c
1 /*
2    Unix SMB/CIFS implementation.
3    Infrastructure for async SMB client requests
4    Copyright (C) Volker Lendecke 2008
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "includes.h"
21 #include "libsmb/libsmb.h"
22 #include "../lib/async_req/async_sock.h"
23 #include "../lib/util/tevent_ntstatus.h"
24 #include "../lib/util/tevent_unix.h"
25 #include "async_smb.h"
26 #include "smb_crypt.h"
27 #include "libsmb/nmblib.h"
28 #include "read_smb.h"
29
30 static NTSTATUS cli_pull_raw_error(const uint8_t *buf)
31 {
32         uint32_t flags2 = SVAL(buf, smb_flg2);
33
34         if (flags2 & FLAGS2_32_BIT_ERROR_CODES) {
35                 return NT_STATUS(IVAL(buf, smb_rcls));
36         }
37
38         return NT_STATUS_DOS(CVAL(buf, smb_rcls), SVAL(buf,smb_err));
39 }
40
41 /**
42  * Figure out if there is an andx command behind the current one
43  * @param[in] buf       The smb buffer to look at
44  * @param[in] ofs       The offset to the wct field that is followed by the cmd
45  * @retval Is there a command following?
46  */
47
48 static bool have_andx_command(const char *buf, uint16_t ofs)
49 {
50         uint8_t wct;
51         size_t buflen = talloc_get_size(buf);
52
53         if ((ofs == buflen-1) || (ofs == buflen)) {
54                 return false;
55         }
56
57         wct = CVAL(buf, ofs);
58         if (wct < 2) {
59                 /*
60                  * Not enough space for the command and a following pointer
61                  */
62                 return false;
63         }
64         return (CVAL(buf, ofs+1) != 0xff);
65 }
66
67 #define MAX_SMB_IOV 5
68
69 struct cli_smb_state {
70         struct tevent_context *ev;
71         struct cli_state *cli;
72         uint8_t header[smb_wct+1]; /* Space for the header including the wct */
73
74         /*
75          * For normal requests, cli_smb_req_send chooses a mid. Secondary
76          * trans requests need to use the mid of the primary request, so we
77          * need a place to store it. Assume it's set if != 0.
78          */
79         uint16_t mid;
80
81         uint16_t *vwv;
82         uint8_t bytecount_buf[2];
83
84         struct iovec iov[MAX_SMB_IOV+3];
85         int iov_count;
86
87         uint8_t *inbuf;
88         uint32_t seqnum;
89         int chain_num;
90         int chain_length;
91         struct tevent_req **chained_requests;
92 };
93
94 static uint16_t cli_alloc_mid(struct cli_state *cli)
95 {
96         int num_pending = talloc_array_length(cli->pending);
97         uint16_t result;
98
99         while (true) {
100                 int i;
101
102                 result = cli->mid++;
103                 if ((result == 0) || (result == 0xffff)) {
104                         continue;
105                 }
106
107                 for (i=0; i<num_pending; i++) {
108                         if (result == cli_smb_req_mid(cli->pending[i])) {
109                                 break;
110                         }
111                 }
112
113                 if (i == num_pending) {
114                         return result;
115                 }
116         }
117 }
118
119 void cli_smb_req_unset_pending(struct tevent_req *req)
120 {
121         struct cli_smb_state *state = tevent_req_data(
122                 req, struct cli_smb_state);
123         struct cli_state *cli = state->cli;
124         int num_pending = talloc_array_length(cli->pending);
125         int i;
126
127         if (state->mid != 0) {
128                 /*
129                  * This is a [nt]trans[2] request which waits
130                  * for more than one reply.
131                  */
132                 return;
133         }
134
135         if (num_pending == 1) {
136                 /*
137                  * The pending read_smb tevent_req is a child of
138                  * cli->pending. So if nothing is pending anymore, we need to
139                  * delete the socket read fde.
140                  */
141                 TALLOC_FREE(cli->pending);
142                 return;
143         }
144
145         for (i=0; i<num_pending; i++) {
146                 if (req == cli->pending[i]) {
147                         break;
148                 }
149         }
150         if (i == num_pending) {
151                 /*
152                  * Something's seriously broken. Just returning here is the
153                  * right thing nevertheless, the point of this routine is to
154                  * remove ourselves from cli->pending.
155                  */
156                 return;
157         }
158
159         /*
160          * Remove ourselves from the cli->pending array
161          */
162         cli->pending[i] = cli->pending[num_pending-1];
163
164         /*
165          * No NULL check here, we're shrinking by sizeof(void *), and
166          * talloc_realloc just adjusts the size for this.
167          */
168         cli->pending = talloc_realloc(NULL, cli->pending, struct tevent_req *,
169                                       num_pending - 1);
170         return;
171 }
172
173 static int cli_smb_req_destructor(struct tevent_req *req)
174 {
175         struct cli_smb_state *state = tevent_req_data(
176                 req, struct cli_smb_state);
177         /*
178          * Make sure we really remove it from
179          * the pending array on destruction.
180          */
181         state->mid = 0;
182         cli_smb_req_unset_pending(req);
183         return 0;
184 }
185
186 static void cli_smb_received(struct tevent_req *subreq);
187
188 bool cli_smb_req_set_pending(struct tevent_req *req)
189 {
190         struct cli_smb_state *state = tevent_req_data(
191                 req, struct cli_smb_state);
192         struct cli_state *cli;
193         struct tevent_req **pending;
194         int num_pending;
195         struct tevent_req *subreq;
196
197         cli = state->cli;
198         num_pending = talloc_array_length(cli->pending);
199
200         pending = talloc_realloc(cli, cli->pending, struct tevent_req *,
201                                  num_pending+1);
202         if (pending == NULL) {
203                 return false;
204         }
205         pending[num_pending] = req;
206         cli->pending = pending;
207         talloc_set_destructor(req, cli_smb_req_destructor);
208
209         if (num_pending > 0) {
210                 return true;
211         }
212
213         /*
214          * We're the first ones, add the read_smb request that waits for the
215          * answer from the server
216          */
217         subreq = read_smb_send(cli->pending, state->ev, cli->fd);
218         if (subreq == NULL) {
219                 cli_smb_req_unset_pending(req);
220                 return false;
221         }
222         tevent_req_set_callback(subreq, cli_smb_received, cli);
223         return true;
224 }
225
226 /*
227  * Fetch a smb request's mid. Only valid after the request has been sent by
228  * cli_smb_req_send().
229  */
230 uint16_t cli_smb_req_mid(struct tevent_req *req)
231 {
232         struct cli_smb_state *state = tevent_req_data(
233                 req, struct cli_smb_state);
234         return SVAL(state->header, smb_mid);
235 }
236
237 void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid)
238 {
239         struct cli_smb_state *state = tevent_req_data(
240                 req, struct cli_smb_state);
241         state->mid = mid;
242 }
243
244 uint32_t cli_smb_req_seqnum(struct tevent_req *req)
245 {
246         struct cli_smb_state *state = tevent_req_data(
247                 req, struct cli_smb_state);
248         return state->seqnum;
249 }
250
251 void cli_smb_req_set_seqnum(struct tevent_req *req, uint32_t seqnum)
252 {
253         struct cli_smb_state *state = tevent_req_data(
254                 req, struct cli_smb_state);
255         state->seqnum = seqnum;
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_oom(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_unset_pending(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_unset_pending(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         state->cli->raw_status = cli_pull_raw_error(state->inbuf);
756         if (NT_STATUS_IS_DOS(state->cli->raw_status)) {
757                 uint8_t eclass = NT_STATUS_DOS_CLASS(state->cli->raw_status);
758                 uint16_t ecode = NT_STATUS_DOS_CODE(state->cli->raw_status);
759                 /*
760                  * TODO: is it really a good idea to do a mapping here?
761                  *
762                  * The old cli_pull_error() also does it, so I do not change
763                  * the behavior yet.
764                  */
765                 status = dos_to_ntstatus(eclass, ecode);
766         } else {
767                 status = state->cli->raw_status;
768         }
769
770         if (!have_andx_command((char *)state->inbuf, wct_ofs)) {
771
772                 if ((cmd == SMBsesssetupX)
773                     && NT_STATUS_EQUAL(
774                             status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
775                         /*
776                          * NT_STATUS_MORE_PROCESSING_REQUIRED is a
777                          * valid return code for session setup
778                          */
779                         goto no_err;
780                 }
781
782                 if (NT_STATUS_IS_ERR(status)) {
783                         /*
784                          * The last command takes the error code. All
785                          * further commands down the requested chain
786                          * will get a NT_STATUS_REQUEST_ABORTED.
787                          */
788                         return status;
789                 }
790         }
791
792 no_err:
793
794         wct = CVAL(state->inbuf, wct_ofs);
795         bytes_offset = wct_ofs + 1 + wct * sizeof(uint16_t);
796         num_bytes = SVAL(state->inbuf, bytes_offset);
797
798         if (wct < min_wct) {
799                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
800         }
801
802         /*
803          * wct_ofs is a 16-bit value plus 4, wct is a 8-bit value, num_bytes
804          * is a 16-bit value. So bytes_offset being size_t should be far from
805          * wrapping.
806          */
807         if ((bytes_offset + 2 > talloc_get_size(state->inbuf))
808             || (bytes_offset > 0xffff)) {
809                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
810         }
811
812         if (pwct != NULL) {
813                 *pwct = wct;
814         }
815         if (pvwv != NULL) {
816                 *pvwv = (uint16_t *)(state->inbuf + wct_ofs + 1);
817         }
818         if (pnum_bytes != NULL) {
819                 *pnum_bytes = num_bytes;
820         }
821         if (pbytes != NULL) {
822                 *pbytes = (uint8_t *)state->inbuf + bytes_offset + 2;
823         }
824         if ((mem_ctx != NULL) && (pinbuf != NULL)) {
825                 if (state->chain_num == state->chain_length-1) {
826                         *pinbuf = talloc_move(mem_ctx, &state->inbuf);
827                 } else {
828                         *pinbuf = state->inbuf;
829                 }
830         }
831
832         return status;
833 }
834
835 size_t cli_smb_wct_ofs(struct tevent_req **reqs, int num_reqs)
836 {
837         size_t wct_ofs;
838         int i;
839
840         wct_ofs = smb_wct - 4;
841
842         for (i=0; i<num_reqs; i++) {
843                 struct cli_smb_state *state;
844                 state = tevent_req_data(reqs[i], struct cli_smb_state);
845                 wct_ofs += iov_len(state->iov+1, state->iov_count-1);
846                 wct_ofs = (wct_ofs + 3) & ~3;
847         }
848         return wct_ofs;
849 }
850
851 NTSTATUS cli_smb_chain_send(struct tevent_req **reqs, int num_reqs)
852 {
853         struct cli_smb_state *first_state = tevent_req_data(
854                 reqs[0], struct cli_smb_state);
855         struct cli_smb_state *last_state = tevent_req_data(
856                 reqs[num_reqs-1], struct cli_smb_state);
857         struct cli_smb_state *state;
858         size_t wct_offset;
859         size_t chain_padding = 0;
860         int i, iovlen;
861         struct iovec *iov = NULL;
862         struct iovec *this_iov;
863         NTSTATUS status;
864
865         iovlen = 0;
866         for (i=0; i<num_reqs; i++) {
867                 state = tevent_req_data(reqs[i], struct cli_smb_state);
868                 iovlen += state->iov_count;
869         }
870
871         iov = talloc_array(last_state, struct iovec, iovlen);
872         if (iov == NULL) {
873                 return NT_STATUS_NO_MEMORY;
874         }
875
876         first_state->chained_requests = (struct tevent_req **)talloc_memdup(
877                 last_state, reqs, sizeof(*reqs) * num_reqs);
878         if (first_state->chained_requests == NULL) {
879                 TALLOC_FREE(iov);
880                 return NT_STATUS_NO_MEMORY;
881         }
882
883         wct_offset = smb_wct - 4;
884         this_iov = iov;
885
886         for (i=0; i<num_reqs; i++) {
887                 size_t next_padding = 0;
888                 uint16_t *vwv;
889
890                 state = tevent_req_data(reqs[i], struct cli_smb_state);
891
892                 if (i < num_reqs-1) {
893                         if (!is_andx_req(CVAL(state->header, smb_com))
894                             || CVAL(state->header, smb_wct) < 2) {
895                                 TALLOC_FREE(iov);
896                                 TALLOC_FREE(first_state->chained_requests);
897                                 return NT_STATUS_INVALID_PARAMETER;
898                         }
899                 }
900
901                 wct_offset += iov_len(state->iov+1, state->iov_count-1) + 1;
902                 if ((wct_offset % 4) != 0) {
903                         next_padding = 4 - (wct_offset % 4);
904                 }
905                 wct_offset += next_padding;
906                 vwv = state->vwv;
907
908                 if (i < num_reqs-1) {
909                         struct cli_smb_state *next_state = tevent_req_data(
910                                 reqs[i+1], struct cli_smb_state);
911                         SCVAL(vwv+0, 0, CVAL(next_state->header, smb_com));
912                         SCVAL(vwv+0, 1, 0);
913                         SSVAL(vwv+1, 0, wct_offset);
914                 } else if (is_andx_req(CVAL(state->header, smb_com))) {
915                         /* properly end the chain */
916                         SCVAL(vwv+0, 0, 0xff);
917                         SCVAL(vwv+0, 1, 0xff);
918                         SSVAL(vwv+1, 0, 0);
919                 }
920
921                 if (i == 0) {
922                         this_iov[0] = state->iov[0];
923                 } else {
924                         /*
925                          * This one is a bit subtle. We have to add
926                          * chain_padding bytes between the requests, and we
927                          * have to also include the wct field of the
928                          * subsequent requests. We use the subsequent header
929                          * for the padding, it contains the wct field in its
930                          * last byte.
931                          */
932                         this_iov[0].iov_len = chain_padding+1;
933                         this_iov[0].iov_base = (void *)&state->header[
934                                 sizeof(state->header) - this_iov[0].iov_len];
935                         memset(this_iov[0].iov_base, 0, this_iov[0].iov_len-1);
936                 }
937                 memcpy(this_iov+1, state->iov+1,
938                        sizeof(struct iovec) * (state->iov_count-1));
939                 this_iov += state->iov_count;
940                 chain_padding = next_padding;
941         }
942
943         status = cli_smb_req_iov_send(reqs[0], last_state, iov, iovlen);
944         if (!NT_STATUS_IS_OK(status)) {
945                 TALLOC_FREE(iov);
946                 TALLOC_FREE(first_state->chained_requests);
947                 return status;
948         }
949
950         return NT_STATUS_OK;
951 }
952
953 uint8_t *cli_smb_inbuf(struct tevent_req *req)
954 {
955         struct cli_smb_state *state = tevent_req_data(
956                 req, struct cli_smb_state);
957         return state->inbuf;
958 }
959
960 bool cli_has_async_calls(struct cli_state *cli)
961 {
962         return ((tevent_queue_length(cli->outgoing) != 0)
963                 || (talloc_array_length(cli->pending) != 0));
964 }
965
966 struct cli_smb_oplock_break_waiter_state {
967         uint16_t fnum;
968         uint8_t level;
969 };
970
971 static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq);
972
973 struct tevent_req *cli_smb_oplock_break_waiter_send(TALLOC_CTX *mem_ctx,
974                                                     struct event_context *ev,
975                                                     struct cli_state *cli)
976 {
977         struct tevent_req *req, *subreq;
978         struct cli_smb_oplock_break_waiter_state *state;
979         struct cli_smb_state *smb_state;
980
981         req = tevent_req_create(mem_ctx, &state,
982                                 struct cli_smb_oplock_break_waiter_state);
983         if (req == NULL) {
984                 return NULL;
985         }
986
987         /*
988          * Create a fake SMB request that we will never send out. This is only
989          * used to be set into the pending queue with the right mid.
990          */
991         subreq = cli_smb_req_create(mem_ctx, ev, cli, 0, 0, 0, NULL, 0, NULL);
992         if (tevent_req_nomem(subreq, req)) {
993                 return tevent_req_post(req, ev);
994         }
995         smb_state = tevent_req_data(subreq, struct cli_smb_state);
996         SSVAL(smb_state->header, smb_mid, 0xffff);
997
998         if (!cli_smb_req_set_pending(subreq)) {
999                 tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
1000                 return tevent_req_post(req, ev);
1001         }
1002         tevent_req_set_callback(subreq, cli_smb_oplock_break_waiter_done, req);
1003         return req;
1004 }
1005
1006 static void cli_smb_oplock_break_waiter_done(struct tevent_req *subreq)
1007 {
1008         struct tevent_req *req = tevent_req_callback_data(
1009                 subreq, struct tevent_req);
1010         struct cli_smb_oplock_break_waiter_state *state = tevent_req_data(
1011                 req, struct cli_smb_oplock_break_waiter_state);
1012         uint8_t wct;
1013         uint16_t *vwv;
1014         uint32_t num_bytes;
1015         uint8_t *bytes;
1016         uint8_t *inbuf;
1017         NTSTATUS status;
1018
1019         status = cli_smb_recv(subreq, state, &inbuf, 8, &wct, &vwv,
1020                               &num_bytes, &bytes);
1021         TALLOC_FREE(subreq);
1022         if (!NT_STATUS_IS_OK(status)) {
1023                 tevent_req_nterror(req, status);
1024                 return;
1025         }
1026         state->fnum = SVAL(vwv+2, 0);
1027         state->level = CVAL(vwv+3, 1);
1028         tevent_req_done(req);
1029 }
1030
1031 NTSTATUS cli_smb_oplock_break_waiter_recv(struct tevent_req *req,
1032                                           uint16_t *pfnum,
1033                                           uint8_t *plevel)
1034 {
1035         struct cli_smb_oplock_break_waiter_state *state = tevent_req_data(
1036                 req, struct cli_smb_oplock_break_waiter_state);
1037         NTSTATUS status;
1038
1039         if (tevent_req_is_nterror(req, &status)) {
1040                 return status;
1041         }
1042         *pfnum = state->fnum;
1043         *plevel = state->level;
1044         return NT_STATUS_OK;
1045 }
1046
1047
1048 struct cli_session_request_state {
1049         struct tevent_context *ev;
1050         int sock;
1051         uint32 len_hdr;
1052         struct iovec iov[3];
1053         uint8_t nb_session_response;
1054 };
1055
1056 static void cli_session_request_sent(struct tevent_req *subreq);
1057 static void cli_session_request_recvd(struct tevent_req *subreq);
1058
1059 struct tevent_req *cli_session_request_send(TALLOC_CTX *mem_ctx,
1060                                             struct tevent_context *ev,
1061                                             int sock,
1062                                             const struct nmb_name *called,
1063                                             const struct nmb_name *calling)
1064 {
1065         struct tevent_req *req, *subreq;
1066         struct cli_session_request_state *state;
1067
1068         req = tevent_req_create(mem_ctx, &state,
1069                                 struct cli_session_request_state);
1070         if (req == NULL) {
1071                 return NULL;
1072         }
1073         state->ev = ev;
1074         state->sock = sock;
1075
1076         state->iov[1].iov_base = name_mangle(
1077                 state, called->name, called->name_type);
1078         if (tevent_req_nomem(state->iov[1].iov_base, req)) {
1079                 return tevent_req_post(req, ev);
1080         }
1081         state->iov[1].iov_len = name_len(
1082                 (unsigned char *)state->iov[1].iov_base,
1083                 talloc_get_size(state->iov[1].iov_base));
1084
1085         state->iov[2].iov_base = name_mangle(
1086                 state, calling->name, calling->name_type);
1087         if (tevent_req_nomem(state->iov[2].iov_base, req)) {
1088                 return tevent_req_post(req, ev);
1089         }
1090         state->iov[2].iov_len = name_len(
1091                 (unsigned char *)state->iov[2].iov_base,
1092                 talloc_get_size(state->iov[2].iov_base));
1093
1094         _smb_setlen(((char *)&state->len_hdr),
1095                     state->iov[1].iov_len + state->iov[2].iov_len);
1096         SCVAL((char *)&state->len_hdr, 0, 0x81);
1097
1098         state->iov[0].iov_base = &state->len_hdr;
1099         state->iov[0].iov_len = sizeof(state->len_hdr);
1100
1101         subreq = writev_send(state, ev, NULL, sock, true, state->iov, 3);
1102         if (tevent_req_nomem(subreq, req)) {
1103                 return tevent_req_post(req, ev);
1104         }
1105         tevent_req_set_callback(subreq, cli_session_request_sent, req);
1106         return req;
1107 }
1108
1109 static void cli_session_request_sent(struct tevent_req *subreq)
1110 {
1111         struct tevent_req *req = tevent_req_callback_data(
1112                 subreq, struct tevent_req);
1113         struct cli_session_request_state *state = tevent_req_data(
1114                 req, struct cli_session_request_state);
1115         ssize_t ret;
1116         int err;
1117
1118         ret = writev_recv(subreq, &err);
1119         TALLOC_FREE(subreq);
1120         if (ret == -1) {
1121                 tevent_req_error(req, err);
1122                 return;
1123         }
1124         subreq = read_smb_send(state, state->ev, state->sock);
1125         if (tevent_req_nomem(subreq, req)) {
1126                 return;
1127         }
1128         tevent_req_set_callback(subreq, cli_session_request_recvd, req);
1129 }
1130
1131 static void cli_session_request_recvd(struct tevent_req *subreq)
1132 {
1133         struct tevent_req *req = tevent_req_callback_data(
1134                 subreq, struct tevent_req);
1135         struct cli_session_request_state *state = tevent_req_data(
1136                 req, struct cli_session_request_state);
1137         uint8_t *buf;
1138         ssize_t ret;
1139         int err;
1140
1141         ret = read_smb_recv(subreq, talloc_tos(), &buf, &err);
1142         TALLOC_FREE(subreq);
1143
1144         if (ret < 4) {
1145                 ret = -1;
1146                 err = EIO;
1147         }
1148         if (ret == -1) {
1149                 tevent_req_error(req, err);
1150                 return;
1151         }
1152         /*
1153          * In case of an error there is more information in the data
1154          * portion according to RFC1002. We're not subtle enough to
1155          * respond to the different error conditions, so drop the
1156          * error info here.
1157          */
1158         state->nb_session_response = CVAL(buf, 0);
1159         tevent_req_done(req);
1160 }
1161
1162 bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp)
1163 {
1164         struct cli_session_request_state *state = tevent_req_data(
1165                 req, struct cli_session_request_state);
1166
1167         if (tevent_req_is_unix_error(req, err)) {
1168                 return false;
1169         }
1170         *resp = state->nb_session_response;
1171         return true;
1172 }