s3:smbd: implement SMB2 Cancel correctly.
[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                                          struct tevent_req *subreq)
425 {
426         struct smbd_smb2_request_pending_state *state;
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         if (!tevent_req_is_in_progress(subreq)) {
436                 return NT_STATUS_OK;
437         }
438
439         req->subreq = subreq;
440         subreq = NULL;
441
442         outhdr = (uint8_t *)req->out.vector[i].iov_base;
443
444         flags = IVAL(outhdr, SMB2_HDR_FLAGS);
445         message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
446
447         async_id = message_id; /* keep it simple for now... */
448         SIVAL(outhdr, SMB2_HDR_FLAGS,   flags | SMB2_HDR_FLAG_ASYNC);
449         SBVAL(outhdr, SMB2_HDR_PID,     async_id);
450
451         /* TODO: add a paramter to delay this */
452         state = talloc(req->sconn, struct smbd_smb2_request_pending_state);
453         if (state == NULL) {
454                 return NT_STATUS_NO_MEMORY;
455         }
456         state->sconn = req->sconn;
457
458         state->vector.iov_base = (void *)state->buf;
459         state->vector.iov_len = sizeof(state->buf);
460
461         _smb2_setlen(state->buf, sizeof(state->buf) - 4);
462         hdr = state->buf + 4;
463         body = hdr + SMB2_HDR_BODY;
464
465         SIVAL(hdr, SMB2_HDR_PROTOCOL_ID,        SMB2_MAGIC);
466         SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
467         SSVAL(hdr, SMB2_HDR_EPOCH,              0);
468         SIVAL(hdr, SMB2_HDR_STATUS,             NT_STATUS_V(STATUS_PENDING));
469         SSVAL(hdr, SMB2_HDR_OPCODE,
470               SVAL(outhdr, SMB2_HDR_OPCODE));
471         SSVAL(hdr, SMB2_HDR_CREDIT,             1);
472         SIVAL(hdr, SMB2_HDR_FLAGS,
473               IVAL(outhdr, SMB2_HDR_FLAGS));
474         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,       0);
475         SBVAL(hdr, SMB2_HDR_MESSAGE_ID,
476               BVAL(outhdr, SMB2_HDR_MESSAGE_ID));
477         SBVAL(hdr, SMB2_HDR_PID,
478               BVAL(outhdr, SMB2_HDR_PID));
479         SBVAL(hdr, SMB2_HDR_SESSION_ID,
480               BVAL(outhdr, SMB2_HDR_SESSION_ID));
481         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
482
483         SSVAL(body, 0x00, 0x08 + 1);
484
485         SCVAL(body, 0x02, 0);
486         SCVAL(body, 0x03, 0);
487         SIVAL(body, 0x04, 0);
488
489         subreq = tstream_writev_queue_send(state,
490                                            req->sconn->smb2.event_ctx,
491                                            req->sconn->smb2.stream,
492                                            req->sconn->smb2.send_queue,
493                                            &state->vector, 1);
494         if (subreq == NULL) {
495                 return NT_STATUS_NO_MEMORY;
496         }
497         tevent_req_set_callback(subreq,
498                                 smbd_smb2_request_pending_writev_done,
499                                 state);
500
501         return NT_STATUS_OK;
502 }
503
504 static void smbd_smb2_request_pending_writev_done(struct tevent_req *subreq)
505 {
506         struct smbd_smb2_request_pending_state *state =
507                 tevent_req_callback_data(subreq,
508                 struct smbd_smb2_request_pending_state);
509         struct smbd_server_connection *sconn = state->sconn;
510         int ret;
511         int sys_errno;
512
513         ret = tstream_writev_queue_recv(subreq, &sys_errno);
514         TALLOC_FREE(subreq);
515         if (ret == -1) {
516                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
517                 smbd_server_connection_terminate(sconn, nt_errstr(status));
518                 return;
519         }
520
521         TALLOC_FREE(state);
522 }
523
524 static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req)
525 {
526         struct smbd_server_connection *sconn = req->sconn;
527         struct smbd_smb2_request *cur;
528         const uint8_t *inhdr;
529         int i = req->current_idx;
530         uint32_t flags;
531         uint64_t search_message_id;
532         uint64_t search_async_id;
533
534         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
535
536         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
537         search_message_id = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
538         search_async_id = BVAL(inhdr, SMB2_HDR_PID);
539
540         /*
541          * we don't need the request anymore
542          * cancel requests never have a response
543          */
544         TALLOC_FREE(req);
545
546         for (cur = sconn->smb2.requests; cur; cur = cur->next) {
547                 const uint8_t *outhdr;
548                 uint64_t message_id;
549                 uint64_t async_id;
550
551                 i = cur->current_idx;
552
553                 outhdr = (const uint8_t *)cur->out.vector[i].iov_base;
554
555                 message_id = BVAL(outhdr, SMB2_HDR_MESSAGE_ID);
556                 async_id = BVAL(outhdr, SMB2_HDR_PID);
557
558                 if (flags & SMB2_HDR_FLAG_ASYNC) {
559                         if (search_async_id == async_id) {
560                                 break;
561                         }
562                 } else {
563                         if (search_message_id == message_id) {
564                                 break;
565                         }
566                 }
567         }
568
569         if (cur && cur->subreq) {
570                 tevent_req_cancel(cur->subreq);
571         }
572
573         return NT_STATUS_OK;
574 }
575
576 static NTSTATUS smbd_smb2_request_dispatch(struct smbd_smb2_request *req)
577 {
578         const uint8_t *inhdr;
579         int i = req->current_idx;
580         uint16_t opcode;
581         uint32_t flags;
582         NTSTATUS status;
583         NTSTATUS session_status;
584         uint32_t allowed_flags;
585
586         inhdr = (const uint8_t *)req->in.vector[i].iov_base;
587
588         /* TODO: verify more things */
589
590         flags = IVAL(inhdr, SMB2_HDR_FLAGS);
591         opcode = IVAL(inhdr, SMB2_HDR_OPCODE);
592         DEBUG(10,("smbd_smb2_request_dispatch: opcode[%u]\n", opcode));
593
594         allowed_flags = SMB2_HDR_FLAG_CHAINED |
595                         SMB2_HDR_FLAG_SIGNED |
596                         SMB2_HDR_FLAG_DFS;
597         if (opcode == SMB2_OP_CANCEL) {
598                 allowed_flags |= SMB2_HDR_FLAG_ASYNC;
599         }
600         if ((flags & ~allowed_flags) != 0) {
601                 return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
602         }
603
604         session_status = smbd_smb2_request_check_session(req);
605
606         req->do_signing = false;
607         if (flags & SMB2_HDR_FLAG_SIGNED) {
608                 if (!NT_STATUS_IS_OK(session_status)) {
609                         return smbd_smb2_request_error(req, session_status);
610                 }
611
612                 req->do_signing = true;
613                 status = smb2_signing_check_pdu(req->session->session_key,
614                                                 &req->in.vector[i], 3);
615                 if (!NT_STATUS_IS_OK(status)) {
616                         return smbd_smb2_request_error(req, status);
617                 }
618         } else if (req->session && req->session->do_signing) {
619                 return smbd_smb2_request_error(req, NT_STATUS_ACCESS_DENIED);
620         }
621
622         if (flags & SMB2_HDR_FLAG_CHAINED) {
623                 /*
624                  * This check is mostly for giving the correct error code
625                  * for compounded requests.
626                  *
627                  * TODO: we may need to move this after the session
628                  *       and tcon checks.
629                  */
630                 if (!NT_STATUS_IS_OK(req->next_status)) {
631                         return smbd_smb2_request_error(req, req->next_status);
632                 }
633         } else {
634                 req->compat_chain_fsp = NULL;
635         }
636
637         switch (opcode) {
638         case SMB2_OP_NEGPROT:
639                 return smbd_smb2_request_process_negprot(req);
640
641         case SMB2_OP_SESSSETUP:
642                 return smbd_smb2_request_process_sesssetup(req);
643
644         case SMB2_OP_LOGOFF:
645                 if (!NT_STATUS_IS_OK(session_status)) {
646                         return smbd_smb2_request_error(req, session_status);
647                 }
648                 return smbd_smb2_request_process_logoff(req);
649
650         case SMB2_OP_TCON:
651                 if (!NT_STATUS_IS_OK(session_status)) {
652                         return smbd_smb2_request_error(req, session_status);
653                 }
654                 status = smbd_smb2_request_check_session(req);
655                 if (!NT_STATUS_IS_OK(status)) {
656                         return smbd_smb2_request_error(req, status);
657                 }
658                 return smbd_smb2_request_process_tcon(req);
659
660         case SMB2_OP_TDIS:
661                 if (!NT_STATUS_IS_OK(session_status)) {
662                         return smbd_smb2_request_error(req, session_status);
663                 }
664                 status = smbd_smb2_request_check_tcon(req);
665                 if (!NT_STATUS_IS_OK(status)) {
666                         return smbd_smb2_request_error(req, status);
667                 }
668                 return smbd_smb2_request_process_tdis(req);
669
670         case SMB2_OP_CREATE:
671                 if (!NT_STATUS_IS_OK(session_status)) {
672                         return smbd_smb2_request_error(req, session_status);
673                 }
674                 status = smbd_smb2_request_check_tcon(req);
675                 if (!NT_STATUS_IS_OK(status)) {
676                         return smbd_smb2_request_error(req, status);
677                 }
678                 return smbd_smb2_request_process_create(req);
679
680         case SMB2_OP_CLOSE:
681                 if (!NT_STATUS_IS_OK(session_status)) {
682                         return smbd_smb2_request_error(req, session_status);
683                 }
684                 status = smbd_smb2_request_check_tcon(req);
685                 if (!NT_STATUS_IS_OK(status)) {
686                         return smbd_smb2_request_error(req, status);
687                 }
688                 return smbd_smb2_request_process_close(req);
689
690         case SMB2_OP_FLUSH:
691                 if (!NT_STATUS_IS_OK(session_status)) {
692                         return smbd_smb2_request_error(req, session_status);
693                 }
694                 status = smbd_smb2_request_check_tcon(req);
695                 if (!NT_STATUS_IS_OK(status)) {
696                         return smbd_smb2_request_error(req, status);
697                 }
698                 return smbd_smb2_request_process_flush(req);
699
700         case SMB2_OP_READ:
701                 if (!NT_STATUS_IS_OK(session_status)) {
702                         return smbd_smb2_request_error(req, session_status);
703                 }
704                 status = smbd_smb2_request_check_tcon(req);
705                 if (!NT_STATUS_IS_OK(status)) {
706                         return smbd_smb2_request_error(req, status);
707                 }
708                 return smbd_smb2_request_process_read(req);
709
710         case SMB2_OP_WRITE:
711                 if (!NT_STATUS_IS_OK(session_status)) {
712                         return smbd_smb2_request_error(req, session_status);
713                 }
714                 status = smbd_smb2_request_check_tcon(req);
715                 if (!NT_STATUS_IS_OK(status)) {
716                         return smbd_smb2_request_error(req, status);
717                 }
718                 return smbd_smb2_request_process_write(req);
719
720         case SMB2_OP_LOCK:
721                 if (!NT_STATUS_IS_OK(session_status)) {
722                         return smbd_smb2_request_error(req, session_status);
723                 }
724                 status = smbd_smb2_request_check_tcon(req);
725                 if (!NT_STATUS_IS_OK(status)) {
726                         return smbd_smb2_request_error(req, status);
727                 }
728                 return smbd_smb2_request_process_lock(req);
729
730         case SMB2_OP_IOCTL:
731                 if (!NT_STATUS_IS_OK(session_status)) {
732                         return smbd_smb2_request_error(req, session_status);
733                 }
734                 status = smbd_smb2_request_check_tcon(req);
735                 if (!NT_STATUS_IS_OK(status)) {
736                         return smbd_smb2_request_error(req, status);
737                 }
738                 return smbd_smb2_request_process_ioctl(req);
739
740         case SMB2_OP_CANCEL:
741                 return smbd_smb2_request_process_cancel(req);
742
743         case SMB2_OP_KEEPALIVE:
744                 return smbd_smb2_request_process_keepalive(req);
745
746         case SMB2_OP_FIND:
747                 if (!NT_STATUS_IS_OK(session_status)) {
748                         return smbd_smb2_request_error(req, session_status);
749                 }
750                 status = smbd_smb2_request_check_tcon(req);
751                 if (!NT_STATUS_IS_OK(status)) {
752                         return smbd_smb2_request_error(req, status);
753                 }
754                 return smbd_smb2_request_process_find(req);
755
756         case SMB2_OP_NOTIFY:
757                 if (!NT_STATUS_IS_OK(session_status)) {
758                         return smbd_smb2_request_error(req, session_status);
759                 }
760                 status = smbd_smb2_request_check_tcon(req);
761                 if (!NT_STATUS_IS_OK(status)) {
762                         return smbd_smb2_request_error(req, status);
763                 }
764                 return smbd_smb2_request_process_notify(req);
765
766         case SMB2_OP_GETINFO:
767                 if (!NT_STATUS_IS_OK(session_status)) {
768                         return smbd_smb2_request_error(req, session_status);
769                 }
770                 status = smbd_smb2_request_check_tcon(req);
771                 if (!NT_STATUS_IS_OK(status)) {
772                         return smbd_smb2_request_error(req, status);
773                 }
774                 return smbd_smb2_request_process_getinfo(req);
775
776         case SMB2_OP_SETINFO:
777                 if (!NT_STATUS_IS_OK(session_status)) {
778                         return smbd_smb2_request_error(req, session_status);
779                 }
780                 status = smbd_smb2_request_check_tcon(req);
781                 if (!NT_STATUS_IS_OK(status)) {
782                         return smbd_smb2_request_error(req, status);
783                 }
784                 return smbd_smb2_request_process_setinfo(req);
785
786         case SMB2_OP_BREAK:
787                 if (!NT_STATUS_IS_OK(session_status)) {
788                         return smbd_smb2_request_error(req, session_status);
789                 }
790                 status = smbd_smb2_request_check_tcon(req);
791                 if (!NT_STATUS_IS_OK(status)) {
792                         return smbd_smb2_request_error(req, status);
793                 }
794                 return smbd_smb2_request_process_break(req);
795         }
796
797         return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
798 }
799
800 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq);
801 static void smbd_smb2_request_writev_done(struct tevent_req *subreq);
802
803 static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req)
804 {
805         struct tevent_req *subreq;
806
807         req->subreq = NULL;
808
809         smb2_setup_nbt_length(req->out.vector, req->out.vector_count);
810
811         if (req->do_signing) {
812                 int i = req->current_idx;
813                 NTSTATUS status;
814                 status = smb2_signing_sign_pdu(req->session->session_key,
815                                                &req->out.vector[i], 3);
816                 if (!NT_STATUS_IS_OK(status)) {
817                         return status;
818                 }
819         }
820
821         req->current_idx += 3;
822
823         if (req->current_idx < req->out.vector_count) {
824                 struct timeval zero = timeval_zero();
825                 subreq = tevent_wakeup_send(req,
826                                             req->sconn->smb2.event_ctx,
827                                             zero);
828                 if (subreq == NULL) {
829                         return NT_STATUS_NO_MEMORY;
830                 }
831                 tevent_req_set_callback(subreq,
832                                         smbd_smb2_request_dispatch_compound,
833                                         req);
834
835                 return NT_STATUS_OK;
836         }
837
838         subreq = tstream_writev_queue_send(req,
839                                            req->sconn->smb2.event_ctx,
840                                            req->sconn->smb2.stream,
841                                            req->sconn->smb2.send_queue,
842                                            req->out.vector,
843                                            req->out.vector_count);
844         if (subreq == NULL) {
845                 return NT_STATUS_NO_MEMORY;
846         }
847         tevent_req_set_callback(subreq, smbd_smb2_request_writev_done, req);
848
849         return NT_STATUS_OK;
850 }
851
852 static void smbd_smb2_request_dispatch_compound(struct tevent_req *subreq)
853 {
854         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
855                                         struct smbd_smb2_request);
856         struct smbd_server_connection *sconn = req->sconn;
857         NTSTATUS status;
858
859         tevent_wakeup_recv(subreq);
860         TALLOC_FREE(subreq);
861
862         DEBUG(10,("smbd_smb2_request_dispatch_compound: idx[%d] of %d vectors\n",
863                   req->current_idx, req->in.vector_count));
864
865         status = smbd_smb2_request_dispatch(req);
866         if (!NT_STATUS_IS_OK(status)) {
867                 smbd_server_connection_terminate(sconn, nt_errstr(status));
868                 return;
869         }
870 }
871
872 static void smbd_smb2_request_writev_done(struct tevent_req *subreq)
873 {
874         struct smbd_smb2_request *req = tevent_req_callback_data(subreq,
875                                         struct smbd_smb2_request);
876         struct smbd_server_connection *sconn = req->sconn;
877         int ret;
878         int sys_errno;
879
880         ret = tstream_writev_queue_recv(subreq, &sys_errno);
881         TALLOC_FREE(subreq);
882         TALLOC_FREE(req);
883         if (ret == -1) {
884                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
885                 smbd_server_connection_terminate(sconn, nt_errstr(status));
886                 return;
887         }
888 }
889
890 NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
891                                     NTSTATUS status,
892                                     DATA_BLOB *info,
893                                     const char *location)
894 {
895         uint8_t *outhdr;
896         uint8_t *outbody;
897         int i = req->current_idx;
898
899         DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
900                   i, nt_errstr(status), info ? " +info" : "",
901                   location));
902
903         outhdr = (uint8_t *)req->out.vector[i].iov_base;
904
905         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
906
907         outbody = outhdr + SMB2_HDR_BODY;
908
909         req->out.vector[i+1].iov_base = (void *)outbody;
910         req->out.vector[i+1].iov_len = 8;
911
912         if (info) {
913                 SIVAL(outbody, 0x04, info->length);
914                 req->out.vector[i+2].iov_base   = (void *)info->data;
915                 req->out.vector[i+2].iov_len    = info->length;
916         } else {
917                 req->out.vector[i+2].iov_base = NULL;
918                 req->out.vector[i+2].iov_len = 0;
919         }
920
921         /*
922          * if a request fails, all other remaining
923          * compounded requests should fail too
924          */
925         req->next_status = NT_STATUS_INVALID_PARAMETER;
926
927         return smbd_smb2_request_reply(req);
928 }
929
930 NTSTATUS smbd_smb2_request_done_ex(struct smbd_smb2_request *req,
931                                    NTSTATUS status,
932                                    DATA_BLOB body, DATA_BLOB *dyn,
933                                    const char *location)
934 {
935         uint8_t *outhdr;
936         uint8_t *outdyn;
937         int i = req->current_idx;
938         uint32_t next_command_ofs;
939
940         DEBUG(10,("smbd_smb2_request_done_ex: "
941                   "idx[%d] status[%s] body[%u] dyn[%s:%u] at %s\n",
942                   i, nt_errstr(status), (unsigned int)body.length,
943                   dyn ? "yes": "no",
944                   (unsigned int)(dyn ? dyn->length : 0),
945                   location));
946
947         if (body.length < 2) {
948                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
949         }
950
951         if ((body.length % 2) != 0) {
952                 return smbd_smb2_request_error(req, NT_STATUS_INTERNAL_ERROR);
953         }
954
955         outhdr = (uint8_t *)req->out.vector[i].iov_base;
956         /* the fallback dynamic buffer */
957         outdyn = outhdr + SMB2_HDR_BODY + 8;
958
959         next_command_ofs = IVAL(outhdr, SMB2_HDR_NEXT_COMMAND);
960         SIVAL(outhdr, SMB2_HDR_STATUS, NT_STATUS_V(status));
961
962         req->out.vector[i+1].iov_base = (void *)body.data;
963         req->out.vector[i+1].iov_len = body.length;
964
965         if (dyn) {
966                 req->out.vector[i+2].iov_base   = (void *)dyn->data;
967                 req->out.vector[i+2].iov_len    = dyn->length;
968         } else {
969                 req->out.vector[i+2].iov_base = NULL;
970                 req->out.vector[i+2].iov_len = 0;
971         }
972
973         /* see if we need to recalculate the offset to the next response */
974         if (next_command_ofs > 0) {
975                 next_command_ofs  = SMB2_HDR_BODY;
976                 next_command_ofs += req->out.vector[i+1].iov_len;
977                 next_command_ofs += req->out.vector[i+2].iov_len;
978         }
979
980         if ((next_command_ofs % 8) != 0) {
981                 size_t pad_size = 8 - (next_command_ofs % 8);
982                 if (req->out.vector[i+2].iov_len == 0) {
983                         /*
984                          * if the dyn buffer is empty
985                          * we can use it to add padding
986                          */
987                         uint8_t *pad;
988
989                         pad = talloc_zero_array(req->out.vector,
990                                                 uint8_t, pad_size);
991                         if (pad == NULL) {
992                                 return smbd_smb2_request_error(req,
993                                                 NT_STATUS_NO_MEMORY);
994                         }
995
996                         req->out.vector[i+2].iov_base = (void *)pad;
997                         req->out.vector[i+2].iov_len = pad_size;
998                 } else {
999                         /*
1000                          * For now we copy the dynamic buffer
1001                          * and add the padding to the new buffer
1002                          */
1003                         size_t old_size;
1004                         uint8_t *old_dyn;
1005                         size_t new_size;
1006                         uint8_t *new_dyn;
1007
1008                         old_size = req->out.vector[i+2].iov_len;
1009                         old_dyn = (uint8_t *)req->out.vector[i+2].iov_base;
1010
1011                         new_size = old_size + pad_size;
1012                         new_dyn = talloc_array(req->out.vector,
1013                                                uint8_t, new_size);
1014                         if (new_dyn == NULL) {
1015                                 return smbd_smb2_request_error(req,
1016                                                 NT_STATUS_NO_MEMORY);
1017                         }
1018
1019                         memcpy(new_dyn, old_dyn, old_size);
1020                         memset(new_dyn + old_size, 0, pad_size);
1021
1022                         req->out.vector[i+2].iov_base = (void *)new_dyn;
1023                         req->out.vector[i+2].iov_len = new_size;
1024
1025                         TALLOC_FREE(old_dyn);
1026                 }
1027                 next_command_ofs += pad_size;
1028         }
1029
1030         SIVAL(outhdr, SMB2_HDR_NEXT_COMMAND, next_command_ofs);
1031
1032         return smbd_smb2_request_reply(req);
1033 }
1034
1035 struct smbd_smb2_send_oplock_break_state {
1036         struct smbd_server_connection *sconn;
1037         uint8_t buf[4 + SMB2_HDR_BODY + 0x18];
1038         struct iovec vector;
1039 };
1040
1041 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq);
1042
1043 NTSTATUS smbd_smb2_send_oplock_break(struct smbd_server_connection *sconn,
1044                                      uint64_t file_id_persistent,
1045                                      uint64_t file_id_volatile,
1046                                      uint8_t oplock_level)
1047 {
1048         struct smbd_smb2_send_oplock_break_state *state;
1049         struct tevent_req *subreq;
1050         uint8_t *hdr;
1051         uint8_t *body;
1052
1053         state = talloc(sconn, struct smbd_smb2_send_oplock_break_state);
1054         if (state == NULL) {
1055                 return NT_STATUS_NO_MEMORY;
1056         }
1057         state->sconn = sconn;
1058
1059         state->vector.iov_base = (void *)state->buf;
1060         state->vector.iov_len = sizeof(state->buf);
1061
1062         _smb2_setlen(state->buf, sizeof(state->buf) - 4);
1063         hdr = state->buf + 4;
1064         body = hdr + SMB2_HDR_BODY;
1065
1066         SIVAL(hdr, 0,                           SMB2_MAGIC);
1067         SSVAL(hdr, SMB2_HDR_LENGTH,             SMB2_HDR_BODY);
1068         SSVAL(hdr, SMB2_HDR_EPOCH,              0);
1069         SIVAL(hdr, SMB2_HDR_STATUS,             0);
1070         SSVAL(hdr, SMB2_HDR_OPCODE,             SMB2_OP_BREAK);
1071         SSVAL(hdr, SMB2_HDR_CREDIT,             0);
1072         SIVAL(hdr, SMB2_HDR_FLAGS,              SMB2_HDR_FLAG_REDIRECT);
1073         SIVAL(hdr, SMB2_HDR_NEXT_COMMAND,       0);
1074         SBVAL(hdr, SMB2_HDR_MESSAGE_ID,         UINT64_MAX);
1075         SIVAL(hdr, SMB2_HDR_PID,                0);
1076         SIVAL(hdr, SMB2_HDR_TID,                0);
1077         SBVAL(hdr, SMB2_HDR_SESSION_ID,         0);
1078         memset(hdr+SMB2_HDR_SIGNATURE, 0, 16);
1079
1080         SSVAL(body, 0x00, 0x18);
1081
1082         SCVAL(body, 0x02, oplock_level);
1083         SCVAL(body, 0x03, 0);           /* reserved */
1084         SIVAL(body, 0x04, 0);           /* reserved */
1085         SBVAL(body, 0x08, file_id_persistent);
1086         SBVAL(body, 0x10, file_id_volatile);
1087
1088         subreq = tstream_writev_queue_send(state,
1089                                            sconn->smb2.event_ctx,
1090                                            sconn->smb2.stream,
1091                                            sconn->smb2.send_queue,
1092                                            &state->vector, 1);
1093         if (subreq == NULL) {
1094                 return NT_STATUS_NO_MEMORY;
1095         }
1096         tevent_req_set_callback(subreq,
1097                                 smbd_smb2_oplock_break_writev_done,
1098                                 state);
1099
1100         return NT_STATUS_OK;
1101 }
1102
1103 static void smbd_smb2_oplock_break_writev_done(struct tevent_req *subreq)
1104 {
1105         struct smbd_smb2_send_oplock_break_state *state =
1106                 tevent_req_callback_data(subreq,
1107                 struct smbd_smb2_send_oplock_break_state);
1108         struct smbd_server_connection *sconn = state->sconn;
1109         int ret;
1110         int sys_errno;
1111
1112         ret = tstream_writev_queue_recv(subreq, &sys_errno);
1113         TALLOC_FREE(subreq);
1114         if (ret == -1) {
1115                 NTSTATUS status = map_nt_error_from_unix(sys_errno);
1116                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1117                 return;
1118         }
1119
1120         TALLOC_FREE(state);
1121 }
1122
1123 struct smbd_smb2_request_read_state {
1124         size_t missing;
1125         bool asked_for_header;
1126         struct smbd_smb2_request *smb2_req;
1127 };
1128
1129 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1130                                          void *private_data,
1131                                          TALLOC_CTX *mem_ctx,
1132                                          struct iovec **_vector,
1133                                          size_t *_count);
1134 static void smbd_smb2_request_read_done(struct tevent_req *subreq);
1135
1136 static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
1137                                         struct tevent_context *ev,
1138                                         struct smbd_server_connection *sconn)
1139 {
1140         struct tevent_req *req;
1141         struct smbd_smb2_request_read_state *state;
1142         struct tevent_req *subreq;
1143
1144         req = tevent_req_create(mem_ctx, &state,
1145                                 struct smbd_smb2_request_read_state);
1146         if (req == NULL) {
1147                 return NULL;
1148         }
1149         state->missing = 0;
1150         state->asked_for_header = false;
1151
1152         state->smb2_req = smbd_smb2_request_allocate(state);
1153         if (tevent_req_nomem(state->smb2_req, req)) {
1154                 return tevent_req_post(req, ev);
1155         }
1156         state->smb2_req->sconn = sconn;
1157
1158         subreq = tstream_readv_pdu_queue_send(state, ev, sconn->smb2.stream,
1159                                               sconn->smb2.recv_queue,
1160                                               smbd_smb2_request_next_vector,
1161                                               state);
1162         if (tevent_req_nomem(subreq, req)) {
1163                 return tevent_req_post(req, ev);
1164         }
1165         tevent_req_set_callback(subreq, smbd_smb2_request_read_done, req);
1166
1167         return req;
1168 }
1169
1170 static int smbd_smb2_request_next_vector(struct tstream_context *stream,
1171                                          void *private_data,
1172                                          TALLOC_CTX *mem_ctx,
1173                                          struct iovec **_vector,
1174                                          size_t *_count)
1175 {
1176         struct smbd_smb2_request_read_state *state =
1177                 talloc_get_type_abort(private_data,
1178                 struct smbd_smb2_request_read_state);
1179         struct smbd_smb2_request *req = state->smb2_req;
1180         struct iovec *vector;
1181         int idx = req->in.vector_count;
1182         size_t len = 0;
1183         uint8_t *buf = NULL;
1184
1185         if (req->in.vector_count == 0) {
1186                 /*
1187                  * first we need to get the NBT header
1188                  */
1189                 req->in.vector = talloc_array(req, struct iovec,
1190                                               req->in.vector_count + 1);
1191                 if (req->in.vector == NULL) {
1192                         return -1;
1193                 }
1194                 req->in.vector_count += 1;
1195
1196                 req->in.vector[idx].iov_base    = (void *)req->in.nbt_hdr;
1197                 req->in.vector[idx].iov_len     = 4;
1198
1199                 vector = talloc_array(mem_ctx, struct iovec, 1);
1200                 if (vector == NULL) {
1201                         return -1;
1202                 }
1203
1204                 vector[0] = req->in.vector[idx];
1205
1206                 *_vector = vector;
1207                 *_count = 1;
1208                 return 0;
1209         }
1210
1211         if (req->in.vector_count == 1) {
1212                 /*
1213                  * Now we analyze the NBT header
1214                  */
1215                 state->missing = smb2_len(req->in.vector[0].iov_base);
1216
1217                 if (state->missing == 0) {
1218                         /* if there're no remaining bytes, we're done */
1219                         *_vector = NULL;
1220                         *_count = 0;
1221                         return 0;
1222                 }
1223
1224                 req->in.vector = talloc_realloc(req, req->in.vector,
1225                                                 struct iovec,
1226                                                 req->in.vector_count + 1);
1227                 if (req->in.vector == NULL) {
1228                         return -1;
1229                 }
1230                 req->in.vector_count += 1;
1231
1232                 if (CVAL(req->in.vector[0].iov_base, 0) != 0) {
1233                         /*
1234                          * it's a special NBT message,
1235                          * so get all remaining bytes
1236                          */
1237                         len = state->missing;
1238                 } else if (state->missing < (SMB2_HDR_BODY + 2)) {
1239                         /*
1240                          * it's an invalid message, just read what we can get
1241                          * and let the caller handle the error
1242                          */
1243                         len = state->missing;
1244                 } else {
1245                         /*
1246                          * We assume it's a SMB2 request,
1247                          * and we first get the header and the
1248                          * first 2 bytes (the struct size) of the body
1249                          */
1250                         len = SMB2_HDR_BODY + 2;
1251
1252                         state->asked_for_header = true;
1253                 }
1254
1255                 state->missing -= len;
1256
1257                 buf = talloc_array(req->in.vector, uint8_t, len);
1258                 if (buf == NULL) {
1259                         return -1;
1260                 }
1261
1262                 req->in.vector[idx].iov_base    = (void *)buf;
1263                 req->in.vector[idx].iov_len     = len;
1264
1265                 vector = talloc_array(mem_ctx, struct iovec, 1);
1266                 if (vector == NULL) {
1267                         return -1;
1268                 }
1269
1270                 vector[0] = req->in.vector[idx];
1271
1272                 *_vector = vector;
1273                 *_count = 1;
1274                 return 0;
1275         }
1276
1277         if (state->missing == 0) {
1278                 /* if there're no remaining bytes, we're done */
1279                 *_vector = NULL;
1280                 *_count = 0;
1281                 return 0;
1282         }
1283
1284         if (state->asked_for_header) {
1285                 const uint8_t *hdr;
1286                 size_t full_size;
1287                 size_t next_command_ofs;
1288                 size_t body_size;
1289                 uint8_t *body;
1290                 size_t dyn_size;
1291                 uint8_t *dyn;
1292                 bool invalid = false;
1293
1294                 state->asked_for_header = false;
1295
1296                 /*
1297                  * We got the SMB2 header and the first 2 bytes
1298                  * of the body. We fix the size to just the header
1299                  * and manually copy the 2 first bytes to the body section
1300                  */
1301                 req->in.vector[idx-1].iov_len = SMB2_HDR_BODY;
1302                 hdr = (const uint8_t *)req->in.vector[idx-1].iov_base;
1303
1304                 /* allocate vectors for body and dynamic areas */
1305                 req->in.vector = talloc_realloc(req, req->in.vector,
1306                                                 struct iovec,
1307                                                 req->in.vector_count + 2);
1308                 if (req->in.vector == NULL) {
1309                         return -1;
1310                 }
1311                 req->in.vector_count += 2;
1312
1313                 full_size = state->missing + SMB2_HDR_BODY + 2;
1314                 next_command_ofs = IVAL(hdr, SMB2_HDR_NEXT_COMMAND);
1315                 body_size = SVAL(hdr, SMB2_HDR_BODY);
1316
1317                 if (next_command_ofs != 0) {
1318                         if (next_command_ofs < (SMB2_HDR_BODY + 2)) {
1319                                 /*
1320                                  * this is invalid, just return a zero
1321                                  * body and let the caller deal with the error
1322                                  */
1323                                 invalid = true;
1324                         } else if (next_command_ofs > full_size) {
1325                                 /*
1326                                  * this is invalid, just return a zero
1327                                  * body and let the caller deal with the error
1328                                  */
1329                                 invalid = true;
1330                         } else {
1331                                 full_size = next_command_ofs;
1332                         }
1333                 }
1334
1335                 if (!invalid) {
1336                         if (body_size < 2) {
1337                                 /*
1338                                  * this is invalid, just return a zero
1339                                  * body and let the caller deal with the error
1340                                  */
1341                                 invalid = true;
1342                         }
1343
1344                         if ((body_size % 2) != 0) {
1345                                 body_size -= 1;
1346                         }
1347
1348                         if (body_size > (full_size - SMB2_HDR_BODY)) {
1349                                 /*
1350                                  * this is invalid, just return a zero
1351                                  * body and let the caller deal with the error
1352                                  */
1353                                 invalid = true;
1354                         }
1355                 }
1356
1357                 if (invalid) {
1358                         /* the caller should check this */
1359                         body_size = 2;
1360                 }
1361
1362                 dyn_size = full_size - (SMB2_HDR_BODY + body_size);
1363
1364                 state->missing -= (body_size - 2) + dyn_size;
1365
1366                 body = talloc_array(req->in.vector, uint8_t, body_size);
1367                 if (body == NULL) {
1368                         return -1;
1369                 }
1370
1371                 dyn = talloc_array(req->in.vector, uint8_t, dyn_size);
1372                 if (dyn == NULL) {
1373                         return -1;
1374                 }
1375
1376                 req->in.vector[idx].iov_base    = (void *)body;
1377                 req->in.vector[idx].iov_len     = body_size;
1378                 req->in.vector[idx+1].iov_base  = (void *)dyn;
1379                 req->in.vector[idx+1].iov_len   = dyn_size;
1380
1381                 vector = talloc_array(mem_ctx, struct iovec, 2);
1382                 if (vector == NULL) {
1383                         return -1;
1384                 }
1385
1386                 /*
1387                  * the first 2 bytes of the body were already fetched
1388                  * together with the header
1389                  */
1390                 memcpy(body, hdr + SMB2_HDR_BODY, 2);
1391                 vector[0].iov_base = body + 2;
1392                 vector[0].iov_len = body_size - 2;
1393
1394                 vector[1] = req->in.vector[idx+1];
1395
1396                 *_vector = vector;
1397                 *_count = 2;
1398                 return 0;
1399         }
1400
1401         /*
1402          * when we endup here, we're looking for a new SMB2 request
1403          * next. And we ask for its header and the first 2 bytes of
1404          * the body (like we did for the first SMB2 request).
1405          */
1406
1407         req->in.vector = talloc_realloc(req, req->in.vector,
1408                                         struct iovec,
1409                                         req->in.vector_count + 1);
1410         if (req->in.vector == NULL) {
1411                 return -1;
1412         }
1413         req->in.vector_count += 1;
1414
1415         /*
1416          * We assume it's a SMB2 request,
1417          * and we first get the header and the
1418          * first 2 bytes (the struct size) of the body
1419          */
1420         len = SMB2_HDR_BODY + 2;
1421
1422         if (len > state->missing) {
1423                 /* let the caller handle the error */
1424                 len = state->missing;
1425         }
1426
1427         state->missing -= len;
1428         state->asked_for_header = true;
1429
1430         buf = talloc_array(req->in.vector, uint8_t, len);
1431         if (buf == NULL) {
1432                 return -1;
1433         }
1434
1435         req->in.vector[idx].iov_base    = (void *)buf;
1436         req->in.vector[idx].iov_len     = len;
1437
1438         vector = talloc_array(mem_ctx, struct iovec, 1);
1439         if (vector == NULL) {
1440                 return -1;
1441         }
1442
1443         vector[0] = req->in.vector[idx];
1444
1445         *_vector = vector;
1446         *_count = 1;
1447         return 0;
1448 }
1449
1450 static void smbd_smb2_request_read_done(struct tevent_req *subreq)
1451 {
1452         struct tevent_req *req =
1453                 tevent_req_callback_data(subreq,
1454                 struct tevent_req);
1455         int ret;
1456         int sys_errno;
1457         NTSTATUS status;
1458
1459         ret = tstream_readv_pdu_queue_recv(subreq, &sys_errno);
1460         if (ret == -1) {
1461                 status = map_nt_error_from_unix(sys_errno);
1462                 tevent_req_nterror(req, status);
1463                 return;
1464         }
1465
1466         tevent_req_done(req);
1467 }
1468
1469 static NTSTATUS smbd_smb2_request_read_recv(struct tevent_req *req,
1470                                             TALLOC_CTX *mem_ctx,
1471                                             struct smbd_smb2_request **_smb2_req)
1472 {
1473         struct smbd_smb2_request_read_state *state =
1474                 tevent_req_data(req,
1475                 struct smbd_smb2_request_read_state);
1476         NTSTATUS status;
1477
1478         if (tevent_req_is_nterror(req, &status)) {
1479                 tevent_req_received(req);
1480                 return status;
1481         }
1482
1483         talloc_steal(mem_ctx, state->smb2_req->mem_pool);
1484         *_smb2_req = state->smb2_req;
1485         tevent_req_received(req);
1486         return NT_STATUS_OK;
1487 }
1488
1489 static void smbd_smb2_request_incoming(struct tevent_req *subreq);
1490
1491 void smbd_smb2_first_negprot(struct smbd_server_connection *sconn,
1492                              const uint8_t *inbuf, size_t size)
1493 {
1494         NTSTATUS status;
1495         struct smbd_smb2_request *req;
1496         struct tevent_req *subreq;
1497
1498         DEBUG(10,("smbd_smb2_first_negprot: packet length %u\n",
1499                  (unsigned int)size));
1500
1501         status = smbd_initialize_smb2(sconn);
1502         if (!NT_STATUS_IS_OK(status)) {
1503                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1504                 return;
1505         }
1506
1507         status = smbd_smb2_request_create(sconn, inbuf, size, &req);
1508         if (!NT_STATUS_IS_OK(status)) {
1509                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1510                 return;
1511         }
1512
1513         status = smbd_smb2_request_setup_out(req);
1514         if (!NT_STATUS_IS_OK(status)) {
1515                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1516                 return;
1517         }
1518
1519         status = smbd_smb2_request_dispatch(req);
1520         if (!NT_STATUS_IS_OK(status)) {
1521                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1522                 return;
1523         }
1524
1525         /* ask for the next request */
1526         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
1527         if (subreq == NULL) {
1528                 smbd_server_connection_terminate(sconn, "no memory for reading");
1529                 return;
1530         }
1531         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
1532 }
1533
1534 static void smbd_smb2_request_incoming(struct tevent_req *subreq)
1535 {
1536         struct smbd_server_connection *sconn = tevent_req_callback_data(subreq,
1537                                                struct smbd_server_connection);
1538         NTSTATUS status;
1539         struct smbd_smb2_request *req = NULL;
1540
1541         status = smbd_smb2_request_read_recv(subreq, sconn, &req);
1542         TALLOC_FREE(subreq);
1543         if (!NT_STATUS_IS_OK(status)) {
1544                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1545                 return;
1546         }
1547
1548         if (req->in.nbt_hdr[0] != 0x00) {
1549                 DEBUG(1,("smbd_smb2_request_incoming: ignore NBT[0x%02X] msg\n",
1550                          req->in.nbt_hdr[0]));
1551                 TALLOC_FREE(req);
1552                 goto next;
1553         }
1554
1555         req->current_idx = 1;
1556
1557         DEBUG(10,("smbd_smb2_request_incoming: idx[%d] of %d vectors\n",
1558                  req->current_idx, req->in.vector_count));
1559
1560         status = smbd_smb2_request_validate(req);
1561         if (!NT_STATUS_IS_OK(status)) {
1562                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1563                 return;
1564         }
1565
1566         status = smbd_smb2_request_setup_out(req);
1567         if (!NT_STATUS_IS_OK(status)) {
1568                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1569                 return;
1570         }
1571
1572         status = smbd_smb2_request_dispatch(req);
1573         if (!NT_STATUS_IS_OK(status)) {
1574                 smbd_server_connection_terminate(sconn, nt_errstr(status));
1575                 return;
1576         }
1577
1578 next:
1579         /* ask for the next request (this constructs the main loop) */
1580         subreq = smbd_smb2_request_read_send(sconn, sconn->smb2.event_ctx, sconn);
1581         if (subreq == NULL) {
1582                 smbd_server_connection_terminate(sconn, "no memory for reading");
1583                 return;
1584         }
1585         tevent_req_set_callback(subreq, smbd_smb2_request_incoming, sconn);
1586 }