s3:smbd: allow SMB2 Cancel to have the async flag set
[metze/samba/wip.git] / source3 / smbd / smb2_server.c
1 /*
2    Unix SMB/CIFS implementation.
3    Core SMB2 server
4
5    Copyright (C) Stefan Metzmacher 2009
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 3 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "includes.h"
22 #include "smbd/globals.h"
23 #include "../libcli/smb/smb_common.h"
24 #include "../lib/tsocket/tsocket.h"
25
26 bool smbd_is_smb2_header(const uint8_t *inbuf, size_t size)
27 {
28         if (size < (4 + SMB2_HDR_BODY)) {
29                 return false;
30         }
31
32         if (IVAL(inbuf, 4) != SMB2_MAGIC) {
33                 return false;
34         }
35
36         return true;
37 }
38
39 static NTSTATUS smbd_initialize_smb2(struct smbd_server_connection *sconn)
40 {
41         NTSTATUS status;
42         int ret;
43
44         TALLOC_FREE(sconn->smb1.fde);
45
46         sconn->smb2.event_ctx = smbd_event_context();
47
48         sconn->smb2.recv_queue = tevent_queue_create(sconn, "smb2 recv queue");
49         if (sconn->smb2.recv_queue == NULL) {
50                 return NT_STATUS_NO_MEMORY;
51         }
52
53         sconn->smb2.send_queue = tevent_queue_create(sconn, "smb2 send queue");
54         if (sconn->smb2.send_queue == NULL) {
55                 return NT_STATUS_NO_MEMORY;
56         }
57
58         sconn->smb2.sessions.idtree = idr_init(sconn);
59         if (sconn->smb2.sessions.idtree == NULL) {
60                 return NT_STATUS_NO_MEMORY;
61         }
62         sconn->smb2.sessions.limit = 0x0000FFFE;
63         sconn->smb2.sessions.list = NULL;
64
65         ret = tstream_bsd_existing_socket(sconn, smbd_server_fd(),
66                                           &sconn->smb2.stream);
67         if (ret == -1) {
68                 status = map_nt_error_from_unix(errno);
69                 return status;
70         }
71
72         /* Ensure child is set to non-blocking mode */
73         set_blocking(smbd_server_fd(),false);
74         return NT_STATUS_OK;
75 }
76
77 #define smb2_len(buf) (PVAL(buf,3)|(PVAL(buf,2)<<8)|(PVAL(buf,1)<<16))
78 #define _smb2_setlen(_buf,len) do { \
79         uint8_t *buf = (uint8_t *)_buf; \
80         buf[0] = 0; \
81         buf[1] = ((len)&0xFF0000)>>16; \
82         buf[2] = ((len)&0xFF00)>>8; \
83         buf[3] = (len)&0xFF; \
84 } while (0)
85
86 static void smb2_setup_nbt_length(struct iovec *vector, int count)
87 {
88         size_t len = 0;
89         int i;
90
91         for (i=1; i < count; i++) {
92                 len += vector[i].iov_len;
93         }
94
95         _smb2_setlen(vector[0].iov_base, len);
96 }
97
98 static int smbd_smb2_request_parent_destructor(struct smbd_smb2_request **req)
99 {
100         if (*req) {
101                 (*req)->parent = NULL;
102                 (*req)->mem_pool = NULL;
103         }
104
105         return 0;
106 }
107
108 static int smbd_smb2_request_destructor(struct smbd_smb2_request *req)
109 {
110         if (req->out.vector) {
111                 DLIST_REMOVE(req->sconn->smb2.requests, req);
112         }
113
114         if (req->parent) {
115                 *req->parent = NULL;
116                 talloc_free(req->mem_pool);
117         }
118
119         return 0;
120 }
121
122 static struct smbd_smb2_request *smbd_smb2_request_allocate(TALLOC_CTX *mem_ctx)
123 {
124         TALLOC_CTX *mem_pool;
125         struct smbd_smb2_request **parent;
126         struct smbd_smb2_request *req;
127
128         mem_pool = talloc_pool(mem_ctx, 8192);
129         if (mem_pool == NULL) {
130                 return NULL;
131         }
132
133         parent = talloc(mem_pool, struct smbd_smb2_request *);
134         if (parent == NULL) {
135                 talloc_free(mem_pool);
136                 return NULL;
137         }
138
139         req = talloc_zero(parent, struct smbd_smb2_request);
140         if (req == NULL) {
141                 talloc_free(mem_pool);
142                 return NULL;
143         }
144         *parent         = req;
145         req->mem_pool   = mem_pool;
146         req->parent     = parent;
147
148         talloc_set_destructor(parent, smbd_smb2_request_parent_destructor);
149         talloc_set_destructor(req, smbd_smb2_request_destructor);
150
151         return req;
152 }
153
154 static NTSTATUS smbd_smb2_request_create(struct smbd_server_connection *sconn,
155                                          const uint8_t *inbuf, size_t size,
156                                          struct smbd_smb2_request **_req)
157 {
158         struct smbd_smb2_request *req;
159         uint32_t protocol_version;
160         const uint8_t *inhdr = NULL;
161         off_t ofs = 0;
162         uint16_t cmd;
163         uint32_t next_command_ofs;
164
165         if (size < (4 + SMB2_HDR_BODY + 2)) {
166                 DEBUG(0,("Invalid SMB2 packet length count %ld\n", (long)size));
167                 return NT_STATUS_INVALID_PARAMETER;
168         }
169
170         inhdr = inbuf + 4;
171
172         protocol_version = IVAL(inhdr, SMB2_HDR_PROTOCOL_ID);
173         if (protocol_version != SMB2_MAGIC) {
174                 DEBUG(0,("Invalid SMB packet: protocol prefix: 0x%08X\n",
175                          protocol_version));
176                 return NT_STATUS_INVALID_PARAMETER;
177         }
178
179         cmd = SVAL(inhdr, SMB2_HDR_OPCODE);
180         if (cmd != SMB2_OP_NEGPROT) {
181                 DEBUG(0,("Invalid SMB packet: first request: 0x%04X\n",
182                          cmd));
183                 return NT_STATUS_INVALID_PARAMETER;
184         }
185
186         next_command_ofs = IVAL(inhdr, SMB2_HDR_NEXT_COMMAND);
187         if (next_command_ofs != 0) {
188                 DEBUG(0,("Invalid SMB packet: next_command: 0x%08X\n",
189                          next_command_ofs));
190                 return NT_STATUS_INVALID_PARAMETER;
191         }
192
193         req = smbd_smb2_request_allocate(sconn);
194         if (req == NULL) {
195                 return NT_STATUS_NO_MEMORY;
196         }
197         req->sconn = sconn;
198
199         talloc_steal(req, inbuf);
200
201         req->in.vector = talloc_array(req, struct iovec, 4);
202         if (req->in.vector == NULL) {
203                 TALLOC_FREE(req);
204                 return NT_STATUS_NO_MEMORY;
205         }
206         req->in.vector_count = 4;
207
208         memcpy(req->in.nbt_hdr, inbuf, 4);
209
210         ofs = 0;
211         req->in.vector[0].iov_base      = (void *)req->in.nbt_hdr;
212         req->in.vector[0].iov_len       = 4;
213         ofs += req->in.vector[0].iov_len;
214
215         req->in.vector[1].iov_base      = (void *)(inbuf + ofs);
216         req->in.vector[1].iov_len       = SMB2_HDR_BODY;
217         ofs += req->in.vector[1].iov_len;
218
219         req->in.vector[2].iov_base      = (void *)(inbuf + ofs);
220         req->in.vector[2].iov_len       = SVAL(inbuf, ofs) & 0xFFFE;
221         ofs += req->in.vector[2].iov_len;
222
223         if (ofs > size) {
224                 return NT_STATUS_INVALID_PARAMETER;
225         }
226
227         req->in.vector[3].iov_base      = (void *)(inbuf + ofs);
228         req->in.vector[3].iov_len       = size - ofs;
229         ofs += req->in.vector[3].iov_len;
230
231         req->current_idx = 1;
232
233         *_req = req;
234         return NT_STATUS_OK;
235 }
236
237 static NTSTATUS smbd_smb2_request_validate(struct smbd_smb2_request *req)
238 {
239         int count;
240         int idx;
241         bool compound_related = false;
242
243         count = req->in.vector_count;
244
245         if (count < 4) {
246                 /* It's not a SMB2 request */
247                 return NT_STATUS_INVALID_PARAMETER;
248         }
249
250         for (idx=1; idx < count; idx += 3) {
251                 const uint8_t *inhdr = NULL;
252                 uint32_t flags;
253
254                 if (req->in.vector[idx].iov_len != SMB2_HDR_BODY) {
255                         return NT_STATUS_INVALID_PARAMETER;
256                 }
257
258                 if (req->in.vector[idx+1].iov_len < 2) {
259                         return NT_STATUS_INVALID_PARAMETER;
260                 }
261
262                 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
263
264                 /* setup the SMB2 header */
265                 if (IVAL(inhdr, SMB2_HDR_PROTOCOL_ID) != SMB2_MAGIC) {
266                         return NT_STATUS_INVALID_PARAMETER;
267                 }
268
269                 flags = IVAL(inhdr, SMB2_HDR_FLAGS);
270                 if (idx == 1) {
271                         /*
272                          * the 1st request should never have the
273                          * SMB2_HDR_FLAG_CHAINED flag set
274                          */
275                         if (flags & SMB2_HDR_FLAG_CHAINED) {
276                                 req->next_status = NT_STATUS_INVALID_PARAMETER;
277                                 return NT_STATUS_OK;
278                         }
279                 } else if (idx == 4) {
280                         /*
281                          * the 2nd request triggers related vs. unrelated
282                          * compounded requests
283                          */
284                         if (flags & SMB2_HDR_FLAG_CHAINED) {
285                                 compound_related = true;
286                         }
287                 } else if (idx > 4) {
288 #if 0
289                         /*
290                          * It seems the this tests are wrong
291                          * see the SMB2-COMPOUND test
292                          */
293
294                         /*
295                          * all other requests should match the 2nd one
296                          */
297                         if (flags & SMB2_HDR_FLAG_CHAINED) {
298                                 if (!compound_related) {
299                                         req->next_status =
300                                                 NT_STATUS_INVALID_PARAMETER;
301                                         return NT_STATUS_OK;
302                                 }
303                         } else {
304                                 if (compound_related) {
305                                         req->next_status =
306                                                 NT_STATUS_INVALID_PARAMETER;
307                                         return NT_STATUS_OK;
308                                 }
309                         }
310 #endif
311                 }
312         }
313
314         return NT_STATUS_OK;
315 }
316
317 static NTSTATUS smbd_smb2_request_setup_out(struct smbd_smb2_request *req)
318 {
319         struct iovec *vector;
320         int count;
321         int idx;
322
323         count = req->in.vector_count;
324         vector = talloc_array(req, struct iovec, count);
325         if (vector == NULL) {
326                 return NT_STATUS_NO_MEMORY;
327         }
328
329         vector[0].iov_base      = req->out.nbt_hdr;
330         vector[0].iov_len       = 4;
331         SIVAL(req->out.nbt_hdr, 0, 0);
332
333         for (idx=1; idx < count; idx += 3) {
334                 const uint8_t *inhdr = NULL;
335                 uint32_t in_flags;
336                 uint8_t *outhdr = NULL;
337                 uint8_t *outbody = NULL;
338                 uint32_t next_command_ofs = 0;
339                 struct iovec *current = &vector[idx];
340
341                 if ((idx + 3) < count) {
342                         /* we have a next command */
343                         next_command_ofs = SMB2_HDR_BODY + 8;
344                 }
345
346                 inhdr = (const uint8_t *)req->in.vector[idx].iov_base;
347                 in_flags = IVAL(inhdr, SMB2_HDR_FLAGS);
348
349                 outhdr = talloc_array(vector, uint8_t,
350                                       SMB2_HDR_BODY + 8);
351                 if (outhdr == NULL) {
352                         return NT_STATUS_NO_MEMORY;
353                 }
354
355                 outbody = outhdr + SMB2_HDR_BODY;
356
357                 current[0].iov_base     = (void *)outhdr;
358                 current[0].iov_len      = SMB2_HDR_BODY;
359
360                 current[1].iov_base     = (void *)outbody;
361                 current[1].iov_len      = 8;
362
363                 current[2].iov_base     = NULL;
364                 current[2].iov_len      = 0;
365
366                 /* setup the SMB2 header */
367                 SIVAL(outhdr, SMB2_HDR_PROTOCOL_ID,     SMB2_MAGIC);
368                 SSVAL(outhdr, SMB2_HDR_LENGTH,          SMB2_HDR_BODY);
369                 SSVAL(outhdr, SMB2_HDR_EPOCH,           0);
370                 SIVAL(outhdr, SMB2_HDR_STATUS,
371                       NT_STATUS_V(NT_STATUS_INTERNAL_ERROR));
372                 SSVAL(outhdr, SMB2_HDR_OPCODE,
373                       SVAL(inhdr, SMB2_HDR_OPCODE));
374                 /* Make up a number for now... JRA. FIXME ! FIXME !*/
375                 SSVAL(outhdr, SMB2_HDR_CREDIT,          20);
376                 SIVAL(outhdr, SMB2_HDR_FLAGS,
377                       IVAL(inhdr, SMB2_HDR_FLAGS) | SMB2_HDR_FLAG_REDIRECT);
378                 SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND,    next_command_ofs);
379                 SBVAL(outhdr, SMB2_HDR_MESSAGE_ID,
380                       BVAL(inhdr, SMB2_HDR_MESSAGE_ID));
381                 SIVAL(outhdr, SMB2_HDR_PID,
382                       IVAL(inhdr, SMB2_HDR_PID));
383                 SIVAL(outhdr, SMB2_HDR_TID,
384                       IVAL(inhdr, SMB2_HDR_TID));
385                 SBVAL(outhdr, SMB2_HDR_SESSION_ID,
386                       BVAL(inhdr, SMB2_HDR_SESSION_ID));
387                 memset(outhdr + SMB2_HDR_SIGNATURE, 0, 16);
388
389                 /* setup error body header */
390                 SSVAL(outbody, 0x00, 0x08 + 1);
391                 SSVAL(outbody, 0x02, 0);
392                 SIVAL(outbody, 0x04, 0);
393         }
394
395         req->out.vector = vector;
396         req->out.vector_count = count;
397
398         /* setup the length of the NBT packet */
399         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
400
401         DLIST_ADD_END(req->sconn->smb2.requests, req, struct smbd_smb2_request *);
402
403         return NT_STATUS_OK;
404 }
405
406 void smbd_server_connection_terminate_ex(struct smbd_server_connection *sconn,
407                                          const char *reason,
408                                          const char *location)
409 {
410         DEBUG(10,("smbd_server_connection_terminate_ex: reason[%s] at %s\n",
411                   reason, location));
412         exit_server_cleanly(reason);
413 }
414
415 struct smbd_smb2_request_pending_state {
416         struct smbd_server_connection *sconn;
417         uint8_t buf[4 + SMB2_HDR_BODY + 0x08];
418         struct iovec vector;
419 };
420
421 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq);
422
423 NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req)
424 {
425         struct smbd_smb2_request_pending_state *state;
426         struct tevent_req *subreq;
427         uint8_t *outhdr;
428         int i = req->current_idx;
429         uint32_t flags;
430         uint64_t message_id;
431         uint64_t async_id;
432         uint8_t *hdr;
433         uint8_t *body;
434
435         outhdr = (uint8_t *)req->out.vector[i].iov_base;
436
437         flags = IVAL(outhdr, SMB2_HDR_FLAGS);
438         message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
439
440         async_id = message_id; /* keep it simple for now... */
441         SIVAL(outhdr, SMB2_HDR_FLAGS,   flags | SMB2_HDR_FLAG_ASYNC);
442         SBVAL(outhdr, SMB2_HDR_PID,     async_id);
443
444         /* TODO: add a paramter to delay this */
445         state = talloc(req->sconn, struct smbd_smb2_request_pending_state);
446         if (state == NULL) {
447                 return NT_STATUS_NO_MEMORY;
448         }
449         state->sconn = req->sconn;
450
451         state->vector.iov_base = (void *)state->buf;
452         state->vector.iov_len = sizeof(state->buf);
453
454         _smb2_setlen(state->buf, sizeof(state->buf) - 4);
455         hdr = state->buf + 4;
456         body = hdr + SMB2_HDR_BODY;
457
458         SIVAL(hdr, SMB2_HDR_PROTOCOL_ID,        SMB2_MAGIC);
459         SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
460         SSVAL(hdr, SMB2_HDR_EPOCH,              0);
461         SIVAL(hdr, SMB2_HDR_STATUS,             NT_STATUS_V(STATUS_PENDING));
462         SSVAL(hdr, SMB2_HDR_OPCODE,
463               SVAL(outhdr, SMB2_HDR_OPCODE));
464         SSVAL(hdr, SMB2_HDR_CREDIT,             1);
465         SIVAL(hdr, SMB2_HDR_FLAGS,
466               IVAL(outhdr, SMB2_HDR_FLAGS));
467         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,       0);
468         SBVAL(hdr, SMB2_HDR_MESSAGE_ID,
469               BVAL(outhdr, SMB2_HDR_MESSAGE_ID));
470         SBVAL(hdr, SMB2_HDR_PID,
471               BVAL(outhdr, SMB2_HDR_PID));
472         SBVAL(hdr, SMB2_HDR_SESSION_ID,
473               BVAL(outhdr, SMB2_HDR_SESSION_ID));
474         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
475
476         SSVAL(body, 0x00, 0x08 + 1);
477
478         SCVAL(body, 0x02, 0);
479         SCVAL(body, 0x03, 0);
480         SIVAL(body, 0x04, 0);
481
482         subreq = tstream_writev_queue_send(state,
483                                            req->sconn->smb2.event_ctx,
484                                            req->sconn->smb2.stream,
485                                            req->sconn->smb2.send_queue,
486                                            &state->vector, 1);
487         if (subreq == NULL) {
488                 return NT_STATUS_NO_MEMORY;
489         }
490         tevent_req_set_callback(subreq,
491                                 smbd_smb2_request_pending_writev_done,
492                                 state);
493
494         return NT_STATUS_OK;
495 }
496
497 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
498 {
499         struct smbd_smb2_request_pending_state *state =
500                 tevent_req_callback_data(subreq,
501                 struct smbd_smb2_request_pending_state);
502         struct smbd_server_connection *sconn = state->sconn;
503         int ret;
504         int sys_errno;
505
506         ret = tstream_writev_queue_recv(subreq, &sys_errno);
507         TALLOC_FREE(subreq);
508         if (ret == -1) {
509                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
510                 smbd_server_connection_terminate(sconn, nt_errstr(status));
511                 return;
512         }
513
514         TALLOC_FREE(state);
515 }
516
517 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
518 {
519         struct smbd_server_connection *sconn = req->sconn;
520         struct smbd_smb2_request *cur;
521         const uint8_t *inhdr;
522         int i = req->current_idx;
523         uint32_t flags;
524         uint64_t search_message_id;
525         uint64_t search_async_id;
526
527         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
528
529         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
530         search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
531         search_async_id = BVAL(inhdr, SMB2_HDR_PID);
532
533         /*
534          * we don't need the request anymore
535          * cancel requests never have a response
536          */
537         TALLOC_FREE(req);
538
539         for (cur = sconn->smb2.requests; cur; cur = cur->next) {
540                 const uint8_t *outhdr;
541                 uint64_t message_id;
542                 uint64_t async_id;
543
544                 i = cur->current_idx;
545
546                 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
547
548                 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
549                 async_id = BVAL(outhdr, SMB2_HDR_PID);
550
551                 if (flags & SMB2_HDR_FLAG_ASYNC) {
552                         if (search_async_id == async_id) {
553                                 break;
554                         }
555                 } else {
556                         if (search_message_id == message_id) {
557                                 break;
558                         }
559                 }
560         }
561
562         if (cur) {
563                 /* TODO: try to cancel the request */
564         }
565
566         return NT_STATUS_OK;
567 }
568
569 static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
570 {
571         const uint8_t *inhdr;
572         int i = req->current_idx;
573         uint16_t opcode;
574         uint32_t flags;
575         NTSTATUS status;
576         NTSTATUS session_status;
577         uint32_t allowed_flags;
578
579         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
580
581         /* TODO: verify more things */
582
583         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
584         opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
585         DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode));
586
587         allowed_flags = SMB2_HDR_FLAG_CHAINED |
588                         SMB2_HDR_FLAG_SIGNED |
589                         SMB2_HDR_FLAG_DFS;
590         if (opcode == SMB2_OP_CANCEL) {
591                 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
592         }
593         if ((flags & ~allowed_flags) != 0) {
594                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
595         }
596
597         session_status = smbd_smb2_request_check_session(req);
598
599         req->do_signing = false;
600         if (flags & SMB2_HDR_FLAG_SIGNED) {
601                 if (!NT_STATUS_IS_OK(session_status)) {
602                         return smbd_smb2_request_error(req, session_status);
603                 }
604
605                 req->do_signing = true;
606                 status = smb2_signing_check_pdu(req->session->session_key,
607                                                 &req->in.vector[i], 3);
608                 if (!NT_STATUS_IS_OK(status)) {
609                         return smbd_smb2_request_error(req, status);
610                 }
611         } else if (req->session && req->session->do_signing) {
612                 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
613         }
614
615         if (flags & SMB2_HDR_FLAG_CHAINED) {
616                 /*
617                  * This check is mostly for giving the correct error code
618                  * for compounded requests.
619                  *
620                  * TODO: we may need to move this after the session
621                  *       and tcon checks.
622                  */
623                 if (!NT_STATUS_IS_OK(req->next_status)) {
624                         return smbd_smb2_request_error(req, req->next_status);
625                 }
626         } else {
627                 req->compat_chain_fsp = NULL;
628         }
629
630         switch (opcode) {
631         case SMB2_OP_NEGPROT:
632                 return smbd_smb2_request_process_negprot(req);
633
634         case SMB2_OP_SESSSETUP:
635                 return smbd_smb2_request_process_sesssetup(req);
636
637         case SMB2_OP_LOGOFF:
638                 if (!NT_STATUS_IS_OK(session_status)) {
639                         return smbd_smb2_request_error(req, session_status);
640                 }
641                 return smbd_smb2_request_process_logoff(req);
642
643         case SMB2_OP_TCON:
644                 if (!NT_STATUS_IS_OK(session_status)) {
645                         return smbd_smb2_request_error(req, session_status);
646                 }
647                 status = smbd_smb2_request_check_session(req);
648                 if (!NT_STATUS_IS_OK(status)) {
649                         return smbd_smb2_request_error(req, status);
650                 }
651                 return smbd_smb2_request_process_tcon(req);
652
653         case SMB2_OP_TDIS:
654                 if (!NT_STATUS_IS_OK(session_status)) {
655                         return smbd_smb2_request_error(req, session_status);
656                 }
657                 status = smbd_smb2_request_check_tcon(req);
658                 if (!NT_STATUS_IS_OK(status)) {
659                         return smbd_smb2_request_error(req, status);
660                 }
661                 return smbd_smb2_request_process_tdis(req);
662
663         case SMB2_OP_CREATE:
664                 if (!NT_STATUS_IS_OK(session_status)) {
665                         return smbd_smb2_request_error(req, session_status);
666                 }
667                 status = smbd_smb2_request_check_tcon(req);
668                 if (!NT_STATUS_IS_OK(status)) {
669                         return smbd_smb2_request_error(req, status);
670                 }
671                 return smbd_smb2_request_process_create(req);
672
673         case SMB2_OP_CLOSE:
674                 if (!NT_STATUS_IS_OK(session_status)) {
675                         return smbd_smb2_request_error(req, session_status);
676                 }
677                 status = smbd_smb2_request_check_tcon(req);
678                 if (!NT_STATUS_IS_OK(status)) {
679                         return smbd_smb2_request_error(req, status);
680                 }
681                 return smbd_smb2_request_process_close(req);
682
683         case SMB2_OP_FLUSH:
684                 if (!NT_STATUS_IS_OK(session_status)) {
685                         return smbd_smb2_request_error(req, session_status);
686                 }
687                 status = smbd_smb2_request_check_tcon(req);
688                 if (!NT_STATUS_IS_OK(status)) {
689                         return smbd_smb2_request_error(req, status);
690                 }
691                 return smbd_smb2_request_process_flush(req);
692
693         case SMB2_OP_READ:
694                 if (!NT_STATUS_IS_OK(session_status)) {
695                         return smbd_smb2_request_error(req, session_status);
696                 }
697                 status = smbd_smb2_request_check_tcon(req);
698                 if (!NT_STATUS_IS_OK(status)) {
699                         return smbd_smb2_request_error(req, status);
700                 }
701                 return smbd_smb2_request_process_read(req);
702
703         case SMB2_OP_WRITE:
704                 if (!NT_STATUS_IS_OK(session_status)) {
705                         return smbd_smb2_request_error(req, session_status);
706                 }
707                 status = smbd_smb2_request_check_tcon(req);
708                 if (!NT_STATUS_IS_OK(status)) {
709                         return smbd_smb2_request_error(req, status);
710                 }
711                 return smbd_smb2_request_process_write(req);
712
713         case SMB2_OP_LOCK:
714                 if (!NT_STATUS_IS_OK(session_status)) {
715                         return smbd_smb2_request_error(req, session_status);
716                 }
717                 status = smbd_smb2_request_check_tcon(req);
718                 if (!NT_STATUS_IS_OK(status)) {
719                         return smbd_smb2_request_error(req, status);
720                 }
721                 return smbd_smb2_request_process_lock(req);
722
723         case SMB2_OP_IOCTL:
724                 if (!NT_STATUS_IS_OK(session_status)) {
725                         return smbd_smb2_request_error(req, session_status);
726                 }
727                 status = smbd_smb2_request_check_tcon(req);
728                 if (!NT_STATUS_IS_OK(status)) {
729                         return smbd_smb2_request_error(req, status);
730                 }
731                 return smbd_smb2_request_process_ioctl(req);
732
733         case SMB2_OP_CANCEL:
734                 return smbd_smb2_request_process_cancel(req);
735
736         case SMB2_OP_KEEPALIVE:
737                 return smbd_smb2_request_process_keepalive(req);
738
739         case SMB2_OP_FIND:
740                 if (!NT_STATUS_IS_OK(session_status)) {
741                         return smbd_smb2_request_error(req, session_status);
742                 }
743                 status = smbd_smb2_request_check_tcon(req);
744                 if (!NT_STATUS_IS_OK(status)) {
745                         return smbd_smb2_request_error(req, status);
746                 }
747                 return smbd_smb2_request_process_find(req);
748
749         case SMB2_OP_NOTIFY:
750                 if (!NT_STATUS_IS_OK(session_status)) {
751                         return smbd_smb2_request_error(req, session_status);
752                 }
753                 status = smbd_smb2_request_check_tcon(req);
754                 if (!NT_STATUS_IS_OK(status)) {
755                         return smbd_smb2_request_error(req, status);
756                 }
757                 return smbd_smb2_request_process_notify(req);
758
759         case SMB2_OP_GETINFO:
760                 if (!NT_STATUS_IS_OK(session_status)) {
761                         return smbd_smb2_request_error(req, session_status);
762                 }
763                 status = smbd_smb2_request_check_tcon(req);
764                 if (!NT_STATUS_IS_OK(status)) {
765                         return smbd_smb2_request_error(req, status);
766                 }
767                 return smbd_smb2_request_process_getinfo(req);
768
769         case SMB2_OP_SETINFO:
770                 if (!NT_STATUS_IS_OK(session_status)) {
771                         return smbd_smb2_request_error(req, session_status);
772                 }
773                 status = smbd_smb2_request_check_tcon(req);
774                 if (!NT_STATUS_IS_OK(status)) {
775                         return smbd_smb2_request_error(req, status);
776                 }
777                 return smbd_smb2_request_process_setinfo(req);
778
779         case SMB2_OP_BREAK:
780                 if (!NT_STATUS_IS_OK(session_status)) {
781                         return smbd_smb2_request_error(req, session_status);
782                 }
783                 status = smbd_smb2_request_check_tcon(req);
784                 if (!NT_STATUS_IS_OK(status)) {
785                         return smbd_smb2_request_error(req, status);
786                 }
787                 return smbd_smb2_request_process_break(req);
788         }
789
790         return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
791 }
792
793 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq);
794 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
795
796 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
797 {
798         struct tevent_req *subreq;
799
800         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
801
802         if (req->do_signing) {
803                 int i = req->current_idx;
804                 NTSTATUS status;
805                 status = smb2_signing_sign_pdu(req->session->session_key,
806                                                &req->out.vector[i], 3);
807                 if (!NT_STATUS_IS_OK(status)) {
808                         return status;
809                 }
810         }
811
812         req->current_idx += 3;
813
814         if (req->current_idx < req->out.vector_count) {
815                 struct timeval zero = timeval_zero();
816                 subreq = tevent_wakeup_send(req,
817                                             req->sconn->smb2.event_ctx,
818                                             zero);
819                 if (subreq == NULL) {
820                         return NT_STATUS_NO_MEMORY;
821                 }
822                 tevent_req_set_callback(subreq,
823                                         smbd_smb2_request_dispatch_compound,
824                                         req);
825
826                 return NT_STATUS_OK;
827         }
828
829         subreq = tstream_writev_queue_send(req,
830                                            req->sconn->smb2.event_ctx,
831                                            req->sconn->smb2.stream,
832                                            req->sconn->smb2.send_queue,
833                                            req->out.vector,
834                                            req->out.vector_count);
835         if (subreq == NULL) {
836                 return NT_STATUS_NO_MEMORY;
837         }
838         tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
839
840         return NT_STATUS_OK;
841 }
842
843 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq)
844 {
845         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
846                                         struct smbd_smb2_request);
847         struct smbd_server_connection *sconn = req->sconn;
848         NTSTATUS status;
849
850         tevent_wakeup_recv(subreq);
851         TALLOC_FREE(subreq);
852
853         DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n",
854                   req->current_idx, req->in.vector_count));
855
856         status = smbd_smb2_request_dispatch(req);
857         if (!NT_STATUS_IS_OK(status)) {
858                 smbd_server_connection_terminate(sconn, nt_errstr(status));
859                 return;
860         }
861 }
862
863 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
864 {
865         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
866                                         struct smbd_smb2_request);
867         struct smbd_server_connection *sconn = req->sconn;
868         int ret;
869         int sys_errno;
870
871         ret = tstream_writev_queue_recv(subreq, &sys_errno);
872         TALLOC_FREE(subreq);
873         TALLOC_FREE(req);
874         if (ret == -1) {
875                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
876                 smbd_server_connection_terminate(sconn, nt_errstr(status));
877                 return;
878         }
879 }
880
881 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
882                                     NTSTATUS status,
883                                     DATA_BLOB *info,
884                                     const char *location)
885 {
886         uint8_t *outhdr;
887         uint8_t *outbody;
888         int i = req->current_idx;
889
890         DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
891                   i, nt_errstr(status), info ? " +info" : "",
892                   location));
893
894         outhdr = (uint8_t *)req->out.vector[i].iov_base;
895
896         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
897
898         outbody = outhdr + SMB2_HDR_BODY;
899
900         req->out.vector[i+1].iov_base = (void *)outbody;
901         req->out.vector[i+1].iov_len = 8;
902
903         if (info) {
904                 SIVAL(outbody, 0x04, info->length);
905                 req->out.vector[i+2].iov_base   = (void *)info->data;
906                 req->out.vector[i+2].iov_len    = info->length;
907         } else {
908                 req->out.vector[i+2].iov_base = NULL;
909                 req->out.vector[i+2].iov_len = 0;
910         }
911
912         /*
913          * if a request fails, all other remaining
914          * compounded requests should fail too
915          */
916         req->next_status = NT_STATUS_INVALID_PARAMETER;
917
918         return smbd_smb2_request_reply(req);
919 }
920
921 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
922                                    NTSTATUS status,
923                                    DATA_BLOB body, DATA_BLOB *dyn,
924                                    const char *location)
925 {
926         uint8_t *outhdr;
927         uint8_t *outdyn;
928         int i = req->current_idx;
929         uint32_t next_command_ofs;
930
931         DEBUG(10,("smbd_smb2_request_done_ex: "
932                   "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
933                   i, nt_errstr(status), (unsigned int)body.length,
934                   dyn ? "yes": "no",
935                   (unsigned int)(dyn ? dyn->length : 0),
936                   location));
937
938         if (body.length < 2) {
939                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
940         }
941
942         if ((body.length % 2) != 0) {
943                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
944         }
945
946         outhdr = (uint8_t *)req->out.vector[i].iov_base;
947         /* the fallback dynamic buffer */
948         outdyn = outhdr + SMB2_HDR_BODY + 8;
949
950         next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
951         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
952
953         req->out.vector[i+1].iov_base = (void *)body.data;
954         req->out.vector[i+1].iov_len = body.length;
955
956         if (dyn) {
957                 req->out.vector[i+2].iov_base   = (void *)dyn->data;
958                 req->out.vector[i+2].iov_len    = dyn->length;
959         } else {
960                 req->out.vector[i+2].iov_base = NULL;
961                 req->out.vector[i+2].iov_len = 0;
962         }
963
964         /* see if we need to recalculate the offset to the next response */
965         if (next_command_ofs > 0) {
966                 next_command_ofs  = SMB2_HDR_BODY;
967                 next_command_ofs += req->out.vector[i+1].iov_len;
968                 next_command_ofs += req->out.vector[i+2].iov_len;
969         }
970
971         if ((next_command_ofs % 8) != 0) {
972                 size_t pad_size = 8 - (next_command_ofs % 8);
973                 if (req->out.vector[i+2].iov_len == 0) {
974                         /*
975                          * if the dyn buffer is empty
976                          * we can use it to add padding
977                          */
978                         uint8_t *pad;
979
980                         pad = talloc_zero_array(req->out.vector,
981                                                 uint8_t, pad_size);
982                         if (pad == NULL) {
983                                 return smbd_smb2_request_error(req,
984                                                 NT_STATUS_NO_MEMORY);
985                         }
986
987                         req->out.vector[i+2].iov_base = (void *)pad;
988                         req->out.vector[i+2].iov_len = pad_size;
989                 } else {
990                         /*
991                          * For now we copy the dynamic buffer
992                          * and add the padding to the new buffer
993                          */
994                         size_t old_size;
995                         uint8_t *old_dyn;
996                         size_t new_size;
997                         uint8_t *new_dyn;
998
999                         old_size = req->out.vector[i+2].iov_len;
1000                         old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
1001
1002                         new_size = old_size + pad_size;
1003                         new_dyn = talloc_array(req->out.vector,
1004                                                uint8_t, new_size);
1005                         if (new_dyn == NULL) {
1006                                 return smbd_smb2_request_error(req,
1007                                                 NT_STATUS_NO_MEMORY);
1008                         }
1009
1010                         memcpy(new_dyn, old_dyn, old_size);
1011                         memset(new_dyn + old_size, 0, pad_size);
1012
1013                         req->out.vector[i+2].iov_base = (void *)new_dyn;
1014                         req->out.vector[i+2].iov_len = new_size;
1015
1016                         TALLOC_FREE(old_dyn);
1017                 }
1018                 next_command_ofs += pad_size;
1019         }
1020
1021         SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1022
1023         return smbd_smb2_request_reply(req);
1024 }
1025
1026 struct smbd_smb2_send_oplock_break_state {
1027         struct smbd_server_connection *sconn;
1028         uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
1029         struct iovec vector;
1030 };
1031
1032 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
1033
1034 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
1035                                      uint64_t file_id_persistent,
1036                                      uint64_t file_id_volatile,
1037                                      uint8_t oplock_level)
1038 {
1039         struct smbd_smb2_send_oplock_break_state *state;
1040         struct tevent_req *subreq;
1041         uint8_t *hdr;
1042         uint8_t *body;
1043
1044         state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
1045         if (state == NULL) {
1046                 return NT_STATUS_NO_MEMORY;
1047         }
1048         state->sconn = sconn;
1049
1050         state->vector.iov_base = (void *)state->buf;
1051         state->vector.iov_len = sizeof(state->buf);
1052
1053         _smb2_setlen(state->buf, sizeof(state->buf) - 4);
1054         hdr = state->buf + 4;
1055         body = hdr + SMB2_HDR_BODY;
1056
1057         SIVAL(hdr, 0,                           SMB2_MAGIC);
1058         SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
1059         SSVAL(hdr, SMB2_HDR_EPOCH,              0);
1060         SIVAL(hdr, SMB2_HDR_STATUS,             0);
1061         SSVAL(hdr, SMB2_HDR_OPCODE,             SMB2_OP_BREAK);
1062         SSVAL(hdr, SMB2_HDR_CREDIT,             0);
1063         SIVAL(hdr, SMB2_HDR_FLAGS,              SMB2_HDR_FLAG_REDIRECT);
1064         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,       0);
1065         SBVAL(hdr, SMB2_HDR_MESSAGE_ID,         UINT64_MAX);
1066         SIVAL(hdr, SMB2_HDR_PID,                0);
1067         SIVAL(hdr, SMB2_HDR_TID,                0);
1068         SBVAL(hdr, SMB2_HDR_SESSION_ID,         0);
1069         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
1070
1071         SSVAL(body, 0x00, 0x18);
1072
1073         SCVAL(body, 0x02, oplock_level);
1074         SCVAL(body, 0x03, 0);           /* reserved */
1075         SIVAL(body, 0x04, 0);           /* reserved */
1076         SBVAL(body, 0x08, file_id_persistent);
1077         SBVAL(body, 0x10, file_id_volatile);
1078
1079         subreq = tstream_writev_queue_send(state,
1080                                            sconn->smb2.event_ctx,
1081                                            sconn->smb2.stream,
1082                                            sconn->smb2.send_queue,
1083                                            &state->vector, 1);
1084         if (subreq == NULL) {
1085                 return NT_STATUS_NO_MEMORY;
1086         }
1087         tevent_req_set_callback(subreq,
1088                                 smbd_smb2_oplock_break_writev_done,
1089                                 state);
1090
1091         return NT_STATUS_OK;
1092 }
1093
1094 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
1095 {
1096         struct smbd_smb2_send_oplock_break_state *state =
1097                 tevent_req_callback_data(subreq,
1098                 struct smbd_smb2_send_oplock_break_state);
1099         struct smbd_server_connection *sconn = state->sconn;
1100         int ret;
1101         int sys_errno;
1102
1103         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1104         TALLOC_FREE(subreq);
1105         if (ret == -1) {
1106                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1107                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1108                 return;
1109         }
1110
1111         TALLOC_FREE(state);
1112 }
1113
1114 struct smbd_smb2_request_read_state {
1115         size_t missing;
1116         bool asked_for_header;
1117         struct smbd_smb2_request *smb2_req;
1118 };
1119
1120 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1121                                          void *private_data,
1122                                          TALLOC_CTX *mem_ctx,
1123                                          struct iovec **_vector,
1124                                          size_t *_count);
1125 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
1126
1127 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
1128                                         struct tevent_context *ev,
1129                                         struct smbd_server_connection *sconn)
1130 {
1131         struct tevent_req *req;
1132         struct smbd_smb2_request_read_state *state;
1133         struct tevent_req *subreq;
1134
1135         req = tevent_req_create(mem_ctx, &state,
1136                                 struct smbd_smb2_request_read_state);
1137         if (req == NULL) {
1138                 return NULL;
1139         }
1140         state->missing = 0;
1141         state->asked_for_header = false;
1142
1143         state->smb2_req = smbd_smb2_request_allocate(state);
1144         if (tevent_req_nomem(state->smb2_req, req)) {
1145                 return tevent_req_post(req, ev);
1146         }
1147         state->smb2_req->sconn = sconn;
1148
1149         subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
1150                                               sconn->smb2.recv_queue,
1151                                               smbd_smb2_request_next_vector,
1152                                               state);
1153         if (tevent_req_nomem(subreq, req)) {
1154                 return tevent_req_post(req, ev);
1155         }
1156         tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
1157
1158         return req;
1159 }
1160
1161 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1162                                          void *private_data,
1163                                          TALLOC_CTX *mem_ctx,
1164                                          struct iovec **_vector,
1165                                          size_t *_count)
1166 {
1167         struct smbd_smb2_request_read_state *state =
1168                 talloc_get_type_abort(private_data,
1169                 struct smbd_smb2_request_read_state);
1170         struct smbd_smb2_request *req = state->smb2_req;
1171         struct iovec *vector;
1172         int idx = req->in.vector_count;
1173         size_t len = 0;
1174         uint8_t *buf = NULL;
1175
1176         if (req->in.vector_count == 0) {
1177                 /*
1178                  * first we need to get the NBT header
1179                  */
1180                 req->in.vector = talloc_array(req, struct iovec,
1181                                               req->in.vector_count + 1);
1182                 if (req->in.vector == NULL) {
1183                         return -1;
1184                 }
1185                 req->in.vector_count += 1;
1186
1187                 req->in.vector[idx].iov_base    = (void *)req->in.nbt_hdr;
1188                 req->in.vector[idx].iov_len     = 4;
1189
1190                 vector = talloc_array(mem_ctx, struct iovec, 1);
1191                 if (vector == NULL) {
1192                         return -1;
1193                 }
1194
1195                 vector[0] = req->in.vector[idx];
1196
1197                 *_vector = vector;
1198                 *_count = 1;
1199                 return 0;
1200         }
1201
1202         if (req->in.vector_count == 1) {
1203                 /*
1204                  * Now we analyze the NBT header
1205                  */
1206                 state->missing = smb2_len(req->in.vector[0].iov_base);
1207
1208                 if (state->missing == 0) {
1209                         /* if there're no remaining bytes, we're done */
1210                         *_vector = NULL;
1211                         *_count = 0;
1212                         return 0;
1213                 }
1214
1215                 req->in.vector = talloc_realloc(req, req->in.vector,
1216                                                 struct iovec,
1217                                                 req->in.vector_count + 1);
1218                 if (req->in.vector == NULL) {
1219                         return -1;
1220                 }
1221                 req->in.vector_count += 1;
1222
1223                 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
1224                         /*
1225                          * it's a special NBT message,
1226                          * so get all remaining bytes
1227                          */
1228                         len = state->missing;
1229                 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
1230                         /*
1231                          * it's an invalid message, just read what we can get
1232                          * and let the caller handle the error
1233                          */
1234                         len = state->missing;
1235                 } else {
1236                         /*
1237                          * We assume it's a SMB2 request,
1238                          * and we first get the header and the
1239                          * first 2 bytes (the struct size) of the body
1240                          */
1241                         len = SMB2_HDR_BODY + 2;
1242
1243                         state->asked_for_header = true;
1244                 }
1245
1246                 state->missing -= len;
1247
1248                 buf = talloc_array(req->in.vector, uint8_t, len);
1249                 if (buf == NULL) {
1250                         return -1;
1251                 }
1252
1253                 req->in.vector[idx].iov_base    = (void *)buf;
1254                 req->in.vector[idx].iov_len     = len;
1255
1256                 vector = talloc_array(mem_ctx, struct iovec, 1);
1257                 if (vector == NULL) {
1258                         return -1;
1259                 }
1260
1261                 vector[0] = req->in.vector[idx];
1262
1263                 *_vector = vector;
1264                 *_count = 1;
1265                 return 0;
1266         }
1267
1268         if (state->missing == 0) {
1269                 /* if there're no remaining bytes, we're done */
1270                 *_vector = NULL;
1271                 *_count = 0;
1272                 return 0;
1273         }
1274
1275         if (state->asked_for_header) {
1276                 const uint8_t *hdr;
1277                 size_t full_size;
1278                 size_t next_command_ofs;
1279                 size_t body_size;
1280                 uint8_t *body;
1281                 size_t dyn_size;
1282                 uint8_t *dyn;
1283                 bool invalid = false;
1284
1285                 state->asked_for_header = false;
1286
1287                 /*
1288                  * We got the SMB2 header and the first 2 bytes
1289                  * of the body. We fix the size to just the header
1290                  * and manually copy the 2 first bytes to the body section
1291                  */
1292                 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
1293                 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
1294
1295                 /* allocate vectors for body and dynamic areas */
1296                 req->in.vector = talloc_realloc(req, req->in.vector,
1297                                                 struct iovec,
1298                                                 req->in.vector_count + 2);
1299                 if (req->in.vector == NULL) {
1300                         return -1;
1301                 }
1302                 req->in.vector_count += 2;
1303
1304                 full_size = state->missing + SMB2_HDR_BODY + 2;
1305                 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
1306                 body_size = SVAL(hdr, SMB2_HDR_BODY);
1307
1308                 if (next_command_ofs != 0) {
1309                         if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
1310                                 /*
1311                                  * this is invalid, just return a zero
1312                                  * body and let the caller deal with the error
1313                                  */
1314                                 invalid = true;
1315                         } else if (next_command_ofs > full_size) {
1316                                 /*
1317                                  * this is invalid, just return a zero
1318                                  * body and let the caller deal with the error
1319                                  */
1320                                 invalid = true;
1321                         } else {
1322                                 full_size = next_command_ofs;
1323                         }
1324                 }
1325
1326                 if (!invalid) {
1327                         if (body_size < 2) {
1328                                 /*
1329                                  * this is invalid, just return a zero
1330                                  * body and let the caller deal with the error
1331                                  */
1332                                 invalid = true;
1333                         }
1334
1335                         if ((body_size % 2) != 0) {
1336                                 body_size -= 1;
1337                         }
1338
1339                         if (body_size > (full_size - SMB2_HDR_BODY)) {
1340                                 /*
1341                                  * this is invalid, just return a zero
1342                                  * body and let the caller deal with the error
1343                                  */
1344                                 invalid = true;
1345                         }
1346                 }
1347
1348                 if (invalid) {
1349                         /* the caller should check this */
1350                         body_size = 2;
1351                 }
1352
1353                 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
1354
1355                 state->missing -= (body_size - 2) + dyn_size;
1356
1357                 body = talloc_array(req->in.vector, uint8_t, body_size);
1358                 if (body == NULL) {
1359                         return -1;
1360                 }
1361
1362                 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
1363                 if (dyn == NULL) {
1364                         return -1;
1365                 }
1366
1367                 req->in.vector[idx].iov_base    = (void *)body;
1368                 req->in.vector[idx].iov_len     = body_size;
1369                 req->in.vector[idx+1].iov_base  = (void *)dyn;
1370                 req->in.vector[idx+1].iov_len   = dyn_size;
1371
1372                 vector = talloc_array(mem_ctx, struct iovec, 2);
1373                 if (vector == NULL) {
1374                         return -1;
1375                 }
1376
1377                 /*
1378                  * the first 2 bytes of the body were already fetched
1379                  * together with the header
1380                  */
1381                 memcpy(body, hdr + SMB2_HDR_BODY, 2);
1382                 vector[0].iov_base = body + 2;
1383                 vector[0].iov_len = body_size - 2;
1384
1385                 vector[1] = req->in.vector[idx+1];
1386
1387                 *_vector = vector;
1388                 *_count = 2;
1389                 return 0;
1390         }
1391
1392         /*
1393          * when we endup here, we're looking for a new SMB2 request
1394          * next. And we ask for its header and the first 2 bytes of
1395          * the body (like we did for the first SMB2 request).
1396          */
1397
1398         req->in.vector = talloc_realloc(req, req->in.vector,
1399                                         struct iovec,
1400                                         req->in.vector_count + 1);
1401         if (req->in.vector == NULL) {
1402                 return -1;
1403         }
1404         req->in.vector_count += 1;
1405
1406         /*
1407          * We assume it's a SMB2 request,
1408          * and we first get the header and the
1409          * first 2 bytes (the struct size) of the body
1410          */
1411         len = SMB2_HDR_BODY + 2;
1412
1413         if (len > state->missing) {
1414                 /* let the caller handle the error */
1415                 len = state->missing;
1416         }
1417
1418         state->missing -= len;
1419         state->asked_for_header = true;
1420
1421         buf = talloc_array(req->in.vector, uint8_t, len);
1422         if (buf == NULL) {
1423                 return -1;
1424         }
1425
1426         req->in.vector[idx].iov_base    = (void *)buf;
1427         req->in.vector[idx].iov_len     = len;
1428
1429         vector = talloc_array(mem_ctx, struct iovec, 1);
1430         if (vector == NULL) {
1431                 return -1;
1432         }
1433
1434         vector[0] = req->in.vector[idx];
1435
1436         *_vector = vector;
1437         *_count = 1;
1438         return 0;
1439 }
1440
1441 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
1442 {
1443         struct tevent_req *req =
1444                 tevent_req_callback_data(subreq,
1445                 struct tevent_req);
1446         int ret;
1447         int sys_errno;
1448         NTSTATUS status;
1449
1450         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1451         if (ret == -1) {
1452                 status = map_nt_error_from_unix(sys_errno);
1453                 tevent_req_nterror(req, status);
1454                 return;
1455         }
1456
1457         tevent_req_done(req);
1458 }
1459
1460 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
1461                                             TALLOC_CTX *mem_ctx,
1462                                             struct smbd_smb2_request **_smb2_req)
1463 {
1464         struct smbd_smb2_request_read_state *state =
1465                 tevent_req_data(req,
1466                 struct smbd_smb2_request_read_state);
1467         NTSTATUS status;
1468
1469         if (tevent_req_is_nterror(req, &status)) {
1470                 tevent_req_received(req);
1471                 return status;
1472         }
1473
1474         talloc_steal(mem_ctx, state->smb2_req->mem_pool);
1475         *_smb2_req = state->smb2_req;
1476         tevent_req_received(req);
1477         return NT_STATUS_OK;
1478 }
1479
1480 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
1481
1482 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
1483                              const uint8_t *inbuf, size_t size)
1484 {
1485         NTSTATUS status;
1486         struct smbd_smb2_request *req;
1487         struct tevent_req *subreq;
1488
1489         DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
1490                  (unsigned int)size));
1491
1492         status = smbd_initialize_smb2(sconn);
1493         if (!NT_STATUS_IS_OK(status)) {
1494                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1495                 return;
1496         }
1497
1498         status = smbd_smb2_request_create(sconn, inbuf, size, &req);
1499         if (!NT_STATUS_IS_OK(status)) {
1500                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1501                 return;
1502         }
1503
1504         status = smbd_smb2_request_setup_out(req);
1505         if (!NT_STATUS_IS_OK(status)) {
1506                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1507                 return;
1508         }
1509
1510         status = smbd_smb2_request_dispatch(req);
1511         if (!NT_STATUS_IS_OK(status)) {
1512                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1513                 return;
1514         }
1515
1516         /* ask for the next request */
1517         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
1518         if (subreq == NULL) {
1519                 smbd_server_connection_terminate(sconn, "no memory for reading");
1520                 return;
1521         }
1522         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
1523 }
1524
1525 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
1526 {
1527         struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
1528                                                struct smbd_server_connection);
1529         NTSTATUS status;
1530         struct smbd_smb2_request *req = NULL;
1531
1532         status = smbd_smb2_request_read_recv(subreq, sconn, &req);
1533         TALLOC_FREE(subreq);
1534         if (!NT_STATUS_IS_OK(status)) {
1535                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1536                 return;
1537         }
1538
1539         if (req->in.nbt_hdr[0] != 0x00) {
1540                 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
1541                          req->in.nbt_hdr[0]));
1542                 TALLOC_FREE(req);
1543                 goto next;
1544         }
1545
1546         req->current_idx = 1;
1547
1548         DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
1549                  req->current_idx, req->in.vector_count));
1550
1551         status = smbd_smb2_request_validate(req);
1552         if (!NT_STATUS_IS_OK(status)) {
1553                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1554                 return;
1555         }
1556
1557         status = smbd_smb2_request_setup_out(req);
1558         if (!NT_STATUS_IS_OK(status)) {
1559                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1560                 return;
1561         }
1562
1563         status = smbd_smb2_request_dispatch(req);
1564         if (!NT_STATUS_IS_OK(status)) {
1565                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1566                 return;
1567         }
1568
1569 next:
1570         /* ask for the next request (this constructs the main loop) */
1571         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
1572         if (subreq == NULL) {
1573                 smbd_server_connection_terminate(sconn, "no memory for reading");
1574                 return;
1575         }
1576         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
1577 }